Ruby support #1

Open
jaroslaw wants to merge 165 commits from ruby into main
Showing only changes of commit aee3276f2b - Show all commits

View file

@ -10,6 +10,7 @@ use bevy::{
ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel}, ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel},
reflect::TypePath, reflect::TypePath,
}; };
use magnus::Ruby;
use magnus::{ use magnus::{
embed::{init, Cleanup}, embed::{init, Cleanup},
function, function,
@ -26,7 +27,7 @@ use crate::{
#[derive(Resource)] #[derive(Resource)]
pub struct RubyRuntime { pub struct RubyRuntime {
ruby_thread: Option<JoinHandle<()>>, ruby_thread: Option<JoinHandle<()>>,
ruby_thread_sender: Option<crossbeam_channel::Sender<()>>, ruby_thread_sender: Option<crossbeam_channel::Sender<Box<dyn FnOnce(Ruby) + Send>>>,
} }
#[derive(ScheduleLabel, Clone, PartialEq, Eq, Debug, Hash, Default)] #[derive(ScheduleLabel, Clone, PartialEq, Eq, Debug, Hash, Default)]
@ -54,16 +55,17 @@ struct RubyEngine(Cleanup);
// TODO: Add SAFETY? // TODO: Add SAFETY?
unsafe impl Send for RubyEngine {} unsafe impl Send for RubyEngine {}
static RUBY_ENGINE: LazyLock<Mutex<RubyEngine>> =
LazyLock::new(|| Mutex::new(RubyEngine(unsafe { magnus::embed::init() })));
impl Default for RubyRuntime { impl Default for RubyRuntime {
fn default() -> Self { fn default() -> Self {
let (ruby_thread_sender, ruby_thread_receiver) = crossbeam_channel::unbounded::<()>(); let (ruby_thread_sender, ruby_thread_receiver) =
crossbeam_channel::unbounded::<Box<dyn FnOnce(Ruby) + Send>>();
let ruby_thread = thread::spawn(move || { let ruby_thread = thread::spawn(move || {
let _cleanup = LazyLock::force(&RUBY_ENGINE); static RUBY_ENGINE: LazyLock<Mutex<RubyEngine>> =
LazyLock::new(|| Mutex::new(RubyEngine(unsafe { magnus::embed::init() })));
LazyLock::force(&RUBY_ENGINE);
while let Ok(val) = ruby_thread_receiver.recv() { while let Ok(val) = ruby_thread_receiver.recv() {
println!("received"); let ruby = Ruby::get().unwrap();
val(ruby);
} }
}); });
Self { Self {
@ -110,8 +112,15 @@ impl Runtime for RubyRuntime {
script: &Self::ScriptAsset, script: &Self::ScriptAsset,
entity: bevy::prelude::Entity, entity: bevy::prelude::Entity,
) -> Result<Self::ScriptData, crate::ScriptingError> { ) -> Result<Self::ScriptData, crate::ScriptingError> {
let ruby = magnus::Ruby::get().unwrap(); let script = script.0.clone();
ruby.eval::<magnus::value::Qnil>(&script.0); self.ruby_thread_sender
.as_ref()
.unwrap()
.send(Box::new(move |ruby| {
ruby.eval::<magnus::value::Value>(&script).unwrap();
}))
.unwrap();
Ok(RubyScriptData) Ok(RubyScriptData)
} }
@ -129,28 +138,34 @@ impl Runtime for RubyRuntime {
+ Sync + Sync
+ 'static, + 'static,
) -> Result<(), crate::ScriptingError> { ) -> Result<(), crate::ScriptingError> {
let ruby = magnus::Ruby::get().unwrap(); // let ruby = magnus::Ruby::get().unwrap();
//
// static mut FUN: Vec<Box<dyn Fn()>> = Vec::new();
// unsafe {
// FUN.push(Box::new(move || {
// f((), vec![]).unwrap();
// }));
// }
//
static mut FUN: Vec<Box<dyn Fn()>> = Vec::new(); fn callback(val: magnus::Value) -> magnus::Value {
unsafe { // println!("{:?}", val);
FUN.push(Box::new(move || {
f((), vec![]).unwrap();
}));
}
let sender = self.ruby_thread_sender.as_ref().clone();
let x = 5;
fn callback() -> magnus::Value {
// sender.unwrap().send(()); // sender.unwrap().send(());
let ruby = magnus::Ruby::get().unwrap(); let ruby = magnus::Ruby::get().unwrap();
unsafe { // unsafe {
FUN.pop().unwrap()(); // FUN.pop().unwrap()();
} // }
ruby.qnil().as_value() ruby.qnil().as_value()
} }
ruby.define_global_function(&name, function!(callback, 0)); self.ruby_thread_sender
.as_ref()
.unwrap()
.send(Box::new(move |ruby| {
ruby.define_global_function(&name, function!(callback, 1));
}))
.unwrap();
Ok(()) Ok(())
} }
@ -161,8 +176,15 @@ impl Runtime for RubyRuntime {
entity: bevy::prelude::Entity, entity: bevy::prelude::Entity,
args: impl for<'a> crate::FuncArgs<'a, Self::Value, Self>, args: impl for<'a> crate::FuncArgs<'a, Self::Value, Self>,
) -> Result<Self::Value, crate::ScriptingError> { ) -> Result<Self::Value, crate::ScriptingError> {
let ruby = magnus::Ruby::get().unwrap(); let name = name.to_string();
self.ruby_thread_sender
.as_ref()
.unwrap()
.send(Box::new(move |ruby| {
let _: magnus::value::Value = ruby.class_object().funcall(name, ()).unwrap(); let _: magnus::value::Value = ruby.class_object().funcall(name, ()).unwrap();
}))
.unwrap();
Ok(RubyValue(())) Ok(RubyValue(()))
} }