diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 75812dbd..2fca6d96 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -84,71 +84,91 @@ impl ExportedParams for ExportedFnParams { let mut skip = false; let mut special = FnSpecialAccess::None; for attr in attrs { - let crate::attrs::AttrItem { key, value, span: item_span } = attr; + let crate::attrs::AttrItem { + key, + value, + span: item_span, + } = attr; match (key.to_string().as_ref(), value) { ("get", None) | ("set", None) | ("name", None) => { return Err(syn::Error::new(key.span(), "requires value")) - }, + } ("name", Some(s)) if &s.value() == FN_IDX_GET => { - return Err(syn::Error::new(item_span, - "use attribute 'index_get' instead")) - }, + return Err(syn::Error::new( + item_span, + "use attribute 'index_get' instead", + )) + } ("name", Some(s)) if &s.value() == FN_IDX_SET => { - return Err(syn::Error::new(item_span, - "use attribute 'index_set' instead")) - }, + return Err(syn::Error::new( + item_span, + "use attribute 'index_set' instead", + )) + } ("name", Some(s)) if s.value().starts_with("get$") => { - return Err(syn::Error::new(item_span, - format!("use attribute 'getter = \"{}\"' instead", - &s.value()["get$".len()..]))) - }, + return Err(syn::Error::new( + item_span, + format!( + "use attribute 'getter = \"{}\"' instead", + &s.value()["get$".len()..] + ), + )) + } ("name", Some(s)) if s.value().starts_with("set$") => { - return Err(syn::Error::new(item_span, - format!("use attribute 'setter = \"{}\"' instead", - &s.value()["set$".len()..]))) - }, + return Err(syn::Error::new( + item_span, + format!( + "use attribute 'setter = \"{}\"' instead", + &s.value()["set$".len()..] + ), + )) + } ("name", Some(s)) if s.value().contains('$') => { - return Err(syn::Error::new(s.span(), - "Rhai function names may not contain dollar sign")) - }, + return Err(syn::Error::new( + s.span(), + "Rhai function names may not contain dollar sign", + )) + } ("name", Some(s)) if s.value().contains('.') => { - return Err(syn::Error::new(s.span(), - "Rhai function names may not contain dot")) - }, - ("name", Some(s)) => { - name.push(s.value()) - }, - ("set", Some(s)) => special = match special { - FnSpecialAccess::None => - FnSpecialAccess::Property(Property::Set(syn::Ident::new(&s.value(), - s.span()))), - _ => { - return Err(syn::Error::new(item_span.span(), "conflicting setter")) + return Err(syn::Error::new( + s.span(), + "Rhai function names may not contain dot", + )) + } + ("name", Some(s)) => name.push(s.value()), + ("set", Some(s)) => { + special = match special { + FnSpecialAccess::None => FnSpecialAccess::Property(Property::Set( + syn::Ident::new(&s.value(), s.span()), + )), + _ => return Err(syn::Error::new(item_span.span(), "conflicting setter")), } - }, - ("get", Some(s)) => special = match special { - FnSpecialAccess::None => - FnSpecialAccess::Property(Property::Get(syn::Ident::new(&s.value(), - s.span()))), - _ => { - return Err(syn::Error::new(item_span.span(), "conflicting getter")) + } + ("get", Some(s)) => { + special = match special { + FnSpecialAccess::None => FnSpecialAccess::Property(Property::Get( + syn::Ident::new(&s.value(), s.span()), + )), + _ => return Err(syn::Error::new(item_span.span(), "conflicting getter")), } - }, - ("index_get", None) => special = match special { - FnSpecialAccess::None => - FnSpecialAccess::Index(Index::Get), - _ => { - return Err(syn::Error::new(item_span.span(), "conflicting index_get")) + } + ("index_get", None) => { + special = match special { + FnSpecialAccess::None => FnSpecialAccess::Index(Index::Get), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting index_get")) + } } - }, + } - ("index_set", None) => special = match special { - FnSpecialAccess::None => - FnSpecialAccess::Index(Index::Set), - _ => { - return Err(syn::Error::new(item_span.span(), "conflicting index_set")) + ("index_set", None) => { + special = match special { + FnSpecialAccess::None => FnSpecialAccess::Index(Index::Set), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting index_set")) + } } - }, + } ("return_raw", None) => return_raw = true, ("index_get", Some(s)) | ("index_set", Some(s)) | ("return_raw", Some(s)) => { return Err(syn::Error::new(s.span(), "extraneous value")) @@ -327,26 +347,40 @@ impl ExportedFn { } pub(crate) fn exported_names(&self) -> Vec { - let mut literals = self.params.name.as_ref() - .map(|v| v.iter() - .map(|s| syn::LitStr::new(s, proc_macro2::Span::call_site())).collect()) + let mut literals = self + .params + .name + .as_ref() + .map(|v| { + v.iter() + .map(|s| syn::LitStr::new(s, proc_macro2::Span::call_site())) + .collect() + }) .unwrap_or_else(|| Vec::new()); match self.params.special { - FnSpecialAccess::None => {}, - FnSpecialAccess::Property(Property::Get(ref g)) => - literals.push(syn::LitStr::new(&format!("get${}", g.to_string()), g.span())), - FnSpecialAccess::Property(Property::Set(ref s)) => - literals.push(syn::LitStr::new(&format!("set${}", s.to_string()), s.span())), - FnSpecialAccess::Index(Index::Get) => - literals.push(syn::LitStr::new(FN_IDX_GET, proc_macro2::Span::call_site())), - FnSpecialAccess::Index(Index::Set) => - literals.push(syn::LitStr::new(FN_IDX_SET, proc_macro2::Span::call_site())), + FnSpecialAccess::None => {} + FnSpecialAccess::Property(Property::Get(ref g)) => literals.push(syn::LitStr::new( + &format!("get${}", g.to_string()), + g.span(), + )), + FnSpecialAccess::Property(Property::Set(ref s)) => literals.push(syn::LitStr::new( + &format!("set${}", s.to_string()), + s.span(), + )), + FnSpecialAccess::Index(Index::Get) => { + literals.push(syn::LitStr::new(FN_IDX_GET, proc_macro2::Span::call_site())) + } + FnSpecialAccess::Index(Index::Set) => { + literals.push(syn::LitStr::new(FN_IDX_SET, proc_macro2::Span::call_site())) + } } if literals.is_empty() { - literals.push(syn::LitStr::new(&self.signature.ident.to_string(), - self.signature.ident.span())); + literals.push(syn::LitStr::new( + &self.signature.ident.to_string(), + self.signature.ident.span(), + )); } literals @@ -394,53 +428,61 @@ impl ExportedFn { match params.special { // 2a. Property getters must take only the subject as an argument. - FnSpecialAccess::Property(Property::Get(_)) if self.arg_count() != 1 => + FnSpecialAccess::Property(Property::Get(_)) if self.arg_count() != 1 => { return Err(syn::Error::new( self.signature.span(), "property getter requires exactly 1 argument", - )), + )) + } // 2b. Property getters must return a value. - FnSpecialAccess::Property(Property::Get(_)) if self.return_type().is_none() => + FnSpecialAccess::Property(Property::Get(_)) if self.return_type().is_none() => { return Err(syn::Error::new( self.signature.span(), - "property getter must return a value" - )), + "property getter must return a value", + )) + } // 3a. Property setters must take the subject and a new value as arguments. - FnSpecialAccess::Property(Property::Set(_)) if self.arg_count() != 2 => + FnSpecialAccess::Property(Property::Set(_)) if self.arg_count() != 2 => { return Err(syn::Error::new( self.signature.span(), "property setter requires exactly 2 arguments", - )), + )) + } // 3b. Property setters must return nothing. - FnSpecialAccess::Property(Property::Set(_)) if self.return_type().is_some() => + FnSpecialAccess::Property(Property::Set(_)) if self.return_type().is_some() => { return Err(syn::Error::new( self.signature.span(), - "property setter must return no value" - )), + "property setter must return no value", + )) + } // 4a. Index getters must take the subject and the accessed "index" as arguments. - FnSpecialAccess::Index(Index::Get) if self.arg_count() != 2 => + FnSpecialAccess::Index(Index::Get) if self.arg_count() != 2 => { return Err(syn::Error::new( self.signature.span(), "index getter requires exactly 2 arguments", - )), + )) + } // 4b. Index getters must return a value. - FnSpecialAccess::Index(Index::Get) if self.return_type().is_none() => + FnSpecialAccess::Index(Index::Get) if self.return_type().is_none() => { return Err(syn::Error::new( self.signature.span(), - "index getter must return a value" - )), + "index getter must return a value", + )) + } // 5a. Index setters must take the subject, "index", and new value as arguments. - FnSpecialAccess::Index(Index::Set) if self.arg_count() != 3 => + FnSpecialAccess::Index(Index::Set) if self.arg_count() != 3 => { return Err(syn::Error::new( self.signature.span(), "index setter requires exactly 3 arguments", - )), + )) + } // 5b. Index setters must return nothing. - FnSpecialAccess::Index(Index::Set) if self.return_type().is_some() => + FnSpecialAccess::Index(Index::Set) if self.return_type().is_some() => { return Err(syn::Error::new( self.signature.span(), - "index setter must return no value" - )), + "index setter must return no value", + )) + } _ => {} } @@ -596,11 +638,13 @@ impl ExportedFn { // Handle the rest of the arguments, which all are passed by value. // // The only exception is strings, which need to be downcast to ImmutableString to enable a - // zero-copy conversion to &str by reference. + // zero-copy conversion to &str by reference, or a cloned String. let str_type_path = syn::parse2::(quote! { str }).unwrap(); + let string_type_path = syn::parse2::(quote! { String }).unwrap(); for (i, arg) in self.arg_list().enumerate().skip(skip_first_arg as usize) { let var = syn::Ident::new(&format!("arg{}", i), proc_macro2::Span::call_site()); - let is_str_ref; + let is_string; + let is_ref; match arg { syn::FnArg::Typed(pattern) => { let arg_type: &syn::Type = pattern.ty.as_ref(); @@ -611,15 +655,22 @@ impl ExportedFn { .. }) => match elem.as_ref() { &syn::Type::Path(ref p) if p.path == str_type_path => { - is_str_ref = true; + is_string = true; + is_ref = true; quote_spanned!(arg_type.span()=> - mem::take(args[#i]) - .clone().cast::()) + mem::take(args[#i]).take_immutable_string().unwrap()) } _ => panic!("internal error: why wasn't this found earlier!?"), }, + &syn::Type::Path(ref p) if p.path == string_type_path => { + is_string = true; + is_ref = false; + quote_spanned!(arg_type.span()=> + mem::take(args[#i]).take_string().unwrap()) + } _ => { - is_str_ref = false; + is_string = false; + is_ref = false; quote_spanned!(arg_type.span()=> mem::take(args[#i]).clone().cast::<#arg_type>()) } @@ -631,7 +682,7 @@ impl ExportedFn { }) .unwrap(), ); - if !is_str_ref { + if !is_string { input_type_exprs.push( syn::parse2::(quote_spanned!( arg_type.span()=> TypeId::of::<#arg_type>() @@ -649,7 +700,7 @@ impl ExportedFn { } syn::FnArg::Receiver(_) => panic!("internal error: how did this happen!?"), } - if !is_str_ref { + if !is_ref { unpack_exprs.push(syn::parse2::(quote! { #var }).unwrap()); } else { unpack_exprs.push(syn::parse2::(quote! { &#var }).unwrap()); @@ -685,7 +736,7 @@ impl ExportedFn { quote! { impl PluginFunction for #type_name { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), #arg_count, "wrong arg count: {} != {}", diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index 1859ba42..c25c9484 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -19,6 +19,7 @@ pub(crate) fn generate_body( let mut add_mod_blocks: Vec = Vec::new(); let mut set_flattened_mod_blocks: Vec = Vec::new(); let str_type_path = syn::parse2::(quote! { str }).unwrap(); + let string_type_path = syn::parse2::(quote! { String }).unwrap(); for (const_name, _, _) in consts { let const_literal = syn::LitStr::new(&const_name, proc_macro2::Span::call_site()); @@ -97,6 +98,11 @@ pub(crate) fn generate_body( } _ => panic!("internal error: non-string shared reference!?"), }, + syn::Type::Path(ref p) if p.path == string_type_path => { + syn::parse2::(quote! { + ImmutableString }) + .unwrap() + } syn::Type::Reference(syn::TypeReference { mutability: Some(_), ref elem, diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index a4a54959..f22f1fe2 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -245,9 +245,7 @@ mod generate_tests { false } }); - eprintln!("actual != expected, diverge at char {}", counter); - /* - let (actual_diff, expected_diff) = { + let (_actual_diff, _expected_diff) = { let mut actual_diff = String::new(); let mut expected_diff = String::new(); for (a, e) in _iter.take(50) { @@ -256,10 +254,10 @@ mod generate_tests { } (actual_diff, expected_diff) }; - eprintln!(" actual: {}", actual_diff); - eprintln!("expected: {}", expected_diff); - assert!(false); - */ + eprintln!("actual != expected, diverge at char {}", counter); + // eprintln!(" actual: {}", _actual_diff); + // eprintln!("expected: {}", _expected_diff); + // assert!(false); } assert_eq!(actual, expected); } @@ -277,7 +275,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); @@ -321,7 +319,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -362,7 +360,7 @@ mod generate_tests { let expected_tokens = quote! { impl PluginFunction for MyType { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -396,7 +394,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -443,7 +441,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -491,11 +489,11 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); - let arg0 = mem::take(args[0usize]).clone().cast::(); + let arg0 = mem::take(args[0usize]).take_immutable_string().unwrap(); Ok(Dynamic::from(special_print(&arg0))) } diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index b560e94b..80a93f28 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -226,9 +226,7 @@ mod generate_tests { false } }); - eprintln!("actual != expected, diverge at char {}", counter); - /* - let (actual_diff, expected_diff) = { + let (_actual_diff, _expected_diff) = { let mut actual_diff = String::new(); let mut expected_diff = String::new(); for (a, e) in _iter.take(50) { @@ -237,10 +235,10 @@ mod generate_tests { } (actual_diff, expected_diff) }; - eprintln!(" actual: {}", actual_diff); - eprintln!("expected: {}", expected_diff); - assert!(false); - */ + eprintln!("actual != expected, diverge at char {}", counter); + // eprintln!(" actual: {}", _actual_diff); + // eprintln!("expected: {}", _expected_diff); + // assert!(false); } assert_eq!(actual, expected); } @@ -305,7 +303,7 @@ mod generate_tests { struct get_mystic_number_token(); impl PluginFunction for get_mystic_number_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); @@ -367,7 +365,7 @@ mod generate_tests { struct add_one_to_token(); impl PluginFunction for add_one_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -444,7 +442,7 @@ mod generate_tests { struct add_one_to_token(); impl PluginFunction for add_one_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -472,7 +470,7 @@ mod generate_tests { struct add_n_to_token(); impl PluginFunction for add_n_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -538,7 +536,7 @@ mod generate_tests { struct add_together_token(); impl PluginFunction for add_together_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -611,7 +609,7 @@ mod generate_tests { struct add_together_token(); impl PluginFunction for add_together_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -853,7 +851,7 @@ mod generate_tests { struct get_mystic_number_token(); impl PluginFunction for get_mystic_number_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); @@ -946,11 +944,11 @@ mod generate_tests { struct print_out_to_token(); impl PluginFunction for print_out_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); - let arg0 = mem::take(args[0usize]).clone().cast::(); + let arg0 = mem::take(args[0usize]).take_immutable_string().unwrap(); Ok(Dynamic::from(print_out_to(&arg0))) } @@ -976,6 +974,70 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_string_arg_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod str_fn { + pub fn print_out_to(x: String) { + x + 1 + } + } + }; + + let expected_tokens = quote! { + pub mod str_fn { + pub fn print_out_to(x: String) { + x + 1 + } + #[allow(unused_imports)] + use super::*; + + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + rhai_generate_into_module(&mut m, false); + m + } + #[allow(unused_mut)] + pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { + m.set_fn("print_out_to", FnAccess::Public, + &[core::any::TypeId::of::()], + CallableFunction::from_plugin(print_out_to_token())); + if flatten {} else {} + } + #[allow(non_camel_case_types)] + struct print_out_to_token(); + impl PluginFunction for print_out_to_token { + fn call(&self, + args: &mut [&mut Dynamic] + ) -> Result> { + debug_assert_eq!(args.len(), 1usize, + "wrong arg count: {} != {}", args.len(), 1usize); + let arg0 = mem::take(args[0usize]).take_string().unwrap(); + Ok(Dynamic::from(print_out_to(arg0))) + } + + fn is_method_call(&self) -> bool { false } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(print_out_to_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::()].into_boxed_slice() + } + } + pub fn print_out_to_token_callable() -> CallableFunction { + CallableFunction::from_plugin(print_out_to_token()) + } + pub fn print_out_to_token_input_types() -> Box<[TypeId]> { + print_out_to_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_mut_ref_fn_module() { let input_tokens: TokenStream = quote! { @@ -1010,7 +1072,7 @@ mod generate_tests { struct increment_token(); impl PluginFunction for increment_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1077,7 +1139,7 @@ mod generate_tests { struct increment_token(); impl PluginFunction for increment_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1164,7 +1226,7 @@ mod generate_tests { struct increment_token(); impl PluginFunction for increment_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1249,7 +1311,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1315,7 +1377,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1381,7 +1443,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1452,7 +1514,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1519,7 +1581,7 @@ mod generate_tests { struct get_by_index_token(); impl PluginFunction for get_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1591,7 +1653,7 @@ mod generate_tests { struct get_by_index_token(); impl PluginFunction for get_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1660,7 +1722,7 @@ mod generate_tests { struct set_by_index_token(); impl PluginFunction for set_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 3usize, "wrong arg count: {} != {}", args.len(), 3usize); @@ -1736,7 +1798,7 @@ mod generate_tests { struct set_by_index_token(); impl PluginFunction for set_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 3usize, "wrong arg count: {} != {}", args.len(), 3usize); diff --git a/src/any.rs b/src/any.rs index 7b1fa184..a1e532aa 100644 --- a/src/any.rs +++ b/src/any.rs @@ -1136,6 +1136,7 @@ impl Dynamic { } /// Convert the `Dynamic` into `String` and return it. + /// If there are other references to the same string, a cloned copy is returned. /// Returns the name of the actual type if the cast fails. #[inline(always)] pub fn take_string(self) -> Result { @@ -1145,7 +1146,8 @@ impl Dynamic { /// Convert the `Dynamic` into `ImmutableString` and return it. /// Returns the name of the actual type if the cast fails. - pub(crate) fn take_immutable_string(self) -> Result { + #[inline] + pub fn take_immutable_string(self) -> Result { match self.0 { Union::Str(s) => Ok(s), Union::FnPtr(f) => Ok(f.take_data().0), diff --git a/src/fn_call.rs b/src/fn_call.rs index 3728d4e8..c40d352f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -232,7 +232,7 @@ impl Engine { // Run external function let result = if func.is_plugin_fn() { - func.get_plugin_fn().call(args, Position::none()) + func.get_plugin_fn().call(args) } else { func.get_native_fn()(self, lib, args) }; @@ -1099,7 +1099,7 @@ impl Engine { self.call_script_fn(scope, mods, state, lib, &mut None, name, func, args, level) } - Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut(), Position::none()), + Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut()), Some(f) if f.is_native() => { if !f.is_method() { // Clone first argument diff --git a/src/fn_register.rs b/src/fn_register.rs index 28d33198..12aedad2 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -46,7 +46,7 @@ pub trait RegisterPlugin { /// fn is_method_call(&self) -> bool { false } /// fn is_varadic(&self) -> bool { false } /// - /// fn call(&self, args: &mut[&mut Dynamic], pos: Position) -> Result> { + /// fn call(&self, args: &mut[&mut Dynamic]) -> Result> { /// let x1: NUMBER = std::mem::take(args[0]).clone().cast::(); /// let y1: NUMBER = std::mem::take(args[1]).clone().cast::(); /// let x2: NUMBER = std::mem::take(args[2]).clone().cast::(); diff --git a/src/plugin.rs b/src/plugin.rs index ef4a6590..e6e4e956 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -3,7 +3,7 @@ pub use crate::{ fn_native::CallableFunction, stdlib::any::TypeId, stdlib::boxed::Box, stdlib::format, stdlib::mem, stdlib::string::ToString, stdlib::vec as new_vec, stdlib::vec::Vec, Dynamic, - Engine, EvalAltResult, FnAccess, ImmutableString, Module, Position, RegisterResultFn, + Engine, EvalAltResult, FnAccess, ImmutableString, Module, RegisterResultFn, }; #[cfg(not(features = "no_module"))] @@ -34,8 +34,7 @@ pub trait PluginFunction { fn is_method_call(&self) -> bool; fn is_varadic(&self) -> bool; - fn call(&self, args: &mut [&mut Dynamic], pos: Position) - -> Result>; + fn call(&self, args: &mut [&mut Dynamic]) -> Result>; fn clone_boxed(&self) -> Box; diff --git a/tests/plugins.rs b/tests/plugins.rs index 2bee84e4..909ad51b 100644 --- a/tests/plugins.rs +++ b/tests/plugins.rs @@ -24,6 +24,13 @@ mod test { } } + pub fn hash(_text: String) -> INT { + 42 + } + pub fn hash2(_text: &str) -> INT { + 42 + } + #[rhai_fn(name = "test", name = "hi")] #[inline(always)] pub fn len(array: &mut Array, mul: INT) -> INT { @@ -77,6 +84,8 @@ fn test_plugins_package() -> Result<(), Box> { #[cfg(not(feature = "no_object"))] assert_eq!(engine.eval::("let a = [1, 2, 3]; a.foo")?, 1); + assert_eq!(engine.eval::(r#"hash("hello")"#)?, 42); + assert_eq!(engine.eval::(r#"hash2("hello")"#)?, 42); assert_eq!(engine.eval::("let a = [1, 2, 3]; test(a, 2)")?, 6); assert_eq!(engine.eval::("let a = [1, 2, 3]; hi(a, 2)")?, 6); assert_eq!(engine.eval::("let a = [1, 2, 3]; test(a, 2)")?, 6);