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. * `Module::with_capacity` is deprecated.
* The internal method `Engine::eval_statements_raw` 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 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 } num-traits = { version = "0.2", default-features = false }
bitflags = { version = "1", default-features = false } bitflags = { version = "1", default-features = false }
smartstring = { 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 } no-std-compat = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
libm = { version = "0.2", default-features = false, optional = true } libm = { version = "0.2", default-features = false, optional = true }

View File

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

View File

@ -674,6 +674,7 @@ impl ExportedFn {
let arg_count = self.arg_count(); let arg_count = self.arg_count();
let is_method_call = self.mutable_receiver(); let is_method_call = self.mutable_receiver();
let is_pure = !self.mutable_receiver() || self.params().pure.is_some(); 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_statements = Vec::new();
let mut unpack_exprs = Vec::new(); let mut unpack_exprs = Vec::new();
@ -689,7 +690,7 @@ impl ExportedFn {
let skip_first_arg; let skip_first_arg;
if self.pass_context { 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 // Handle the first argument separately if the function has a "method like" receiver
@ -860,13 +861,14 @@ impl ExportedFn {
#(#cfg_attrs)* #(#cfg_attrs)*
impl PluginFunction for #type_name { impl PluginFunction for #type_name {
#[inline(always)] #[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)* #(#unpack_statements)*
#return_expr #return_expr
} }
#[inline(always)] fn is_method_call(&self) -> bool { #is_method_call } #[inline(always)] fn is_method_call(&self) -> bool { #is_method_call }
#[inline(always)] fn is_pure(&self) -> bool { #is_pure } #[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] { [] } #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] }
} }
impl PluginFunction for Token { 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())) Ok(Dynamic::from(do_nothing()))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
} }
#[allow(unused)] #[allow(unused)]
#[doc(hidden)] #[doc(hidden)]
@ -318,13 +319,14 @@ mod generate_tests {
} }
impl PluginFunction for Token { impl PluginFunction for Token {
#[inline(always)] #[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 arg0 = mem::take(args[0usize]).cast::<usize>();
Ok(Dynamic::from(do_something(arg0))) Ok(Dynamic::from(do_something(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
} }
#[allow(unused)] #[allow(unused)]
#[doc(hidden)] #[doc(hidden)]
@ -357,13 +359,14 @@ mod generate_tests {
} }
impl PluginFunction for Token { impl PluginFunction for Token {
#[inline(always)] #[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 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_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { true }
} }
#[allow(unused)] #[allow(unused)]
#[doc(hidden)] #[doc(hidden)]
@ -399,12 +402,13 @@ mod generate_tests {
} }
impl PluginFunction for Token { impl PluginFunction for Token {
#[inline(always)] #[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())) Ok(Dynamic::from(return_dynamic()))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
} }
#[allow(unused)] #[allow(unused)]
#[doc(hidden)] #[doc(hidden)]
@ -432,13 +436,14 @@ mod generate_tests {
} }
impl PluginFunction for TestStruct { impl PluginFunction for TestStruct {
#[inline(always)] #[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 arg0 = mem::take(args[0usize]).cast::<usize>();
Ok(Dynamic::from(do_something(arg0))) Ok(Dynamic::from(do_something(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for Token {
#[inline(always)] #[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 arg0 = mem::take(args[0usize]).cast::<usize>();
let arg1 = mem::take(args[1usize]).cast::<usize>(); let arg1 = mem::take(args[1usize]).cast::<usize>();
Ok(Dynamic::from(add_together(arg0, arg1))) 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_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
} }
#[allow(unused)] #[allow(unused)]
#[doc(hidden)] #[doc(hidden)]
@ -505,7 +511,7 @@ mod generate_tests {
} }
impl PluginFunction for Token { impl PluginFunction for Token {
#[inline(always)] #[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 arg1 = mem::take(args[1usize]).cast::<usize>();
let arg0 = &mut args[0usize].write_lock::<usize>().unwrap(); let arg0 = &mut args[0usize].write_lock::<usize>().unwrap();
Ok(Dynamic::from(increment(arg0, arg1))) 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_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
} }
#[allow(unused)] #[allow(unused)]
#[doc(hidden)] #[doc(hidden)]
@ -546,13 +553,14 @@ mod generate_tests {
} }
impl PluginFunction for Token { impl PluginFunction for Token {
#[inline(always)] #[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(); let arg0 = mem::take(args[0usize]).into_immutable_string().unwrap();
Ok(Dynamic::from(special_print(&arg0))) Ok(Dynamic::from(special_print(&arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
} }
#[allow(unused)] #[allow(unused)]
#[doc(hidden)] #[doc(hidden)]

View File

@ -386,12 +386,13 @@ mod generate_tests {
} }
impl PluginFunction for get_mystic_number_token { impl PluginFunction for get_mystic_number_token {
#[inline(always)] #[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())) Ok(Dynamic::from(get_mystic_number()))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for get_mystic_number_token {
#[inline(always)] #[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())) Ok(Dynamic::from(get_mystic_number()))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for add_one_to_token {
#[inline(always)] #[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 arg0 = mem::take(args[0usize]).cast::<INT>();
Ok(Dynamic::from(add_one_to(arg0))) Ok(Dynamic::from(add_one_to(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for add_one_to_token {
#[inline(always)] #[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 arg0 = mem::take(args[0usize]).cast::<INT>();
Ok(Dynamic::from(add_one_to(arg0))) Ok(Dynamic::from(add_one_to(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for add_one_to_token {
#[inline(always)] #[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 arg0 = mem::take(args[0usize]).cast::<INT>();
Ok(Dynamic::from(add_one_to(arg0))) Ok(Dynamic::from(add_one_to(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { true }
#[inline(always)] fn has_context(&self) -> bool { false }
} }
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -681,7 +686,7 @@ mod generate_tests {
} }
impl PluginFunction for add_n_to_token { impl PluginFunction for add_n_to_token {
#[inline(always)] #[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 arg0 = mem::take(args[0usize]).cast::<INT>();
let arg1 = mem::take(args[1usize]).cast::<INT>(); let arg1 = mem::take(args[1usize]).cast::<INT>();
Ok(Dynamic::from(add_n_to(arg0, arg1))) 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_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for add_together_token {
#[inline(always)] #[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 arg0 = mem::take(args[0usize]).cast::<INT>();
let arg1 = mem::take(args[1usize]).cast::<INT>(); let arg1 = mem::take(args[1usize]).cast::<INT>();
Ok(Dynamic::from(add_together(arg0, arg1))) 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_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for add_together_token {
#[inline(always)] #[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 arg0 = mem::take(args[0usize]).cast::<INT>();
let arg1 = mem::take(args[1usize]).cast::<INT>(); let arg1 = mem::take(args[1usize]).cast::<INT>();
Ok(Dynamic::from(add_together(arg0, arg1))) 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_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for get_mystic_number_token {
#[inline(always)] #[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(); let arg0 = &mut args[0usize].write_lock::<Hello>().unwrap();
Ok(Dynamic::from(get_mystic_number(arg0))) Ok(Dynamic::from(get_mystic_number(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 { impl PluginFunction for get_mystic_number_token {
#[inline(always)] #[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())) Ok(Dynamic::from(get_mystic_number()))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for print_out_to_token {
#[inline(always)] #[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(); let arg0 = mem::take(args[0usize]).into_immutable_string().unwrap();
Ok(Dynamic::from(print_out_to(&arg0))) Ok(Dynamic::from(print_out_to(&arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for print_out_to_token {
#[inline(always)] #[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(); let arg0 = mem::take(args[0usize]).into_string().unwrap();
Ok(Dynamic::from(print_out_to(arg0))) Ok(Dynamic::from(print_out_to(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_method_call(&self) -> bool { false }
#[inline(always)] fn is_pure(&self) -> bool { true } #[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 { impl PluginFunction for foo_token {
#[inline(always)] #[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 arg1 = mem::take(args[1usize]).cast::<INT>();
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap(); let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
Ok(Dynamic::from(foo(arg0, arg1))) 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_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&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 { impl PluginFunction for increment_token {
#[inline(always)] #[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(); let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
Ok(Dynamic::from(increment(arg0))) Ok(Dynamic::from(increment(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 { impl PluginFunction for increment_token {
#[inline(always)] #[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(); let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
Ok(Dynamic::from(increment(arg0))) Ok(Dynamic::from(increment(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
} }
} }
#[allow(unused_imports)] #[allow(unused_imports)]
@ -1503,13 +1518,14 @@ mod generate_tests {
} }
impl PluginFunction for increment_token { impl PluginFunction for increment_token {
#[inline(always)] #[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(); let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
Ok(Dynamic::from(increment(arg0))) Ok(Dynamic::from(increment(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { false }
#[inline(always)] fn has_context(&self) -> bool { false }
} }
} }
#[allow(unused_imports)] #[allow(unused_imports)]
@ -1588,13 +1604,14 @@ mod generate_tests {
} }
impl PluginFunction for int_foo_token { impl PluginFunction for int_foo_token {
#[inline(always)] #[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(); let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0))) Ok(Dynamic::from(int_foo(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 { impl PluginFunction for int_foo_token {
#[inline(always)] #[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(); let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0))) Ok(Dynamic::from(int_foo(arg0)))
} }
#[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 { impl PluginFunction for int_foo_token {
#[inline(always)] #[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 arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap(); let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0, arg1))) 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_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 { impl PluginFunction for int_foo_token {
#[inline(always)] #[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 arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap(); let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0, arg1))) 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_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 { impl PluginFunction for get_by_index_token {
#[inline(always)] #[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 arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap(); let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(get_by_index(arg0, arg1))) 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_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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)] #[cfg(hello)]
impl PluginFunction for get_by_index_token { impl PluginFunction for get_by_index_token {
#[inline(always)] #[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 arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap(); let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(get_by_index(arg0, arg1))) 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_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 { impl PluginFunction for get_by_index_token {
#[inline(always)] #[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 arg1 = mem::take(args[1usize]).cast::<u64>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap(); let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(get_by_index(arg0, arg1))) 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_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 { impl PluginFunction for set_by_index_token {
#[inline(always)] #[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 arg1 = mem::take(args[1usize]).cast::<u64>();
let arg2 = mem::take(args[2usize]).cast::<FLOAT>(); let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap(); 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_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 { impl PluginFunction for set_by_index_token {
#[inline(always)] #[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 arg1 = mem::take(args[1usize]).cast::<u64>();
let arg2 = mem::take(args[2usize]).cast::<FLOAT>(); let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap(); 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_method_call(&self) -> bool { true }
#[inline(always)] fn is_pure(&self) -> bool { false } #[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 is_method = func.is_method();
let src = source.as_ref().map(|s| s.as_str()); 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() { let context = if func.has_context() {
Some((self, name, src, &*global, pos).into()) Some((self, name, src, &*global, pos).into())
} else { } else {
None 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) f(context, args)
} else { } else {
unreachable!(); unreachable!();
@ -1390,8 +1390,12 @@ impl Engine {
} }
Some(f) if f.is_plugin_fn() => { 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 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() { if !f.is_pure() && !args.is_empty() && args[0].is_read_only() {
Err(ERR::ErrorNonPureMethodCallOnConstant(fn_name.to_string(), pos).into()) Err(ERR::ErrorNonPureMethodCallOnConstant(fn_name.to_string(), pos).into())
} else { } else {

View File

@ -142,7 +142,8 @@ impl CallableFunction {
pub fn has_context(&self) -> bool { pub fn has_context(&self) -> bool {
match self { match self {
Self::Pure(.., ctx) | Self::Method(.., ctx) => *ctx, 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"))] #[cfg(not(feature = "no_function"))]
Self::Script(..) => false, 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. /// Use the `#[export_module]` and `#[export_fn]` procedural attributes instead.
pub trait PluginFunction { pub trait PluginFunction {
/// Call the plugin function with the arguments provided. /// 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? /// Is this plugin function a method?
#[must_use] #[must_use]
fn is_method_call(&self) -> bool; 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? /// Is this plugin function pure?
/// ///
/// This defaults to `true` such that any old implementation that has constant-checking code /// This defaults to `true` such that any old implementation that has constant-checking code