ruby fibers POC
This commit is contained in:
parent
c6bdfb1400
commit
57f865178a
4 changed files with 71 additions and 18 deletions
|
|
@ -35,6 +35,7 @@ magnus = { version = "0.7.1", optional = true }
|
||||||
rb-sys = { version = "0.9", default-features = false, features = ["link-ruby", "ruby-static"], optional = true }
|
rb-sys = { version = "0.9", default-features = false, features = ["link-ruby", "ruby-static"], optional = true }
|
||||||
crossbeam-channel = "0.5.15"
|
crossbeam-channel = "0.5.15"
|
||||||
libc = "0.2.172"
|
libc = "0.2.172"
|
||||||
|
tempfile = "3.20.0"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "call_function_from_rust_rhai"
|
name = "call_function_from_rust_rhai"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,2 @@
|
||||||
get_player_name.and_then do |name|
|
puts get_player_name.await
|
||||||
puts name
|
quit
|
||||||
end
|
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,19 @@ fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_scripting::<RubyRuntime>(|builder| {
|
.add_scripting::<RubyRuntime>(|builder| {
|
||||||
builder.add_function(
|
builder
|
||||||
String::from("get_player_name"),
|
.add_function(
|
||||||
|player_names: Query<&Name, With<Player>>| {
|
String::from("get_player_name"),
|
||||||
player_names
|
|player_names: Query<&Name, With<Player>>| {
|
||||||
.single()
|
player_names
|
||||||
.expect("Missing player_names")
|
.single()
|
||||||
.to_string()
|
.expect("Missing player_names")
|
||||||
},
|
.to_string()
|
||||||
);
|
},
|
||||||
|
)
|
||||||
|
.add_function(String::from("quit"), |mut exit: EventWriter<AppExit>| {
|
||||||
|
exit.write(AppExit::Success);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.add_systems(Startup, startup)
|
.add_systems(Startup, startup)
|
||||||
.run();
|
.run();
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
ffi::CString,
|
ffi::CString,
|
||||||
|
io::Write,
|
||||||
sync::{Arc, Condvar, LazyLock, Mutex},
|
sync::{Arc, Condvar, LazyLock, Mutex},
|
||||||
thread::{self, JoinHandle},
|
thread::{self, JoinHandle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ::magnus::{typed_data::Inspect, value::Opaque};
|
use ::magnus::{
|
||||||
|
typed_data::Inspect,
|
||||||
|
value::{self, Opaque},
|
||||||
|
};
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::Asset,
|
asset::Asset,
|
||||||
ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel},
|
ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel},
|
||||||
|
|
@ -19,7 +23,7 @@ use magnus::{
|
||||||
value::{Lazy, ReprValue},
|
value::{Lazy, ReprValue},
|
||||||
};
|
};
|
||||||
use magnus::{method, prelude::*};
|
use magnus::{method, prelude::*};
|
||||||
use rb_sys::{VALUE, ruby_init_stack};
|
use rb_sys::{VALUE, rb_load, ruby_init_stack};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -174,6 +178,25 @@ fn then(r_self: magnus::Value) -> magnus::Value {
|
||||||
.into_value()
|
.into_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn await_promise(r_self: magnus::Value) -> magnus::Value {
|
||||||
|
let promise: &Promise<(), RubyValue> =
|
||||||
|
TryConvert::try_convert(r_self).expect("Couldn't convert self to Promise");
|
||||||
|
let ruby =
|
||||||
|
Ruby::get().expect("Failed to get a handle to Ruby API when registering Promise callback");
|
||||||
|
let fiber = Opaque::from(ruby.fiber_current());
|
||||||
|
promise
|
||||||
|
.clone()
|
||||||
|
.then(RubyValue::new(
|
||||||
|
ruby.proc_from_fn(move |ruby, args, _| {
|
||||||
|
let fiber = ruby.get_inner(fiber);
|
||||||
|
fiber.resume::<_, magnus::Value>(args).unwrap();
|
||||||
|
})
|
||||||
|
.as_value(),
|
||||||
|
))
|
||||||
|
.into_value();
|
||||||
|
ruby.fiber_yield::<_, magnus::Value>(()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[magnus::wrap(class = "Bevy::Entity")]
|
#[magnus::wrap(class = "Bevy::Entity")]
|
||||||
pub struct BevyEntity(pub Entity);
|
pub struct BevyEntity(pub Entity);
|
||||||
|
|
@ -266,6 +289,7 @@ impl Default for RubyRuntime {
|
||||||
|
|
||||||
let promise = module.define_class("Promise", ruby.class_object())?;
|
let promise = module.define_class("Promise", ruby.class_object())?;
|
||||||
promise.define_method("and_then", magnus::method!(then, 0))?;
|
promise.define_method("and_then", magnus::method!(then, 0))?;
|
||||||
|
promise.define_method("await", magnus::method!(await_promise, 0))?;
|
||||||
|
|
||||||
let vec3 = module.define_class("Vec3", ruby.class_object())?;
|
let vec3 = module.define_class("Vec3", ruby.class_object())?;
|
||||||
vec3.define_singleton_method("new", function!(BevyVec3::new, 3))?;
|
vec3.define_singleton_method("new", function!(BevyVec3::new, 3))?;
|
||||||
|
|
@ -392,10 +416,35 @@ impl Runtime for RubyRuntime {
|
||||||
) -> Result<Self::ScriptData, crate::ScriptingError> {
|
) -> Result<Self::ScriptData, crate::ScriptingError> {
|
||||||
let script = script.0.clone();
|
let script = script.0.clone();
|
||||||
self.execute_in_thread(Box::new(move |ruby: &Ruby| {
|
self.execute_in_thread(Box::new(move |ruby: &Ruby| {
|
||||||
Self::with_current_entity(ruby, entity, || {
|
let p = Opaque::from(ruby.proc_from_fn(move |ruby, _args, _block| {
|
||||||
ruby.eval::<magnus::value::Value>(&script)
|
Self::with_current_entity(ruby, entity, || {
|
||||||
.map_err(<magnus::Error as Into<ScriptingError>>::into)
|
let mut tmpfile = tempfile::NamedTempFile::new().unwrap();
|
||||||
})?;
|
tmpfile.write(script.as_bytes()).unwrap();
|
||||||
|
unsafe {
|
||||||
|
let file = rb_sys::rb_str_new_cstr(
|
||||||
|
CString::new(tmpfile.path().to_str().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.into_raw(),
|
||||||
|
);
|
||||||
|
rb_load(file, 1);
|
||||||
|
};
|
||||||
|
// ruby.eval::<magnus::value::Value>(&script)
|
||||||
|
// .map_err(<magnus::Error as Into<ScriptingError>>::into)
|
||||||
|
Ok::<(), ScriptingError>(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}));
|
||||||
|
let fiber = ruby
|
||||||
|
.fiber_new_from_fn(Default::default(), move |ruby, _args, _block| {
|
||||||
|
let p = ruby.get_inner(p);
|
||||||
|
|
||||||
|
p.call::<_, value::Value>(()).unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
fiber.resume::<_, value::Value>(()).unwrap();
|
||||||
|
|
||||||
Ok::<Self::ScriptData, ScriptingError>(RubyScriptData)
|
Ok::<Self::ScriptData, ScriptingError>(RubyScriptData)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue