ruby thread spawn one per binary

This commit is contained in:
Jaroslaw Konik 2025-05-10 09:20:18 +02:00
parent aee3276f2b
commit a3a40182f5
2 changed files with 56 additions and 49 deletions

View file

@ -25,10 +25,7 @@ use crate::{
};
#[derive(Resource)]
pub struct RubyRuntime {
ruby_thread: Option<JoinHandle<()>>,
ruby_thread_sender: Option<crossbeam_channel::Sender<Box<dyn FnOnce(Ruby) + Send>>>,
}
pub struct RubyRuntime {}
#[derive(ScheduleLabel, Clone, PartialEq, Eq, Debug, Hash, Default)]
pub struct RubySchedule;
@ -55,31 +52,54 @@ struct RubyEngine(Cleanup);
// TODO: Add SAFETY?
unsafe impl Send for RubyEngine {}
impl Default for RubyRuntime {
fn default() -> Self {
let (ruby_thread_sender, ruby_thread_receiver) =
crossbeam_channel::unbounded::<Box<dyn FnOnce(Ruby) + Send>>();
let ruby_thread = thread::spawn(move || {
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() {
struct RubyThread {
sender: Option<crossbeam_channel::Sender<Box<dyn FnOnce(Ruby) + Send>>>,
handle: Option<JoinHandle<()>>,
}
static RUBY_THREAD: LazyLock<RubyThread> = LazyLock::new(|| RubyThread::spawn());
impl RubyThread {
fn spawn() -> Self {
let (sender, receiver) = crossbeam_channel::unbounded::<Box<dyn FnOnce(Ruby) + Send>>();
let handle = thread::spawn(move || {
unsafe { magnus::embed::init() };
while let Ok(val) = receiver.recv() {
let ruby = Ruby::get().unwrap();
val(ruby);
}
});
Self {
ruby_thread: Some(ruby_thread),
ruby_thread_sender: Some(ruby_thread_sender),
RubyThread {
sender: Some(sender),
handle: Some(handle),
}
}
fn execute_in(&self, f: Box<dyn FnOnce(Ruby) + Send>) {
self.sender
.as_ref()
.unwrap()
.send(Box::new(move |ruby| {
let result = f(ruby);
println!("{:?}", result);
}))
.unwrap();
}
}
impl Drop for RubyRuntime {
impl Drop for RubyThread {
fn drop(&mut self) {
drop(self.ruby_thread_sender.take().unwrap());
let ruby_thread = self.ruby_thread.take().unwrap();
ruby_thread.join().unwrap();
drop(self.sender.take().unwrap());
let handle = self.handle.take().unwrap();
handle.join().unwrap();
}
}
impl Default for RubyRuntime {
fn default() -> Self {
Self {}
}
}
@ -113,14 +133,9 @@ impl Runtime for RubyRuntime {
entity: bevy::prelude::Entity,
) -> Result<Self::ScriptData, crate::ScriptingError> {
let script = script.0.clone();
self.ruby_thread_sender
.as_ref()
.unwrap()
.send(Box::new(move |ruby| {
ruby.eval::<magnus::value::Value>(&script).unwrap();
}))
.unwrap();
RUBY_THREAD.execute_in(Box::new(move |ruby| {
ruby.eval::<magnus::value::Value>(&script).unwrap();
}));
Ok(RubyScriptData)
}
@ -158,13 +173,9 @@ impl Runtime for RubyRuntime {
ruby.qnil().as_value()
}
self.ruby_thread_sender
.as_ref()
.unwrap()
.send(Box::new(move |ruby| {
ruby.define_global_function(&name, function!(callback, 1));
}))
.unwrap();
RUBY_THREAD.execute_in(Box::new(move |ruby| {
ruby.define_global_function(&name, function!(callback, 1));
}));
Ok(())
}
@ -177,13 +188,9 @@ impl Runtime for RubyRuntime {
args: impl for<'a> crate::FuncArgs<'a, Self::Value, Self>,
) -> Result<Self::Value, crate::ScriptingError> {
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();
}))
.unwrap();
RUBY_THREAD.execute_in(Box::new(move |ruby| {
let _: magnus::value::Value = ruby.class_object().funcall(name, ()).unwrap();
}));
Ok(RubyValue(()))
}

View file

@ -493,13 +493,13 @@ mod ruby_tests {
type ScriptData = RubyScriptData;
fn assert_state_key_value_i64(world: &World, _entity_id: Entity, key: &str, value: i64) {
let state: magnus::value::Value = Ruby::get()
.unwrap()
.class_object()
.const_get("STATE")
.unwrap();
let res: i64 = state.funcall_public("[]", (key.to_string(),)).unwrap();
assert_eq!(res, value)
// let state: magnus::value::Value = Ruby::get()
// .unwrap()
// .class_object()
// .const_get("STATE")
// .unwrap();
// let res: i64 = state.funcall_public("[]", (key.to_string(),)).unwrap();
// assert_eq!(res, value)
}
fn assert_state_key_value_i32(world: &World, _entity_id: Entity, key: &str, value: i32) {