Skip to content

Commit 5848e6f

Browse files
committed
implement iterators, and add function passing
1 parent 6540642 commit 5848e6f

File tree

9 files changed

+267
-50
lines changed

9 files changed

+267
-50
lines changed

crates/bevy_mod_scripting_core/src/bindings/function/into.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ use crate::{
1313
self_type_dependency_only,
1414
};
1515

16-
use super::from::Val;
16+
use super::{
17+
from::Val,
18+
script_function::{DynamicScriptFunction, DynamicScriptFunctionMut},
19+
};
1720

1821
pub trait IntoScript {
1922
fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError>;
@@ -32,9 +35,16 @@ impl IntoScript for () {
3235
Ok(ScriptValue::Unit)
3336
}
3437
}
35-
3638
self_type_dependency_only!(());
3739

40+
impl IntoScript for DynamicScriptFunctionMut {
41+
fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
42+
Ok(ScriptValue::Function(self))
43+
}
44+
}
45+
46+
self_type_dependency_only!(DynamicScriptFunctionMut, DynamicScriptFunction);
47+
3848
impl IntoScript for bool {
3949
fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
4050
Ok(ScriptValue::Bool(self))

crates/bevy_mod_scripting_core/src/bindings/function/mod.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use bevy::reflect::{
1313
},
1414
PartialReflect,
1515
};
16-
use script_function::{CallerContext, DynamicScriptFunction};
16+
use script_function::{CallerContext, DynamicScriptFunction, DynamicScriptFunctionMut};
1717

1818
use crate::{
1919
error::{FlattenError, InteropError, InteropErrorInner, ScriptError, ScriptResult},
@@ -30,7 +30,7 @@ use super::{
3030
/// The claim and release functions must be used to scope the access to the world such that function output .
3131
pub trait CallScriptFunction {
3232
fn call_script_function<I: IntoIterator<Item = ScriptValue>>(
33-
&self,
33+
&mut self,
3434
args: I,
3535
world: WorldGuard,
3636
context: CallerContext,
@@ -39,7 +39,25 @@ pub trait CallScriptFunction {
3939

4040
impl CallScriptFunction for DynamicScriptFunction {
4141
fn call_script_function<I: IntoIterator<Item = ScriptValue>>(
42-
&self,
42+
&mut self,
43+
args: I,
44+
world: WorldGuard,
45+
context: CallerContext,
46+
) -> Result<ScriptValue, InteropError> {
47+
let args = args.into_iter().collect::<Vec<_>>();
48+
let world_callback_access = WorldCallbackAccess::from_guard(world.clone());
49+
// should we be inlining call errors into the return value?
50+
let return_val = self.call(context, world_callback_access, args);
51+
match return_val {
52+
ScriptValue::Error(e) => Err(InteropError::function_interop_error(self.name(), e)),
53+
v => Ok(v),
54+
}
55+
}
56+
}
57+
58+
impl CallScriptFunction for DynamicScriptFunctionMut {
59+
fn call_script_function<I: IntoIterator<Item = ScriptValue>>(
60+
&mut self,
4361
args: I,
4462
world: WorldGuard,
4563
context: CallerContext,

crates/bevy_mod_scripting_core/src/bindings/function/script_function.rs

Lines changed: 142 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ pub trait ScriptFunction<'env, Marker> {
3030
fn into_dynamic_script_function(self) -> DynamicScriptFunction;
3131
}
3232

33+
#[diagnostic::on_unimplemented(
34+
message = "Only functions with all arguments impplementing FromScript and return values supporting IntoScript are supported. Registering functions also requires they implement GetInnerTypeDependencies",
35+
note = "If you're trying to return a non-primitive type, you might need to use Val<T> Ref<T> or Mut<T> wrappers"
36+
)]
37+
pub trait ScriptFunctionMut<'env, Marker> {
38+
fn into_dynamic_script_function_mut(self) -> DynamicScriptFunctionMut;
39+
}
40+
3341
/// Functionally identical to [`GetTypeRegistration`] but without the 'static bound
3442
pub trait GetInnerTypeDependencies {
3543
fn register_type_dependencies(registry: &mut TypeRegistry);
@@ -39,8 +47,8 @@ pub trait GetInnerTypeDependencies {
3947
macro_rules! no_type_dependencies {
4048
($($path:path),*) => {
4149
$(
42-
impl GetInnerTypeDependencies for $path {
43-
fn register_type_dependencies(_registry: &mut TypeRegistry) {}
50+
impl $crate::bindings::function::script_function::GetInnerTypeDependencies for $path {
51+
fn register_type_dependencies(_registry: &mut bevy::reflect::TypeRegistry) {}
4452
}
4553
)*
4654
};
@@ -115,7 +123,8 @@ pub struct CallerContext {
115123
}
116124

117125
/// The Script Function equivalent for dynamic functions. Currently unused
118-
#[derive(Clone)]
126+
#[derive(Clone, Reflect)]
127+
#[reflect(opaque)]
119128
pub struct DynamicScriptFunction {
120129
name: Cow<'static, str>,
121130
// TODO: info about the function, this is hard right now because of non 'static lifetimes in wrappers, we can't use TypePath etc
@@ -126,6 +135,34 @@ pub struct DynamicScriptFunction {
126135
+ 'static,
127136
>,
128137
}
138+
139+
impl PartialEq for DynamicScriptFunction {
140+
fn eq(&self, other: &Self) -> bool {
141+
self.name == other.name
142+
}
143+
}
144+
145+
#[derive(Clone, Reflect)]
146+
#[reflect(opaque)]
147+
pub struct DynamicScriptFunctionMut {
148+
name: Cow<'static, str>,
149+
func: Arc<
150+
RwLock<
151+
// I'd rather consume an option or something instead of having the RWLock but I just wanna get this release out
152+
dyn FnMut(CallerContext, WorldCallbackAccess, Vec<ScriptValue>) -> ScriptValue
153+
+ Send
154+
+ Sync
155+
+ 'static,
156+
>,
157+
>,
158+
}
159+
160+
impl PartialEq for DynamicScriptFunctionMut {
161+
fn eq(&self, other: &Self) -> bool {
162+
self.name == other.name
163+
}
164+
}
165+
129166
impl DynamicScriptFunction {
130167
pub fn call(
131168
&self,
@@ -148,9 +185,72 @@ impl DynamicScriptFunction {
148185
}
149186
}
150187

188+
impl DynamicScriptFunctionMut {
189+
pub fn call(
190+
&mut self,
191+
context: CallerContext,
192+
world: WorldCallbackAccess,
193+
args: Vec<ScriptValue>,
194+
) -> ScriptValue {
195+
let mut write = self.func.write();
196+
write(context, world, args)
197+
}
198+
199+
pub fn name(&self) -> &Cow<'static, str> {
200+
&self.name
201+
}
202+
203+
pub fn with_name<N: Into<Cow<'static, str>>>(self, name: N) -> Self {
204+
Self {
205+
name: name.into(),
206+
func: self.func,
207+
}
208+
}
209+
}
210+
151211
impl std::fmt::Debug for DynamicScriptFunction {
152212
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153-
f.debug_struct("DynamicScriptFunction").finish()
213+
f.debug_struct("DynamicScriptFunction")
214+
.field("name", self.name())
215+
.finish()
216+
}
217+
}
218+
219+
impl std::fmt::Debug for DynamicScriptFunctionMut {
220+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221+
f.debug_struct("DynamicScriptFunctionMut")
222+
.field("name", self.name())
223+
.finish()
224+
}
225+
}
226+
227+
impl<F> From<F> for DynamicScriptFunction
228+
where
229+
F: Fn(CallerContext, WorldCallbackAccess, Vec<ScriptValue>) -> ScriptValue
230+
+ Send
231+
+ Sync
232+
+ 'static,
233+
{
234+
fn from(fn_: F) -> Self {
235+
DynamicScriptFunction {
236+
name: std::any::type_name::<F>().into(),
237+
func: Arc::new(fn_),
238+
}
239+
}
240+
}
241+
242+
impl<F> From<F> for DynamicScriptFunctionMut
243+
where
244+
F: FnMut(CallerContext, WorldCallbackAccess, Vec<ScriptValue>) -> ScriptValue
245+
+ Send
246+
+ Sync
247+
+ 'static,
248+
{
249+
fn from(fn_: F) -> Self {
250+
DynamicScriptFunctionMut {
251+
name: std::any::type_name::<F>().into(),
252+
func: Arc::new(RwLock::new(fn_)),
253+
}
154254
}
155255
}
156256

@@ -261,39 +361,59 @@ macro_rules! count {
261361
macro_rules! impl_script_function {
262362

263363
($( $param:ident ),* ) => {
264-
// fn(T1...Tn) -> O
265-
impl_script_function!(@ $( $param ),* : -> O => O );
266-
// fn(WorldCallbackAccess, T1...Tn) -> O
267-
impl_script_function!(@ $( $param ),* : ,(callback: WorldCallbackAccess) -> O => O);
268-
// fn(CallerContext, WorldCallbackAccess, T1...Tn) -> O
269-
impl_script_function!(@ $( $param ),* : (context: CallerContext),(callback: WorldCallbackAccess) -> O => O);
270-
271-
// fn(T1...Tn) -> Result<O, InteropError>
272-
impl_script_function!(@ $( $param ),* : -> O => Result<O, InteropError> where s);
273-
// fn(WorldCallbackAccess, T1...Tn) -> Result<O, InteropError>
274-
impl_script_function!(@ $( $param ),* : ,(callback: WorldCallbackAccess) -> O => Result<O, InteropError> where s);
275-
// fn(CallerContext, WorldCallbackAccess, T1...Tn) -> Result<O, InteropError>
276-
impl_script_function!(@ $( $param ),* : (context: CallerContext),(callback: WorldCallbackAccess) -> O => Result<O, InteropError> where s);
364+
// all of this is pretty heavy on the compile time.
365+
// ideally we'd do less, but for now this will suffice
366+
367+
// Fn(T1...Tn) -> O
368+
impl_script_function!(@ ScriptFunction Fn DynamicScriptFunction into_dynamic_script_function $( $param ),* : -> O => O );
369+
// FnMut(T1...Tn) -> O
370+
impl_script_function!(@ ScriptFunctionMut FnMut DynamicScriptFunctionMut into_dynamic_script_function_mut $( $param ),* : -> O => O );
371+
372+
// Fn(WorldCallbackAccess, T1...Tn) -> O
373+
impl_script_function!(@ ScriptFunction Fn DynamicScriptFunction into_dynamic_script_function $( $param ),* : ,(callback: WorldCallbackAccess) -> O => O);
374+
// FnMut(WorldCallbackAccess, T1...Tn) -> O
375+
impl_script_function!(@ ScriptFunctionMut FnMut DynamicScriptFunctionMut into_dynamic_script_function_mut $( $param ),* : ,(callback: WorldCallbackAccess) -> O => O);
376+
377+
// Fn(CallerContext, WorldCallbackAccess, T1...Tn) -> O
378+
impl_script_function!(@ ScriptFunction Fn DynamicScriptFunction into_dynamic_script_function $( $param ),* : (context: CallerContext),(callback: WorldCallbackAccess) -> O => O);
379+
// FnMut(CallerContext, WorldCallbackAccess, T1...Tn) -> O
380+
impl_script_function!(@ ScriptFunctionMut FnMut DynamicScriptFunctionMut into_dynamic_script_function_mut $( $param ),* : (context: CallerContext),(callback: WorldCallbackAccess) -> O => O);
381+
382+
// Fn(T1...Tn) -> Result<O, InteropError>
383+
impl_script_function!(@ ScriptFunction Fn DynamicScriptFunction into_dynamic_script_function $( $param ),* : -> O => Result<O, InteropError> where s);
384+
// FnMut(T1...Tn) -> Result<O, InteropError>
385+
impl_script_function!(@ ScriptFunctionMut FnMut DynamicScriptFunctionMut into_dynamic_script_function_mut $( $param ),* : -> O => Result<O, InteropError> where s);
386+
387+
// Fn(WorldCallbackAccess, T1...Tn) -> Result<O, InteropError>
388+
impl_script_function!(@ ScriptFunction Fn DynamicScriptFunction into_dynamic_script_function $( $param ),* : ,(callback: WorldCallbackAccess) -> O => Result<O, InteropError> where s);
389+
// FnMut(WorldCallbackAccess, T1...Tn) -> Result<O, InteropError>
390+
impl_script_function!(@ ScriptFunctionMut FnMut DynamicScriptFunctionMut into_dynamic_script_function_mut $( $param ),* : ,(callback: WorldCallbackAccess) -> O => Result<O, InteropError> where s);
391+
392+
// Fn(CallerContext, WorldCallbackAccess, T1...Tn) -> Result<O, InteropError>
393+
impl_script_function!(@ ScriptFunction Fn DynamicScriptFunction into_dynamic_script_function $( $param ),* : (context: CallerContext),(callback: WorldCallbackAccess) -> O => Result<O, InteropError> where s);
394+
// FnMut(CallerContext, WorldCallbackAccess, T1...Tn) -> Result<O, InteropError>
395+
impl_script_function!(@ ScriptFunctionMut FnMut DynamicScriptFunctionMut into_dynamic_script_function_mut $( $param ),* : (context: CallerContext),(callback: WorldCallbackAccess) -> O => Result<O, InteropError> where s);
396+
277397

278398
};
279399

280-
(@ $( $param:ident ),* : $(($context:ident: $contextty:ty))? $(,($callback:ident: $callbackty:ty))? -> O => $res:ty $(where $out:ident)?) => {
400+
(@ $trait_type:ident $fn_type:ident $dynamic_type:ident $trait_fn_name:ident $( $param:ident ),* : $(($context:ident: $contextty:ty))? $(,($callback:ident: $callbackty:ty))? -> O => $res:ty $(where $out:ident)?) => {
281401
#[allow(non_snake_case)]
282402
impl<
283403
'env,
284404
$( $param: FromScript, )*
285405
O,
286406
F
287-
> ScriptFunction<'env,
407+
> $trait_type<'env,
288408
fn( $($contextty,)? $( $callbackty, )? $($param ),* ) -> $res
289409
> for F
290410
where
291411
O: IntoScript + TypePath + GetOwnership,
292-
F: Fn( $($contextty,)? $( $callbackty, )? $($param ),* ) -> $res + Send + Sync + 'static,
412+
F: $fn_type( $($contextty,)? $( $callbackty, )? $($param ),* ) -> $res + Send + Sync + 'static,
293413
$( $param::This<'env>: Into<$param>,)*
294414
{
295415
#[allow(unused_mut,unused_variables)]
296-
fn into_dynamic_script_function(self) -> DynamicScriptFunction {
416+
fn $trait_fn_name(mut self) -> $dynamic_type {
297417
let func = (move |caller_context: CallerContext, world: WorldCallbackAccess, args: Vec<ScriptValue> | {
298418
let res: Result<ScriptValue, InteropError> = (|| {
299419
let expected_arg_count = count!($($param )*);
@@ -330,7 +450,7 @@ macro_rules! impl_script_function {
330450
script_value
331451
});
332452

333-
DynamicScriptFunction { func: Arc::new(func), name: core::any::type_name::<Self>().into() }
453+
func.into()
334454
}
335455
}
336456
};

crates/bevy_mod_scripting_core/src/bindings/pretty_print.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ impl DisplayWithWorld for ScriptValue {
397397
fn display_value_with_world(&self, world: WorldGuard) -> String {
398398
match self {
399399
ScriptValue::Reference(r) => r.display_value_with_world(world),
400+
ScriptValue::Function(f) => format!("Function({})", f.name()),
400401
ScriptValue::Unit => "()".to_owned(),
401402
ScriptValue::Bool(b) => b.to_string(),
402403
ScriptValue::Integer(i) => i.to_string(),

crates/bevy_mod_scripting_core/src/bindings/script_value/mod.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ use crate::{
1515
reflection_extensions::{PartialReflectExt, TypeIdExtensions, TypeInfoExtensions},
1616
};
1717

18-
use super::{pretty_print::DisplayWithWorld, ReflectReference, WorldGuard};
18+
use super::{
19+
function::script_function::{DynamicScriptFunction, DynamicScriptFunctionMut},
20+
pretty_print::DisplayWithWorld,
21+
ReflectReference, WorldGuard,
22+
};
1923

2024
/// An abstraction of values that can be passed to and from scripts.
2125
/// This allows us to re-use logic between scripting languages.
@@ -36,6 +40,8 @@ pub enum ScriptValue {
3640
List(Vec<ScriptValue>),
3741
/// Represents a reference to a value.
3842
Reference(ReflectReference),
43+
/// A dynamic script function
44+
Function(DynamicScriptFunctionMut),
3945
/// Represents any error, will be thrown when returned to a script
4046
Error(InteropError),
4147
}
@@ -50,6 +56,7 @@ impl ScriptValue {
5056
ScriptValue::String(_) => "String".to_owned(),
5157
ScriptValue::List(_) => "List".to_owned(),
5258
ScriptValue::Reference(_) => "Reference".to_owned(),
59+
ScriptValue::Function(_) => "Function".to_owned(),
5360
ScriptValue::Error(_) => "Error".to_owned(),
5461
}
5562
}
@@ -109,12 +116,6 @@ impl From<ReflectReference> for ScriptValue {
109116
}
110117
}
111118

112-
// impl From<ScriptError> for ScriptValue {
113-
// fn from(value: ScriptError) -> Self {
114-
// ScriptValue::Error(value)
115-
// }
116-
// }
117-
118119
impl From<InteropError> for ScriptValue {
119120
fn from(value: InteropError) -> Self {
120121
ScriptValue::Error(value)

0 commit comments

Comments
 (0)