From 65a4ceb3be68f6e8735ed53ad60d701932b462d6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 30 Nov 2020 00:52:21 +0800 Subject: [PATCH 1/3] Getters/setters and indexers in a plugin module are default global. --- RELEASES.md | 10 +++++ codegen/src/rhai_module.rs | 28 ++++++++++--- codegen/src/test/module.rs | 4 +- doc/src/patterns/enums.md | 6 +-- doc/src/patterns/events.md | 80 +++++++++++++++++++++++--------------- doc/src/plugins/module.md | 3 ++ 6 files changed, 88 insertions(+), 43 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 1db01fd5..70c7d183 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -4,6 +4,16 @@ Rhai Release Notes Version 0.19.7 ============== +Bug fixes +--------- + +* Fixes compilation errors with certain feature flag combinations. + +Enhancements +------------ + +* Property getters/setters and indexers defined in a plugin module are by default `#[rhai_fn(global)]`. + Version 0.19.6 ============== diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index caef2ba2..b1e26691 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -4,7 +4,8 @@ use quote::{quote, ToTokens}; use crate::attrs::ExportScope; use crate::function::{ - flatten_type_groups, print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess, + flatten_type_groups, print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess, FN_GET, + FN_IDX_GET, FN_IDX_SET, FN_SET, }; use crate::module::Module; @@ -81,7 +82,6 @@ pub(crate) fn generate_body( function.name().span(), ); let reg_names = function.exported_names(); - let mut namespace = FnNamespaceAccess::Internal; let fn_input_names: Vec = function .arg_list() @@ -141,11 +141,27 @@ pub(crate) fn generate_body( .map(print_type) .unwrap_or_else(|| "()".to_string()); - if let Some(ns) = function.params().namespace { - namespace = ns; - } - for fn_literal in reg_names { + let mut namespace = FnNamespaceAccess::Internal; + + match function.params().special { + FnSpecialAccess::None => {} + FnSpecialAccess::Index(_) | FnSpecialAccess::Property(_) => { + let reg_name = fn_literal.value(); + if reg_name.starts_with(FN_GET) + || reg_name.starts_with(FN_SET) + || reg_name == FN_IDX_GET + || reg_name == FN_IDX_SET + { + namespace = FnNamespaceAccess::Global; + } + } + } + + if let Some(ns) = function.params().namespace { + namespace = ns; + } + let ns_str = syn::Ident::new( match namespace { FnNamespaceAccess::Global => "Global", diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 8c6bdd50..c586f0a1 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -1519,7 +1519,7 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "u64"]), + m.set_fn("get$square", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut u64", "u64"]), &[core::any::TypeId::of::()], int_foo_token().into()); if flatten {} else {} @@ -1597,7 +1597,7 @@ mod generate_tests { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "u64"]), &[core::any::TypeId::of::()], int_foo_token().into()); - m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "u64"]), &[core::any::TypeId::of::()], + m.set_fn("get$square", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut u64", "u64"]), &[core::any::TypeId::of::()], int_foo_token().into()); if flatten {} else {} } diff --git a/doc/src/patterns/enums.md b/doc/src/patterns/enums.md index 86f3504e..1d693564 100644 --- a/doc/src/patterns/enums.md +++ b/doc/src/patterns/enums.md @@ -37,7 +37,7 @@ mod MyEnumModule { MyEnum::Baz(val1, val2) } // Access to fields - #[rhai_fn(global, get = "enum_type")] + #[rhai_fn(get = "enum_type")] pub fn get_type(a: &mut MyEnum) -> String { match a { MyEnum::Foo => "Foo".to_string(), @@ -45,7 +45,7 @@ mod MyEnumModule { MyEnum::Baz(_, _) => "Baz".to_string() } } - #[rhai_fn(global, get = "field_0")] + #[rhai_fn(get = "field_0")] pub fn get_field_0(a: &mut MyEnum) -> Dynamic { match a { MyEnum::Foo => Dynamic::UNIT, @@ -53,7 +53,7 @@ mod MyEnumModule { MyEnum::Baz(x, _) => Dynamic::from(x) } } - #[rhai_fn(global, get = "field_1")] + #[rhai_fn(get = "field_1")] pub fn get_field_1(a: &mut MyEnum) -> Dynamic { match a { MyEnum::Foo | MyEnum::Bar(_) => Dynamic::UNIT, diff --git a/doc/src/patterns/events.md b/doc/src/patterns/events.md index 0312e42e..cdea89c5 100644 --- a/doc/src/patterns/events.md +++ b/doc/src/patterns/events.md @@ -54,6 +54,33 @@ struct Handler { } ``` +### Register API for Any Custom Type + +[Custom types] are often used to hold state. The easiest way to register an entire API is via a [plugin module]. + +```rust +use rhai::plugin::*; + +// A custom type to a hold state value. +#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] +pub struct SomeType { + data: i64; +} + +#[export_module] +mod SomeTypeAPI { + #[rhai_fn(global)] + pub func1(obj: &mut SomeType) -> bool { ... } + #[rhai_fn(global)] + pub func2(obj: &mut SomeType) -> bool { ... } + pub process(data: i64) -> i64 { ... } + #[rhai_fn(get = "value")] + pub get_value(obj: &mut SomeType) -> i64 { obj.data } + #[rhai_fn(set = "value")] + pub set_value(obj: &mut SomeType, value: i64) { obj.data = value; } +} +``` + ### Initialize Handler Object Steps to initialize the event handler: @@ -70,16 +97,10 @@ impl Handler { pub new(path: impl Into) -> Self { let mut engine = Engine::new(); - // Register API functions here + // Register custom types and API's engine - .register_fn("func1", func1) - .register_fn("func2", func2) - .register_fn("func3", func3) .register_type_with_name::("SomeType") - .register_get_set("value", - |obj: &mut SomeType| obj.data, - |obj: &mut SomeType, value: i64| obj.data = value - ); + .load_package(exported_module!(SomeTypeAPI)); // Create a custom 'Scope' to hold state let mut scope = Scope::new(); @@ -112,36 +133,30 @@ Mapping an event from the system into a scripted handler is straight-forward: impl Handler { // Say there are three events: 'start', 'end', 'update'. // In a real application you'd be handling errors... - pub fn on_event(&mut self, event_name: &str, event_data: i64) { + pub fn on_event(&mut self, event_name: &str, event_data: i64) -> Result<(), Error> { match event_name { // The 'start' event maps to function 'start'. // In a real application you'd be handling errors... - "start" => - self.engine - .call_fn(&mut self.scope, &self.ast, "start", (event_data,)).unwrap(), + "start" => self.engine.call_fn(&mut self.scope, &self.ast, "start", (event_data,))?, // The 'end' event maps to function 'end'. // In a real application you'd be handling errors... - "end" => - self.engine - .call_fn(&mut self.scope, &self.ast, "end", (event_data,)).unwrap(), + "end" => self.engine.call_fn(&mut self.scope, &self.ast, "end", (event_data,))?, // The 'update' event maps to function 'update'. // This event provides a default implementation when the scripted function // is not found. - "update" => - self.engine - .call_fn(&mut self.scope, &self.ast, "update", (event_data,)) - .or_else(|err| match *err { - EvalAltResult::ErrorFunctionNotFound(fn_name, _) if fn_name == "update" => { - // Default implementation of 'update' event handler - self.scope.set_value("state2", SomeType::new(42)); - // Turn function-not-found into a success - Ok(Dynamic::UNIT) - } - _ => Err(err.into()) - }) - .unwrap() + "update" => self.engine + .call_fn(&mut self.scope, &self.ast, "update", (event_data,)) + .or_else(|err| match *err { + EvalAltResult::ErrorFunctionNotFound(fn_name, _) if fn_name == "update" => { + // Default implementation of 'update' event handler + self.scope.set_value("state2", SomeType::new(42)); + // Turn function-not-found into a success + Ok(Dynamic::UNIT) + } + _ => Err(err.into()) + })? } } } @@ -159,24 +174,25 @@ fn start(data) { if state1 { throw "Already started!"; } - if func1(state2) || func2() { + if state2.func1() || state2.func2() { throw "Conditions not yet ready to start!"; } state1 = true; - state2.value = 0; + state2.value = data; } fn end(data) { if !state1 { throw "Not yet started!"; } - if func1(state2) || func2() { + if state2.func1() || state2.func2() { throw "Conditions not yet ready to start!"; } state1 = false; + state2.value = data; } fn update(data) { - state2.value += func3(data); + state2.value += process(data); } ``` diff --git a/doc/src/plugins/module.md b/doc/src/plugins/module.md index cbeb304d..a1e2a684 100644 --- a/doc/src/plugins/module.md +++ b/doc/src/plugins/module.md @@ -166,6 +166,9 @@ as well as all _type iterators_, are automatically exposed to the _global_ names [iteration]({{rootUrl}}/language/for.md), [getters/setters] and [indexers] for [custom types] can work as expected. +In fact, the default for all [getters/setters] and [indexers] defined in a plugin module +is `#[rhai_fn(global)]` unless specifically overridden by `#[rhai_fn(internal)]`. + Therefore, in the example above, the `increment` method (defined with `#[rhai_fn(global)]`) works fine when called in method-call style: From 1004bca5b5f670a3d7fec88f221208b261313baa Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 30 Nov 2020 11:20:51 +0800 Subject: [PATCH 2/3] Print arrays and maps with to_debug. --- RELEASES.md | 2 + doc/src/language/values-and-types.md | 2 + doc/src/patterns/enums.md | 2 +- doc/src/rust/print-custom.md | 1 + src/fn_native.rs | 4 +- src/packages/array_basic.rs | 2 +- src/packages/map_basic.rs | 2 +- src/packages/string_basic.rs | 69 ++++++++++++++++++++++------ tests/print.rs | 48 ++++++++++++++++++- 9 files changed, 113 insertions(+), 19 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 70c7d183..65f943c1 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,6 +13,8 @@ Enhancements ------------ * Property getters/setters and indexers defined in a plugin module are by default `#[rhai_fn(global)]`. +* `to_debug` is a new standard function for converting a value into debug format. +* Arrays and object maps now print values using `to_debug` (if available). Version 0.19.6 diff --git a/doc/src/language/values-and-types.md b/doc/src/language/values-and-types.md index c8fe9181..fbae2013 100644 --- a/doc/src/language/values-and-types.md +++ b/doc/src/language/values-and-types.md @@ -38,3 +38,5 @@ is an alias to `Rc` or `Arc` (depending on the [`sync`] feature) Any modification done to a Rhai string will cause the string to be cloned and the modifications made to the copy. The `to_string` function converts a standard type into a [string] for display purposes. + +The `to_debug` function converts a standard type into a [string] in debug format. diff --git a/doc/src/patterns/enums.md b/doc/src/patterns/enums.md index 1d693564..a4c9bc0b 100644 --- a/doc/src/patterns/enums.md +++ b/doc/src/patterns/enums.md @@ -61,7 +61,7 @@ mod MyEnumModule { } } // Printing - #[rhai(global, name = "to_string", name = "print", name = "debug")] + #[rhai(global, name = "to_string", name = "print", name = "to_debug", name = "debug")] pub fn to_string(a: &mut MyEnum) -> String { format!("{:?}", a)) } diff --git a/doc/src/rust/print-custom.md b/doc/src/rust/print-custom.md index 028a3519..c013559b 100644 --- a/doc/src/rust/print-custom.md +++ b/doc/src/rust/print-custom.md @@ -11,6 +11,7 @@ is `T: Display + Debug`): | ----------- | ---------------------------------------------- | ---------------------------- | -------------------------------------------------------------------- | | `to_string` | \|x: &mut T\| -> String | `x.to_string()` | converts the custom type into a [string] | | `print` | \|x: &mut T\| -> String | `x.to_string()` | converts the custom type into a [string] for the [`print`] statement | +| `to_debug` | \|x: &mut T\| -> String | `format!("{:?}", x)` | converts the custom type into a [string] in debug format | | `debug` | \|x: &mut T\| -> String | `format!("{:?}", x)` | converts the custom type into a [string] for the [`debug`] statement | | `+` | \|s: &str, x: T\| -> String | `format!("{}{}", s, x)` | concatenates the custom type with another [string] | | `+` | \|x: &mut T, s: &str\| -> String | `x.to_string().push_str(s);` | concatenates another [string] with the custom type | diff --git a/src/fn_native.rs b/src/fn_native.rs index b86063eb..ee87de84 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -134,7 +134,7 @@ impl<'e, 'a, 'm, 'pm> NativeCallContext<'e, 'a, 'm, 'pm> { /// If `is_method` is [`true`], the first argument is assumed to be passed /// by reference and is not consumed. pub fn call_fn_dynamic_raw( - &mut self, + &self, fn_name: &str, is_method: bool, public_only: bool, @@ -262,7 +262,7 @@ impl FnPtr { /// clone them _before_ calling this function. pub fn call_dynamic( &self, - mut ctx: NativeCallContext, + ctx: NativeCallContext, this_ptr: Option<&mut Dynamic>, mut arg_values: impl AsMut<[Dynamic]>, ) -> Result> { diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 7858b775..4ab427db 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -650,7 +650,7 @@ mod array_functions { } #[rhai_fn(name = "==", return_raw)] pub fn equals( - mut ctx: NativeCallContext, + ctx: NativeCallContext, arr1: &mut Array, mut arr2: Array, ) -> Result> { diff --git a/src/packages/map_basic.rs b/src/packages/map_basic.rs index a0039dc9..fd328c7b 100644 --- a/src/packages/map_basic.rs +++ b/src/packages/map_basic.rs @@ -45,7 +45,7 @@ mod map_functions { } #[rhai_fn(name = "==", return_raw)] pub fn equals( - mut ctx: NativeCallContext, + ctx: NativeCallContext, map1: &mut Map, mut map2: Map, ) -> Result> { diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index 80686547..86db1c53 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -15,6 +15,9 @@ use crate::Array; #[cfg(not(feature = "no_object"))] use crate::Map; +const FUNC_TO_STRING: &'static str = "to_string"; +const FUNC_TO_DEBUG: &'static str = "to_debug"; + type Unit = (); macro_rules! gen_functions { @@ -32,13 +35,14 @@ macro_rules! gen_functions { macro_rules! reg_print_functions { ($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $( - set_exported_fn!($mod_name, "to_string", $root::$arg_type::to_string_func); + set_exported_fn!($mod_name, FUNC_TO_STRING, $root::$arg_type::to_string_func); set_exported_fn!($mod_name, KEYWORD_PRINT, $root::$arg_type::to_string_func); )* } } macro_rules! reg_debug_functions { ($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $( + set_exported_fn!($mod_name, FUNC_TO_DEBUG, $root::$arg_type::to_string_func); set_exported_fn!($mod_name, KEYWORD_DEBUG, $root::$arg_type::to_string_func); )* } } @@ -67,12 +71,6 @@ def_package!(crate:BasicStringPackage:"Basic string utilities, including printin reg_print_functions!(lib += print_float; f32, f64); reg_debug_functions!(lib += debug_float; f32, f64); } - - #[cfg(not(feature = "no_index"))] - { - reg_print_functions!(lib += print_array; Array); - reg_debug_functions!(lib += print_array; Array); - } }); fn to_string(x: &mut T) -> ImmutableString { @@ -109,10 +107,18 @@ gen_functions!(print_float => to_string(f32, f64)); #[cfg(not(feature = "no_float"))] gen_functions!(debug_float => to_debug(f32, f64)); -#[cfg(not(feature = "no_index"))] -gen_functions!(print_array => to_debug(Array)); - // Register print and debug + +#[cfg(not(feature = "no_index"))] +#[inline(always)] +fn print_with_func(fn_name: &str, ctx: &NativeCallContext, value: &mut Dynamic) -> ImmutableString { + match ctx.call_fn_dynamic_raw(fn_name, true, false, &mut [value], None) { + Ok(result) if result.is::() => result.take_immutable_string().unwrap(), + Ok(result) => ctx.engine().map_type_name(result.type_name()).into(), + Err(_) => ctx.engine().map_type_name(value.type_name()).into(), + } +} + #[export_module] mod print_debug_functions { #[rhai_fn(name = "print", name = "debug")] @@ -132,13 +138,50 @@ mod print_debug_functions { to_string(f) } + #[cfg(not(feature = "no_index"))] + pub mod array_functions { + use super::*; + + #[rhai_fn(name = "print", name = "to_string", name = "to_debug", name = "debug")] + pub fn format_array(ctx: NativeCallContext, arr: &mut Array) -> ImmutableString { + let mut result = String::with_capacity(16); + result.push_str("["); + + let len = arr.len(); + + arr.iter_mut().enumerate().for_each(|(i, x)| { + result.push_str(&print_with_func(FUNC_TO_DEBUG, &ctx, x)); + if i < len - 1 { + result.push_str(", "); + } + }); + + result.push_str("]"); + result.into() + } + } #[cfg(not(feature = "no_object"))] pub mod map_functions { use super::*; - #[rhai_fn(name = "print", name = "debug", name = "to_string")] - pub fn format_map(x: &mut Map) -> ImmutableString { - format!("#{:?}", x).into() + #[rhai_fn(name = "print", name = "to_string", name = "to_debug", name = "debug")] + pub fn format_map(ctx: NativeCallContext, map: &mut Map) -> ImmutableString { + let mut result = String::with_capacity(16); + result.push_str("#{"); + + let len = map.len(); + + map.iter_mut().enumerate().for_each(|(i, (k, v))| { + result.push_str(k); + result.push_str(": "); + result.push_str(&print_with_func(FUNC_TO_DEBUG, &ctx, v)); + if i < len - 1 { + result.push_str(", "); + } + }); + + result.push_str("}"); + result.into() } } } diff --git a/tests/print.rs b/tests/print.rs index 8c580f42..fb50af3e 100644 --- a/tests/print.rs +++ b/tests/print.rs @@ -1,4 +1,4 @@ -use rhai::{Engine, EvalAltResult}; +use rhai::{Engine, EvalAltResult, RegisterFn, INT}; use std::sync::{Arc, RwLock}; #[test] @@ -30,3 +30,49 @@ fn test_print() -> Result<(), Box> { Ok(()) } + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] +struct MyStruct { + field: INT, +} + +impl std::fmt::Display for MyStruct { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "hello: {}", self.field) + } +} + +#[test] +fn test_print_custom_type() -> Result<(), Box> { + let mut engine = Engine::new(); + + engine + .register_type_with_name::("MyStruct") + .register_fn("to_debug", |x: &mut MyStruct| x.to_string()) + .register_fn("debug", |x: &mut MyStruct| x.to_string()) + .register_fn("new_ts", || MyStruct { field: 42 }); + + engine.consume("let x = new_ts(); debug(x);")?; + + #[cfg(not(feature = "no_index"))] + assert_eq!( + engine.eval::( + r#" + let x = [ 123, true, (), "world", new_ts() ]; + x.to_string() + "# + )?, + r#"[123, true, (), "world", hello: 42]"# + ); + + #[cfg(not(feature = "no_object"))] + assert!(engine + .eval::( + r#" + let x = #{ a:123, b:true, c:(), d:"world", e:new_ts() }; + x.to_string() + "# + )? + .contains("e: hello: 42")); + Ok(()) +} From 4c4a209609141ac1705201896ce1316214400234 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 30 Nov 2020 21:16:59 +0800 Subject: [PATCH 3/3] Fix tests. --- codegen/src/test/module.rs | 12 ++++++------ src/packages/string_basic.rs | 6 +++--- tests/print.rs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index c586f0a1..3b3c0d2d 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -1672,7 +1672,7 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]), + m.set_fn("set$squared", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]), &[core::any::TypeId::of::(), core::any::TypeId::of::()], int_foo_token().into()); if flatten {} else {} @@ -1752,7 +1752,7 @@ mod generate_tests { m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]), &[core::any::TypeId::of::(), core::any::TypeId::of::()], int_foo_token().into()); - m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]), + m.set_fn("set$squared", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]), &[core::any::TypeId::of::(), core::any::TypeId::of::()], int_foo_token().into()); if flatten {} else {} @@ -1829,7 +1829,7 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public, + m.set_fn("index$get$", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut MyCollection", "i: u64", "FLOAT"]), &[core::any::TypeId::of::(), core::any::TypeId::of::()], @@ -1914,7 +1914,7 @@ mod generate_tests { &[core::any::TypeId::of::(), core::any::TypeId::of::()], get_by_index_token().into()); - m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public, + m.set_fn("index$get$", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut MyCollection", "i: u64", "FLOAT"]), &[core::any::TypeId::of::(), core::any::TypeId::of::()], @@ -1994,7 +1994,7 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public, + m.set_fn("index$set$", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]), &[core::any::TypeId::of::(), core::any::TypeId::of::(), @@ -2083,7 +2083,7 @@ mod generate_tests { core::any::TypeId::of::(), core::any::TypeId::of::()], set_by_index_token().into()); - m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public, + m.set_fn("index$set$", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]), &[core::any::TypeId::of::(), core::any::TypeId::of::(), diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index 86db1c53..44ab4e7e 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -109,7 +109,7 @@ gen_functions!(debug_float => to_debug(f32, f64)); // Register print and debug -#[cfg(not(feature = "no_index"))] +#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline(always)] fn print_with_func(fn_name: &str, ctx: &NativeCallContext, value: &mut Dynamic) -> ImmutableString { match ctx.call_fn_dynamic_raw(fn_name, true, false, &mut [value], None) { @@ -144,7 +144,7 @@ mod print_debug_functions { #[rhai_fn(name = "print", name = "to_string", name = "to_debug", name = "debug")] pub fn format_array(ctx: NativeCallContext, arr: &mut Array) -> ImmutableString { - let mut result = String::with_capacity(16); + let mut result = crate::stdlib::string::String::with_capacity(16); result.push_str("["); let len = arr.len(); @@ -166,7 +166,7 @@ mod print_debug_functions { #[rhai_fn(name = "print", name = "to_string", name = "to_debug", name = "debug")] pub fn format_map(ctx: NativeCallContext, map: &mut Map) -> ImmutableString { - let mut result = String::with_capacity(16); + let mut result = crate::stdlib::string::String::with_capacity(16); result.push_str("#{"); let len = map.len(); diff --git a/tests/print.rs b/tests/print.rs index fb50af3e..7967670a 100644 --- a/tests/print.rs +++ b/tests/print.rs @@ -42,6 +42,7 @@ impl std::fmt::Display for MyStruct { } } +#[cfg(not(feature = "no_object"))] #[test] fn test_print_custom_type() -> Result<(), Box> { let mut engine = Engine::new(); @@ -65,7 +66,6 @@ fn test_print_custom_type() -> Result<(), Box> { r#"[123, true, (), "world", hello: 42]"# ); - #[cfg(not(feature = "no_object"))] assert!(engine .eval::( r#"