Add has_context to plugin functions.

This commit is contained in:
Stephen Chung 2022-12-03 17:03:15 +08:00
parent 249180b1e0
commit 4998eb6139
9 changed files with 98 additions and 48 deletions

View File

@ -21,6 +21,12 @@ Deprecated API's
* `Module::with_capacity` is deprecated.
* The internal method `Engine::eval_statements_raw` is deprecated.
Speed improvements
------------------
* The functions registration mechanism is revamped to take advantage of constant generics, among others.
* This yields a 20% speed improvements on certain real-life, function-call-heavy workloads.
Net features
------------

View File

@ -23,7 +23,7 @@ ahash = { version = "0.8.2", default-features = false, features = ["compile-time
num-traits = { version = "0.2", default-features = false }
bitflags = { version = "1", default-features = false }
smartstring = { version = "1", default-features = false }
rhai_codegen = { version = "1.4.1", path = "codegen", default-features = false }
rhai_codegen = { version = "1.5.0", path = "codegen", default-features = false }
no-std-compat = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
libm = { version = "0.2", default-features = false, optional = true }

View File

@ -1,6 +1,6 @@
[package]
name = "rhai_codegen"
version = "1.4.4"
version = "1.5.0"
edition = "2018"
resolver = "2"
authors = ["jhwgh1968", "Stephen Chung"]
@ -24,5 +24,5 @@ syn = { version = "1.0", features = ["full", "parsing", "printing", "proc-macro"
quote = "1"
[dev-dependencies]
rhai = { path = "..", version = "1.11", features = ["metadata"] }
rhai = { path = "..", version = "1.12", features = ["metadata"] }
trybuild = "1"

View File

@ -674,6 +674,7 @@ impl ExportedFn {
let arg_count = self.arg_count();
let is_method_call = self.mutable_receiver();
let is_pure = !self.mutable_receiver() || self.params().pure.is_some();
let pass_context = self.pass_context;
let mut unpack_statements = Vec::new();
let mut unpack_exprs = Vec::new();
@ -689,7 +690,7 @@ impl ExportedFn {
let skip_first_arg;
if self.pass_context {
unpack_exprs.push(syn::parse2::<syn::Expr>(quote! { context }).unwrap());
unpack_exprs.push(syn::parse2::<syn::Expr>(quote! { context.unwrap() }).unwrap());
}
// Handle the first argument separately if the function has a "method like" receiver
@ -860,13 +861,14 @@ impl ExportedFn {
#(#cfg_attrs)*
impl PluginFunction for #type_name {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
#(#unpack_statements)*
#return_expr
}
#[inline(always)] fn is_method_call(&self) -> bool { #is_method_call }
#[inline(always)] fn is_pure(&self) -> bool { #is_pure }
#[inline(always)] fn has_context(&self) -> bool { #pass_context }
}
}
}

View File

@ -280,12 +280,13 @@ mod generate_tests {
#[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] }
}
impl PluginFunction for Token {
#[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
#[inline(always)] fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
Ok(Dynamic::from(do_nothing()))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
#[allow(unused)]
#[doc(hidden)]
@ -318,13 +319,14 @@ mod generate_tests {
}
impl PluginFunction for Token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<usize>();
Ok(Dynamic::from(do_something(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
#[allow(unused)]
#[doc(hidden)]
@ -357,13 +359,14 @@ mod generate_tests {
}
impl PluginFunction for Token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<usize>();
Ok(Dynamic::from(do_something(context, arg0)))
Ok(Dynamic::from(do_something(context.unwrap(), arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { true }
}
#[allow(unused)]
#[doc(hidden)]
@ -399,12 +402,13 @@ mod generate_tests {
}
impl PluginFunction for Token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
Ok(Dynamic::from(return_dynamic()))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
#[allow(unused)]
#[doc(hidden)]
@ -432,13 +436,14 @@ mod generate_tests {
}
impl PluginFunction for TestStruct {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<usize>();
Ok(Dynamic::from(do_something(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
};
@ -465,7 +470,7 @@ mod generate_tests {
}
impl PluginFunction for Token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<usize>();
let arg1 = mem::take(args[1usize]).cast::<usize>();
Ok(Dynamic::from(add_together(arg0, arg1)))
@ -473,6 +478,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
#[allow(unused)]
#[doc(hidden)]
@ -505,7 +511,7 @@ mod generate_tests {
}
impl PluginFunction for Token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg1 = mem::take(args[1usize]).cast::<usize>();
let arg0 = &mut args[0usize].write_lock::<usize>().unwrap();
Ok(Dynamic::from(increment(arg0, arg1)))
@ -513,6 +519,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
#[allow(unused)]
#[doc(hidden)]
@ -546,13 +553,14 @@ mod generate_tests {
}
impl PluginFunction for Token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).into_immutable_string().unwrap();
Ok(Dynamic::from(special_print(&arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
#[allow(unused)]
#[doc(hidden)]

View File

@ -386,12 +386,13 @@ mod generate_tests {
}
impl PluginFunction for get_mystic_number_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
Ok(Dynamic::from(get_mystic_number()))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -474,12 +475,13 @@ mod generate_tests {
}
impl PluginFunction for get_mystic_number_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
Ok(Dynamic::from(get_mystic_number()))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -532,13 +534,14 @@ mod generate_tests {
}
impl PluginFunction for add_one_to_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<INT>();
Ok(Dynamic::from(add_one_to(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -590,13 +593,14 @@ mod generate_tests {
}
impl PluginFunction for add_one_to_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<INT>();
Ok(Dynamic::from(add_one_to(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -662,13 +666,14 @@ mod generate_tests {
}
impl PluginFunction for add_one_to_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<INT>();
Ok(Dynamic::from(add_one_to(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
#[allow(non_camel_case_types)]
@ -681,7 +686,7 @@ mod generate_tests {
}
impl PluginFunction for add_n_to_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<INT>();
let arg1 = mem::take(args[1usize]).cast::<INT>();
Ok(Dynamic::from(add_n_to(arg0, arg1)))
@ -689,6 +694,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -740,7 +746,7 @@ mod generate_tests {
}
impl PluginFunction for add_together_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<INT>();
let arg1 = mem::take(args[1usize]).cast::<INT>();
Ok(Dynamic::from(add_together(arg0, arg1)))
@ -748,6 +754,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -806,7 +813,7 @@ mod generate_tests {
}
impl PluginFunction for add_together_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).cast::<INT>();
let arg1 = mem::take(args[1usize]).cast::<INT>();
Ok(Dynamic::from(add_together(arg0, arg1)))
@ -814,6 +821,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -882,13 +890,14 @@ mod generate_tests {
}
impl PluginFunction for get_mystic_number_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = &mut args[0usize].write_lock::<Hello>().unwrap();
Ok(Dynamic::from(get_mystic_number(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1092,12 +1101,13 @@ mod generate_tests {
}
impl PluginFunction for get_mystic_number_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
Ok(Dynamic::from(get_mystic_number()))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1182,13 +1192,14 @@ mod generate_tests {
}
impl PluginFunction for print_out_to_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).into_immutable_string().unwrap();
Ok(Dynamic::from(print_out_to(&arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1240,13 +1251,14 @@ mod generate_tests {
}
impl PluginFunction for print_out_to_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = mem::take(args[0usize]).into_string().unwrap();
Ok(Dynamic::from(print_out_to(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1299,7 +1311,7 @@ mod generate_tests {
}
impl PluginFunction for foo_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg1 = mem::take(args[1usize]).cast::<INT>();
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
Ok(Dynamic::from(foo(arg0, arg1)))
@ -1307,6 +1319,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1358,13 +1371,14 @@ mod generate_tests {
}
impl PluginFunction for increment_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
Ok(Dynamic::from(increment(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1419,13 +1433,14 @@ mod generate_tests {
}
impl PluginFunction for increment_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
Ok(Dynamic::from(increment(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
#[allow(unused_imports)]
@ -1503,13 +1518,14 @@ mod generate_tests {
}
impl PluginFunction for increment_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
Ok(Dynamic::from(increment(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
#[allow(unused_imports)]
@ -1588,13 +1604,14 @@ mod generate_tests {
}
impl PluginFunction for int_foo_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1650,13 +1667,14 @@ mod generate_tests {
}
impl PluginFunction for int_foo_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0)))
}
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1709,7 +1727,7 @@ mod generate_tests {
}
impl PluginFunction for int_foo_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0, arg1)))
@ -1717,6 +1735,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1772,7 +1791,7 @@ mod generate_tests {
}
impl PluginFunction for int_foo_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0, arg1)))
@ -1780,6 +1799,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1832,7 +1852,7 @@ mod generate_tests {
}
impl PluginFunction for get_by_index_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(get_by_index(arg0, arg1)))
@ -1840,6 +1860,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1900,7 +1921,7 @@ mod generate_tests {
#[cfg(hello)]
impl PluginFunction for get_by_index_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(get_by_index(arg0, arg1)))
@ -1908,6 +1929,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -1963,7 +1985,7 @@ mod generate_tests {
}
impl PluginFunction for get_by_index_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(get_by_index(arg0, arg1)))
@ -1971,6 +1993,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -2023,7 +2046,7 @@ mod generate_tests {
}
impl PluginFunction for set_by_index_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg1 = mem::take(args[1usize]).cast::<u64>();
let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
@ -2032,6 +2055,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};
@ -2087,7 +2111,7 @@ mod generate_tests {
}
impl PluginFunction for set_by_index_token {
#[inline(always)]
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
fn call(&self, context: Option<NativeCallContext>, args: &mut [&mut Dynamic]) -> RhaiResult {
let arg1 = mem::take(args[1usize]).cast::<u64>();
let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
@ -2096,6 +2120,7 @@ mod generate_tests {
#[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
}
}
};

View File

@ -401,19 +401,19 @@ impl Engine {
let is_method = func.is_method();
let src = source.as_ref().map(|s| s.as_str());
let mut _result = if let Some(f) = func.get_plugin_fn() {
if !f.is_pure() && !args.is_empty() && args[0].is_read_only() {
Err(ERR::ErrorNonPureMethodCallOnConstant(name.to_string(), pos).into())
} else {
let context = (self, name, src, &*global, pos).into();
f.call(context, args)
}
} else if let Some(f) = func.get_native_fn() {
let context = if func.has_context() {
Some((self, name, src, &*global, pos).into())
} else {
None
};
let mut _result = if let Some(f) = func.get_plugin_fn() {
if !f.is_pure() && !args.is_empty() && args[0].is_read_only() {
Err(ERR::ErrorNonPureMethodCallOnConstant(name.to_string(), pos).into())
} else {
f.call(context, args)
}
} else if let Some(f) = func.get_native_fn() {
f(context, args)
} else {
unreachable!();
@ -1390,8 +1390,12 @@ impl Engine {
}
Some(f) if f.is_plugin_fn() => {
let context = (self, fn_name, module.id(), &*global, pos).into();
let f = f.get_plugin_fn().expect("plugin function");
let context = if f.has_context() {
Some((self, fn_name, module.id(), &*global, pos).into())
} else {
None
};
if !f.is_pure() && !args.is_empty() && args[0].is_read_only() {
Err(ERR::ErrorNonPureMethodCallOnConstant(fn_name.to_string(), pos).into())
} else {

View File

@ -142,7 +142,8 @@ impl CallableFunction {
pub fn has_context(&self) -> bool {
match self {
Self::Pure(.., ctx) | Self::Method(.., ctx) => *ctx,
Self::Plugin(..) | Self::Iterator(..) => false,
Self::Plugin(f) => f.has_context(),
Self::Iterator(..) => false,
#[cfg(not(feature = "no_function"))]
Self::Script(..) => false,
}

View File

@ -24,12 +24,16 @@ pub use rhai_codegen::{export_fn, register_exported_fn};
/// Use the `#[export_module]` and `#[export_fn]` procedural attributes instead.
pub trait PluginFunction {
/// Call the plugin function with the arguments provided.
fn call(&self, context: NativeCallContext, args: &mut FnCallArgs) -> RhaiResult;
fn call(&self, context: Option<NativeCallContext>, args: &mut FnCallArgs) -> RhaiResult;
/// Is this plugin function a method?
#[must_use]
fn is_method_call(&self) -> bool;
/// Does this plugin function contain a [`NativeCallContext`] parameter?
#[must_use]
fn has_context(&self) -> bool;
/// Is this plugin function pure?
///
/// This defaults to `true` such that any old implementation that has constant-checking code