works
This commit is contained in:
parent
8a3661a77a
commit
dfd96746fe
6 changed files with 50 additions and 34 deletions
|
|
@ -1,5 +1,8 @@
|
||||||
a = get_player_name
|
a = get_player_name
|
||||||
b = a
|
b = a
|
||||||
|
puts '0'
|
||||||
puts a.await
|
puts a.await
|
||||||
|
puts '1'
|
||||||
puts b.await
|
puts b.await
|
||||||
|
puts '2'
|
||||||
quit
|
quit
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,18 @@ pub struct CallbackSystem<R: Runtime> {
|
||||||
pub(crate) arg_types: Vec<TypeId>,
|
pub(crate) arg_types: Vec<TypeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct FunctionCallEvent<C: Send, V: Send, F: Send> {
|
pub(crate) struct FunctionCallEvent<C: Send, V: Send> {
|
||||||
pub(crate) params: Vec<V>,
|
pub(crate) params: Vec<V>,
|
||||||
pub(crate) promise: Promise<C, V, F>,
|
pub(crate) promise: Promise<C, V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Calls<C, V, F> = Arc<Mutex<Vec<FunctionCallEvent<C, V, F>>>>;
|
type Calls<C, V> = Arc<Mutex<Vec<FunctionCallEvent<C, V>>>>;
|
||||||
|
|
||||||
/// A struct representing a Bevy system that can be called from a script.
|
/// A struct representing a Bevy system that can be called from a script.
|
||||||
pub(crate) struct Callback<R: Runtime> {
|
pub(crate) struct Callback<R: Runtime> {
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
pub(crate) system: Arc<Mutex<CallbackSystem<R>>>,
|
pub(crate) system: Arc<Mutex<CallbackSystem<R>>>,
|
||||||
pub(crate) calls: Calls<R::CallContext, R::Value, R::Value>,
|
pub(crate) calls: Calls<R::CallContext, R::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Runtime> Clone for Callback<R> {
|
impl<R: Runtime> Clone for Callback<R> {
|
||||||
|
|
@ -37,7 +37,7 @@ impl<R: Runtime> Clone for Callback<R> {
|
||||||
impl<R: Runtime> CallbackSystem<R> {
|
impl<R: Runtime> CallbackSystem<R> {
|
||||||
pub(crate) fn call(
|
pub(crate) fn call(
|
||||||
&mut self,
|
&mut self,
|
||||||
call: &FunctionCallEvent<R::CallContext, R::Value, R::Value>,
|
call: &FunctionCallEvent<R::CallContext, R::Value>,
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
) -> R::Value {
|
) -> R::Value {
|
||||||
self.system.run(call.params.clone(), world)
|
self.system.run(call.params.clone(), world)
|
||||||
|
|
|
||||||
|
|
@ -345,8 +345,7 @@ pub trait Runtime: Resource + Default {
|
||||||
f: impl Fn(
|
f: impl Fn(
|
||||||
Self::CallContext,
|
Self::CallContext,
|
||||||
Vec<Self::Value>,
|
Vec<Self::Value>,
|
||||||
)
|
) -> Result<Promise<Self::CallContext, Self::Value>, ScriptingError>
|
||||||
-> Result<Promise<Self::CallContext, Self::Value, Self::Value>, ScriptingError>
|
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
|
@ -376,6 +375,8 @@ pub trait Runtime: Resource + Default {
|
||||||
fn needs_rdynamic_linking() -> bool {
|
fn needs_rdynamic_linking() -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resume(&self, fiber: &Self::Value, value: &Self::Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FuncArgs<'a, V, R: Runtime> {
|
pub trait FuncArgs<'a, V, R: Runtime> {
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,29 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use magnus::Fiber;
|
|
||||||
|
|
||||||
use crate::{Runtime, ScriptingError};
|
use crate::{Runtime, ScriptingError};
|
||||||
|
|
||||||
/// A struct that represents a function that will get called when the Promise is resolved.
|
/// A struct that represents a function that will get called when the Promise is resolved.
|
||||||
pub(crate) struct PromiseCallback<C: Send, V: Send, F: Send> {
|
pub(crate) struct PromiseCallback<C: Send, V: Send> {
|
||||||
callback: V,
|
callback: V,
|
||||||
following_promise: Arc<Mutex<PromiseInner<C, V, F>>>,
|
following_promise: Arc<Mutex<PromiseInner<C, V>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal representation of a Promise.
|
/// Internal representation of a Promise.
|
||||||
pub(crate) struct PromiseInner<C: Send, V: Send, F: Send> {
|
pub(crate) struct PromiseInner<C: Send, V: Send> {
|
||||||
pub(crate) callbacks: Vec<PromiseCallback<C, V, F>>,
|
pub(crate) callbacks: Vec<PromiseCallback<C, V>>,
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub(crate) context: C,
|
pub(crate) context: C,
|
||||||
pub(crate) resolved_value: Option<V>,
|
pub(crate) resolved_value: Option<V>,
|
||||||
pub(crate) fibers: Vec<F>, // TODO: should htis be vec or option
|
pub(crate) fibers: Vec<V>, // TODO: should htis be vec or option
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct that represents a Promise.
|
/// A struct that represents a Promise.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Promise<C: Send, V: Send, F: Send> {
|
pub struct Promise<C: Send, V: Send> {
|
||||||
pub(crate) inner: Arc<Mutex<PromiseInner<C, V, F>>>,
|
pub(crate) inner: Arc<Mutex<PromiseInner<C, V>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Send, V: Send + Clone, F: Send + Clone> PromiseInner<C, V, F> {
|
impl<C: Send, V: Send + Clone> PromiseInner<C, V> {
|
||||||
/// Resolve the Promise. This will call all the callbacks that were added to the Promise.
|
/// Resolve the Promise. This will call all the callbacks that were added to the Promise.
|
||||||
fn resolve<R>(&mut self, runtime: &mut R, val: R::Value) -> Result<(), ScriptingError>
|
fn resolve<R>(&mut self, runtime: &mut R, val: R::Value) -> Result<(), ScriptingError>
|
||||||
where
|
where
|
||||||
|
|
@ -45,7 +43,7 @@ impl<C: Send, V: Send + Clone, F: Send + Clone> PromiseInner<C, V, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Clone + Send + 'static, V: Send + Clone, F: Send + Clone> Promise<C, V, F> {
|
impl<C: Clone + Send + 'static, V: Send + Clone> Promise<C, V> {
|
||||||
/// Acquire [Mutex] for writing the promise and resolve it. Call will be forwarded to [PromiseInner::resolve].
|
/// Acquire [Mutex] for writing the promise and resolve it. Call will be forwarded to [PromiseInner::resolve].
|
||||||
pub(crate) fn resolve<R>(
|
pub(crate) fn resolve<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -55,19 +53,24 @@ impl<C: Clone + Send + 'static, V: Send + Clone, F: Send + Clone> Promise<C, V,
|
||||||
where
|
where
|
||||||
R: Runtime<Value = V, CallContext = C>,
|
R: Runtime<Value = V, CallContext = C>,
|
||||||
{
|
{
|
||||||
|
let mut fibers: Vec<V> = vec![];
|
||||||
if let Ok(mut inner) = self.inner.lock() {
|
if let Ok(mut inner) = self.inner.lock() {
|
||||||
inner.resolved_value = Some(val.clone());
|
inner.resolved_value = Some(val.clone());
|
||||||
inner.resolve(runtime, val)?;
|
inner.resolve(runtime, val.clone())?;
|
||||||
|
|
||||||
for fiber in inner.fibers.drain(..) {
|
for fiber in inner.fibers.drain(..) {
|
||||||
println!("resume");
|
fibers.push(fiber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for fiber in fibers {
|
||||||
|
runtime.resume(&fiber, &val.clone());
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a fiber that will be resumed when the [Promise] is resolved.
|
/// Register a fiber that will be resumed when the [Promise] is resolved.
|
||||||
#[cfg(any(feature = "rhai", feature = "lua", feature = "ruby"))]
|
#[cfg(any(feature = "rhai", feature = "lua", feature = "ruby"))]
|
||||||
pub(crate) fn await_promise(&mut self, fiber: F) {
|
pub(crate) fn await_promise(&mut self, fiber: V) {
|
||||||
let mut inner = self
|
let mut inner = self
|
||||||
.inner
|
.inner
|
||||||
.lock()
|
.lock()
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use ::magnus::{
|
use ::magnus::{
|
||||||
|
Fiber,
|
||||||
typed_data::Inspect,
|
typed_data::Inspect,
|
||||||
value::{self, Opaque},
|
value::{self, Opaque},
|
||||||
};
|
};
|
||||||
|
|
@ -129,9 +130,9 @@ impl Drop for RubyThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataTypeFunctions for Promise<(), RubyValue, RubyValue> {}
|
impl DataTypeFunctions for Promise<(), RubyValue> {}
|
||||||
|
|
||||||
unsafe impl TypedData for Promise<(), RubyValue, RubyValue> {
|
unsafe impl TypedData for Promise<(), RubyValue> {
|
||||||
fn class(ruby: &Ruby) -> magnus::RClass {
|
fn class(ruby: &Ruby) -> magnus::RClass {
|
||||||
static CLASS: Lazy<RClass> = Lazy::new(|ruby| {
|
static CLASS: Lazy<RClass> = Lazy::new(|ruby| {
|
||||||
let class = ruby
|
let class = ruby
|
||||||
|
|
@ -147,12 +148,12 @@ unsafe impl TypedData for Promise<(), RubyValue, RubyValue> {
|
||||||
|
|
||||||
fn data_type() -> &'static magnus::DataType {
|
fn data_type() -> &'static magnus::DataType {
|
||||||
static DATA_TYPE: DataType =
|
static DATA_TYPE: DataType =
|
||||||
data_type_builder!(Promise<(), RubyValue, RubyValue>, "Bevy::Promise").build();
|
data_type_builder!(Promise<(), RubyValue>, "Bevy::Promise").build();
|
||||||
&DATA_TYPE
|
&DATA_TYPE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryConvert for Promise<(), RubyValue, RubyValue> {
|
impl TryConvert for Promise<(), RubyValue> {
|
||||||
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
||||||
let result: Result<&Self, _> = TryConvert::try_convert(val);
|
let result: Result<&Self, _> = TryConvert::try_convert(val);
|
||||||
result.cloned()
|
result.cloned()
|
||||||
|
|
@ -160,7 +161,7 @@ impl TryConvert for Promise<(), RubyValue, RubyValue> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn then(r_self: magnus::Value) -> magnus::Value {
|
fn then(r_self: magnus::Value) -> magnus::Value {
|
||||||
let promise: &Promise<(), RubyValue, RubyValue> =
|
let promise: &Promise<(), RubyValue> =
|
||||||
TryConvert::try_convert(r_self).expect("Couldn't convert self to Promise");
|
TryConvert::try_convert(r_self).expect("Couldn't convert self to Promise");
|
||||||
let ruby =
|
let ruby =
|
||||||
Ruby::get().expect("Failed to get a handle to Ruby API when registering Promise callback");
|
Ruby::get().expect("Failed to get a handle to Ruby API when registering Promise callback");
|
||||||
|
|
@ -179,13 +180,13 @@ fn then(r_self: magnus::Value) -> magnus::Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn await_promise(r_self: magnus::Value) -> magnus::Value {
|
fn await_promise(r_self: magnus::Value) -> magnus::Value {
|
||||||
let promise: &Promise<(), RubyValue, RubyValue> =
|
let promise: &Promise<(), RubyValue> =
|
||||||
TryConvert::try_convert(r_self).expect("Couldn't convert self to Promise");
|
TryConvert::try_convert(r_self).expect("Couldn't convert self to Promise");
|
||||||
let ruby =
|
let ruby =
|
||||||
Ruby::get().expect("Failed to get a handle to Ruby API when registering Promise callback");
|
Ruby::get().expect("Failed to get a handle to Ruby API when registering Promise callback");
|
||||||
let fiber = Opaque::from(ruby.fiber_current().as_value());
|
let fiber = Opaque::from(ruby.fiber_current().as_value());
|
||||||
if let Some(value) = &promise.inner.try_lock().unwrap().resolved_value {
|
if let Some(value) = &promise.inner.try_lock().unwrap().resolved_value {
|
||||||
panic!();
|
return ruby.get_inner(value.0);
|
||||||
}
|
}
|
||||||
promise.clone().await_promise(RubyValue(fiber)).into_value();
|
promise.clone().await_promise(RubyValue(fiber)).into_value();
|
||||||
ruby.fiber_yield::<_, magnus::Value>(()).unwrap()
|
ruby.fiber_yield::<_, magnus::Value>(()).unwrap()
|
||||||
|
|
@ -451,7 +452,7 @@ impl Runtime for RubyRuntime {
|
||||||
Self::CallContext,
|
Self::CallContext,
|
||||||
Vec<Self::Value>,
|
Vec<Self::Value>,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
crate::promise::Promise<Self::CallContext, Self::Value, Self::Value>,
|
crate::promise::Promise<Self::CallContext, Self::Value>,
|
||||||
crate::ScriptingError,
|
crate::ScriptingError,
|
||||||
> + Send
|
> + Send
|
||||||
+ Sync
|
+ Sync
|
||||||
|
|
@ -461,10 +462,9 @@ impl Runtime for RubyRuntime {
|
||||||
dyn Fn(
|
dyn Fn(
|
||||||
(),
|
(),
|
||||||
Vec<RubyValue>,
|
Vec<RubyValue>,
|
||||||
) -> Result<
|
)
|
||||||
crate::promise::Promise<(), RubyValue, RubyValue>,
|
-> Result<crate::promise::Promise<(), RubyValue>, crate::ScriptingError>
|
||||||
crate::ScriptingError,
|
+ Send,
|
||||||
> + Send,
|
|
||||||
>;
|
>;
|
||||||
static RUBY_CALLBACKS: LazyLock<Mutex<HashMap<String, CallbackClosure>>> =
|
static RUBY_CALLBACKS: LazyLock<Mutex<HashMap<String, CallbackClosure>>> =
|
||||||
LazyLock::new(|| Mutex::new(HashMap::new()));
|
LazyLock::new(|| Mutex::new(HashMap::new()));
|
||||||
|
|
@ -553,6 +553,15 @@ impl Runtime for RubyRuntime {
|
||||||
fn needs_rdynamic_linking() -> bool {
|
fn needs_rdynamic_linking() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resume(&self, fiber: &Self::Value, value: &Self::Value) {
|
||||||
|
let fiber = fiber.clone();
|
||||||
|
let value = value.clone();
|
||||||
|
self.execute_in_thread(move |ruby| {
|
||||||
|
let fiber: Fiber = TryConvert::try_convert(ruby.get_inner(fiber.0)).unwrap();
|
||||||
|
fiber.resume::<_, magnus::Value>((value.0,));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod magnus {
|
pub mod magnus {
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ pub(crate) fn process_calls<R: Runtime>(world: &mut World) -> Result<(), Scripti
|
||||||
.lock()
|
.lock()
|
||||||
.expect("Failed to lock callback calls mutex")
|
.expect("Failed to lock callback calls mutex")
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.collect::<Vec<FunctionCallEvent<R::CallContext, R::Value, R::Value>>>();
|
.collect::<Vec<FunctionCallEvent<R::CallContext, R::Value>>>();
|
||||||
for mut call in calls {
|
for mut call in calls {
|
||||||
tracing::trace!("process_calls: calling '{}'", callback.name);
|
tracing::trace!("process_calls: calling '{}'", callback.name);
|
||||||
let mut system = callback
|
let mut system = callback
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue