Ruby support #1

Open
jaroslaw wants to merge 165 commits from ruby into main
5 changed files with 64 additions and 58 deletions
Showing only changes of commit c75f158dfb - Show all commits

View file

@ -78,7 +78,7 @@ where
inner_system.apply_deferred(world); inner_system.apply_deferred(world);
let mut runtime = world.get_resource_mut::<R>().expect("No runtime resource"); let mut runtime = world.get_resource_mut::<R>().expect("No runtime resource");
if R::is_current_thread() { if R::needs_own_thread() {
runtime.with_engine_mut(move |engine| { runtime.with_engine_mut(move |engine| {
Out::into_runtime_value_with_engine(result, engine) Out::into_runtime_value_with_engine(result, engine)
}) })
@ -110,7 +110,7 @@ macro_rules! impl_tuple {
inner_system.initialize(world); inner_system.initialize(world);
let system_fn = move |args: In<Vec<RN::Value>>, world: &mut World| { let system_fn = move |args: In<Vec<RN::Value>>, world: &mut World| {
let mut runtime = world.get_resource_mut::<RN>().expect("No runtime resource"); let mut runtime = world.get_resource_mut::<RN>().expect("No runtime resource");
let args = if RN::is_current_thread() { let args = if RN::needs_own_thread() {
runtime.with_engine_mut(move |engine| { runtime.with_engine_mut(move |engine| {
( (
$($t::from_runtime_value_with_engine(args.get($idx).expect(&format!("Failed to get function argument for index {}", $idx)).clone(), engine), )+ $($t::from_runtime_value_with_engine(args.get($idx).expect(&format!("Failed to get function argument for index {}", $idx)).clone(), engine), )+
@ -127,7 +127,7 @@ macro_rules! impl_tuple {
let result = inner_system.run(args, world); let result = inner_system.run(args, world);
inner_system.apply_deferred(world); inner_system.apply_deferred(world);
let mut runtime = world.get_resource_mut::<RN>().expect("No runtime resource"); let mut runtime = world.get_resource_mut::<RN>().expect("No runtime resource");
if RN::is_current_thread() { if RN::needs_own_thread() {
runtime.with_engine_mut(move |engine| { runtime.with_engine_mut(move |engine| {
Out::into_runtime_value_with_engine(result, engine) Out::into_runtime_value_with_engine(result, engine)
}) })

View file

@ -300,7 +300,7 @@ pub trait Runtime: Resource + Default {
type Value: Send + Clone; type Value: Send + Clone;
type RawEngine; type RawEngine;
fn is_current_thread() -> bool; fn needs_own_thread() -> bool;
/// Provides mutable reference to raw scripting engine instance. /// Provides mutable reference to raw scripting engine instance.
/// Can be used to directly interact with an interpreter to use interfaces /// Can be used to directly interact with an interpreter to use interfaces

View file

@ -299,7 +299,7 @@ impl Runtime for LuaRuntime {
self.with_engine(f) self.with_engine(f)
} }
fn is_current_thread() -> bool { fn needs_own_thread() -> bool {
true true
} }
} }

View file

@ -208,7 +208,7 @@ impl Runtime for RhaiRuntime {
self.with_engine(f) self.with_engine(f)
} }
fn is_current_thread() -> bool { fn needs_own_thread() -> bool {
true true
} }
} }

View file

@ -291,6 +291,28 @@ impl RubyValue {
} }
} }
impl RubyRuntime {
fn execute_in_thread<T: Send + 'static>(
&self,
f: impl FnOnce(&magnus::Ruby) -> T + Send + 'static,
) -> T {
self.ruby_thread
.as_ref()
.unwrap()
.execute(Box::new(move |ruby| f(&ruby)))
}
fn execute_in_thread_mut<T: Send + 'static>(
&self,
f: impl FnOnce(&mut magnus::Ruby) -> T + Send + 'static,
) -> T {
self.ruby_thread
.as_ref()
.unwrap()
.execute(Box::new(move |mut ruby| f(&mut ruby)))
}
}
impl Runtime for RubyRuntime { impl Runtime for RubyRuntime {
type Schedule = RubySchedule; type Schedule = RubySchedule;
@ -308,20 +330,14 @@ impl Runtime for RubyRuntime {
&mut self, &mut self,
f: impl FnOnce(&mut Self::RawEngine) -> T + Send + 'static, f: impl FnOnce(&mut Self::RawEngine) -> T + Send + 'static,
) -> T { ) -> T {
self.ruby_thread self.execute_in_thread_mut(f)
.as_ref()
.unwrap()
.execute(Box::new(move |mut ruby| f(&mut ruby)))
} }
fn with_engine_thread<T: Send + 'static>( fn with_engine_thread<T: Send + 'static>(
&self, &self,
f: impl FnOnce(&Self::RawEngine) -> T + Send + 'static, f: impl FnOnce(&Self::RawEngine) -> T + Send + 'static,
) -> T { ) -> T {
self.ruby_thread self.execute_in_thread(f)
.as_ref()
.unwrap()
.execute(Box::new(move |ruby| f(&ruby)))
} }
fn with_engine_mut<T>(&mut self, _f: impl FnOnce(&mut Self::RawEngine) -> T) -> T { fn with_engine_mut<T>(&mut self, _f: impl FnOnce(&mut Self::RawEngine) -> T) -> T {
@ -338,22 +354,19 @@ impl Runtime for RubyRuntime {
entity: bevy::prelude::Entity, entity: bevy::prelude::Entity,
) -> Result<Self::ScriptData, crate::ScriptingError> { ) -> Result<Self::ScriptData, crate::ScriptingError> {
let script = script.0.clone(); let script = script.0.clone();
self.ruby_thread self.execute_in_thread(Box::new(move |ruby: &Ruby| {
.as_ref() let var = ruby
.unwrap() .class_object()
.execute(Box::new(move |ruby| { .const_get::<_, RModule>("Bevy")
let var = ruby .unwrap()
.class_object() .const_get::<_, RClass>("Entity")
.const_get::<_, RModule>("Bevy") .unwrap();
.unwrap() var.ivar_set("_current", BevyEntity(entity)).unwrap();
.const_get::<_, RClass>("Entity") let value = ruby.eval::<magnus::value::Value>(&script).unwrap();
.unwrap(); var.ivar_set("_current", ruby.qnil().as_value()).unwrap();
var.ivar_set("_current", BevyEntity(entity)).unwrap();
let value = ruby.eval::<magnus::value::Value>(&script).unwrap();
var.ivar_set("_current", ruby.qnil().as_value()).unwrap();
RubyValue::new(value) RubyValue::new(value)
})); }));
Ok(RubyScriptData) Ok(RubyScriptData)
} }
@ -403,13 +416,10 @@ impl Runtime for RubyRuntime {
result.into_value() result.into_value()
} }
self.ruby_thread self.execute_in_thread(Box::new(move |ruby: &Ruby| {
.as_ref() ruby.define_global_function(&name, function!(callback, -1));
.unwrap() RubyValue::nil(&ruby)
.execute(Box::new(move |ruby| { }));
ruby.define_global_function(&name, function!(callback, -1));
RubyValue::nil(&ruby)
}));
Ok(()) Ok(())
} }
@ -422,30 +432,26 @@ impl Runtime for RubyRuntime {
args: impl for<'a> crate::FuncArgs<'a, Self::Value, Self> + Send + 'static, args: impl for<'a> crate::FuncArgs<'a, Self::Value, Self> + Send + 'static,
) -> Result<Self::Value, crate::ScriptingError> { ) -> Result<Self::Value, crate::ScriptingError> {
let name = name.to_string(); let name = name.to_string();
self.ruby_thread self.execute_in_thread(Box::new(move |ruby: &Ruby| {
.as_ref() let var = ruby
.unwrap() .class_object()
.execute(Box::new(move |ruby| { .const_get::<_, RModule>("Bevy")
let var = ruby .unwrap()
.class_object() .const_get::<_, RClass>("Entity")
.const_get::<_, RModule>("Bevy") .unwrap();
.unwrap() var.ivar_set("_current", BevyEntity(entity)).unwrap();
.const_get::<_, RClass>("Entity")
.unwrap();
var.ivar_set("_current", BevyEntity(entity)).unwrap();
let args: Vec<_> = args let args: Vec<_> = args
.parse(&ruby) .parse(&ruby)
.into_iter() .into_iter()
.map(|a| ruby.get_inner(a.0)) .map(|a| ruby.get_inner(a.0))
.collect(); .collect();
let return_value: magnus::Value = let return_value: magnus::Value = ruby.class_object().funcall(name, args.as_slice())?;
ruby.class_object().funcall(name, args.as_slice())?;
var.ivar_set("_current", ruby.qnil().as_value()).unwrap(); var.ivar_set("_current", ruby.qnil().as_value()).unwrap();
Ok(RubyValue::new(return_value)) Ok(RubyValue::new(return_value))
})) }))
} }
fn call_fn_from_value( fn call_fn_from_value(
@ -471,7 +477,7 @@ impl Runtime for RubyRuntime {
})) }))
} }
fn is_current_thread() -> bool { fn needs_own_thread() -> bool {
false false
} }
} }