diff --git a/CHANGELOG.md b/CHANGELOG.md index 01592c85..d9aecc83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,24 @@ Rhai Release Notes ================== +Version 1.10.0 +============== + +Bug fixes +--------- + +* API for registering property getters/setters and indexers to an `Engine` now works with functions that take a first parameter of `NativeCallContext`. +* Missing API function `Module::set_getter_setter_fn` is added. + +New features +------------ + +Fallible type iterators +----------------------- + +* For very special needs, the ability to register fallible type iterators is added. + + Version 1.9.0 ============= diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 23199b0b..7b54fadf 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -125,10 +125,10 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Register a custom function. #[inline(always)] - pub fn with_fn(&mut self, name: N, method: F) -> &mut Self + pub fn with_fn(&mut self, name: N, method: F) -> &mut Self where N: AsRef + Into, - F: RegisterNativeFunction, + F: RegisterNativeFunction, { self.engine.register_fn(name, method); self @@ -136,10 +136,10 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Register a custom fallible function. #[inline(always)] - pub fn with_result_fn(&mut self, name: N, method: F) -> &mut Self + pub fn with_result_fn(&mut self, name: N, method: F) -> &mut Self where N: AsRef + Into, - F: RegisterNativeFunction>, + F: RegisterNativeFunction>, { self.engine.register_result_fn(name, method); self diff --git a/src/api/json.rs b/src/api/json.rs index ae00bbed..034062bf 100644 --- a/src/api/json.rs +++ b/src/api/json.rs @@ -72,16 +72,13 @@ impl Engine { Token::LeftBrace => Token::MapStart, // Disallowed syntax t @ (Token::Unit | Token::MapStart) => Token::LexError( - LexError::ImproperSymbol( - t.literal_syntax().to_string(), - "".to_string(), - ) - .into(), + LexError::ImproperSymbol(t.literal_syntax().to_string(), String::new()) + .into(), ), Token::InterpolatedString(..) => Token::LexError( LexError::ImproperSymbol( "interpolated string".to_string(), - "".to_string(), + String::new(), ) .into(), ), @@ -93,7 +90,7 @@ impl Engine { Some(&|token, _, _| { match token { Token::Reserved(s) if &*s == "null" => Token::LexError( - LexError::ImproperSymbol("null".to_string(), "".to_string()).into(), + LexError::ImproperSymbol("null".to_string(), String::new()).into(), ), // `{` => `#{` Token::LeftBrace => Token::MapStart, diff --git a/src/api/register.rs b/src/api/register.rs index 3ebb8695..5625773d 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -1,5 +1,6 @@ //! Module that defines the public function/module registration API of [`Engine`]. +use crate::func::register::Mut; use crate::func::{FnCallArgs, RegisterNativeFunction, SendSync}; use crate::types::dynamic::Variant; use crate::{ @@ -50,10 +51,10 @@ impl Engine { /// # } /// ``` #[inline] - pub fn register_fn(&mut self, name: N, func: F) -> &mut Self + pub fn register_fn(&mut self, name: N, func: F) -> &mut Self where N: AsRef + Into, - F: RegisterNativeFunction, + F: RegisterNativeFunction, { let param_types = F::param_types(); @@ -112,10 +113,10 @@ impl Engine { /// .expect_err("expecting division by zero error!"); /// ``` #[inline] - pub fn register_result_fn(&mut self, name: N, func: F) -> &mut Self + pub fn register_result_fn(&mut self, name: N, func: F) -> &mut Self where N: AsRef + Into, - F: RegisterNativeFunction>, + F: RegisterNativeFunction>, { let param_types = F::param_types(); @@ -291,7 +292,7 @@ impl Engine { .set_custom_type_raw(fully_qualified_type_path, name); self } - /// Register an type iterator for an iterable type with the [`Engine`]. + /// Register a type iterator for an iterable type with the [`Engine`]. /// This is an advanced API. #[inline(always)] pub fn register_iterator(&mut self) -> &mut Self @@ -302,6 +303,17 @@ impl Engine { self.global_namespace_mut().set_iterable::(); self } + /// Register a fallible type iterator for an iterable type with the [`Engine`]. + /// This is an advanced API. + #[inline(always)] + pub fn register_iterator_result(&mut self) -> &mut Self + where + T: Variant + Clone + IntoIterator>, + X: Variant + Clone, + { + self.global_namespace_mut().set_iterable_result::(); + self + } /// Register a getter function for a member of a registered type with the [`Engine`]. /// /// The function signature must start with `&mut self` and not `&self`. @@ -344,10 +356,10 @@ impl Engine { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn register_get( + pub fn register_get( &mut self, name: impl AsRef, - get_fn: impl Fn(&mut T) -> V + SendSync + 'static, + get_fn: impl RegisterNativeFunction<(Mut,), V, S> + SendSync + 'static, ) -> &mut Self { self.register_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn) } @@ -393,10 +405,10 @@ impl Engine { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn register_get_result( + pub fn register_get_result( &mut self, name: impl AsRef, - get_fn: impl Fn(&mut T) -> RhaiResultOf + SendSync + 'static, + get_fn: impl RegisterNativeFunction<(Mut,), V, RhaiResultOf> + SendSync + 'static, ) -> &mut Self { self.register_result_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn) } @@ -443,10 +455,10 @@ impl Engine { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn register_set( + pub fn register_set( &mut self, name: impl AsRef, - set_fn: impl Fn(&mut T, V) + SendSync + 'static, + set_fn: impl RegisterNativeFunction<(Mut, V), (), S> + SendSync + 'static, ) -> &mut Self { self.register_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn) } @@ -494,10 +506,10 @@ impl Engine { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn register_set_result( + pub fn register_set_result( &mut self, name: impl AsRef, - set_fn: impl Fn(&mut T, V) -> RhaiResultOf<()> + SendSync + 'static, + set_fn: impl RegisterNativeFunction<(Mut, V), (), RhaiResultOf> + SendSync + 'static, ) -> &mut Self { self.register_result_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn) } @@ -548,11 +560,11 @@ impl Engine { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn register_get_set( + pub fn register_get_set( &mut self, name: impl AsRef, - get_fn: impl Fn(&mut T) -> V + SendSync + 'static, - set_fn: impl Fn(&mut T, V) + SendSync + 'static, + get_fn: impl RegisterNativeFunction<(Mut,), V, S1> + SendSync + 'static, + set_fn: impl RegisterNativeFunction<(Mut, V), (), S2> + SendSync + 'static, ) -> &mut Self { self.register_get(&name, get_fn).register_set(&name, set_fn) } @@ -607,9 +619,9 @@ impl Engine { /// ``` #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline] - pub fn register_indexer_get( + pub fn register_indexer_get( &mut self, - get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, + get_fn: impl RegisterNativeFunction<(Mut, X), V, S> + SendSync + 'static, ) -> &mut Self { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { @@ -686,9 +698,10 @@ impl Engine { T: Variant + Clone, X: Variant + Clone, V: Variant + Clone, + S, >( &mut self, - get_fn: impl Fn(&mut T, X) -> RhaiResultOf + SendSync + 'static, + get_fn: impl RegisterNativeFunction<(Mut, X), V, RhaiResultOf> + SendSync + 'static, ) -> &mut Self { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { @@ -761,9 +774,9 @@ impl Engine { /// ``` #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline] - pub fn register_indexer_set( + pub fn register_indexer_set( &mut self, - set_fn: impl Fn(&mut T, X, V) + SendSync + 'static, + set_fn: impl RegisterNativeFunction<(Mut, X, V), (), S> + SendSync + 'static, ) -> &mut Self { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { @@ -841,9 +854,10 @@ impl Engine { T: Variant + Clone, X: Variant + Clone, V: Variant + Clone, + S, >( &mut self, - set_fn: impl Fn(&mut T, X, V) -> RhaiResultOf<()> + SendSync + 'static, + set_fn: impl RegisterNativeFunction<(Mut, X, V), (), RhaiResultOf> + SendSync + 'static, ) -> &mut Self { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { @@ -917,10 +931,16 @@ impl Engine { /// ``` #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline(always)] - pub fn register_indexer_get_set( + pub fn register_indexer_get_set< + T: Variant + Clone, + X: Variant + Clone, + V: Variant + Clone, + S1, + S2, + >( &mut self, - get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, - set_fn: impl Fn(&mut T, X, V) + SendSync + 'static, + get_fn: impl RegisterNativeFunction<(Mut, X), V, S1> + SendSync + 'static, + set_fn: impl RegisterNativeFunction<(Mut, X, V), (), S2> + SendSync + 'static, ) -> &mut Self { self.register_indexer_get(get_fn) .register_indexer_set(set_fn) diff --git a/src/bin/rhai-dbg.rs b/src/bin/rhai-dbg.rs index 30d521fa..a83b680c 100644 --- a/src/bin/rhai-dbg.rs +++ b/src/bin/rhai-dbg.rs @@ -90,12 +90,12 @@ fn print_error(input: &str, mut err: EvalAltResult) { let line_no = if lines.len() > 1 { if pos.is_none() { - "".to_string() + String::new() } else { format!("{}: ", pos.line().unwrap()) } } else { - "".to_string() + String::new() }; // Print error position diff --git a/src/bin/rhai-repl.rs b/src/bin/rhai-repl.rs index 932bcf30..00e01e8b 100644 --- a/src/bin/rhai-repl.rs +++ b/src/bin/rhai-repl.rs @@ -15,12 +15,12 @@ fn print_error(input: &str, mut err: EvalAltResult) { let line_no = if lines.len() > 1 { if pos.is_none() { - "".to_string() + String::new() } else { format!("{}: ", pos.line().unwrap()) } } else { - "".to_string() + String::new() }; // Print error position diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 8e8ab47c..18d16eba 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -641,38 +641,21 @@ impl Engine { break; } - let index_value = (x as INT).into(); + let index_value = Dynamic::from(x as INT); - #[cfg(not(feature = "no_closure"))] - { - let index_var = scope.get_mut_by_index(counter_index); - if index_var.is_shared() { - *index_var.write_lock().expect("`Dynamic`") = index_value; - } else { - *index_var = index_value; - } - } - #[cfg(feature = "no_closure")] - { - *scope.get_mut_by_index(counter_index) = index_value; - } + *scope.get_mut_by_index(counter_index).write_lock().unwrap() = + index_value; } - let value = iter_value.flatten(); - - #[cfg(not(feature = "no_closure"))] - { - let loop_var = scope.get_mut_by_index(index); - if loop_var.is_shared() { - *loop_var.write_lock().expect("`Dynamic`") = value; - } else { - *loop_var = value; + let value = match iter_value { + Ok(v) => v.flatten(), + Err(err) => { + loop_result = Err(err.fill_position(expr.position())); + break; } - } - #[cfg(feature = "no_closure")] - { - *scope.get_mut_by_index(index) = value; - } + }; + + *scope.get_mut_by_index(index).write_lock().unwrap() = value; #[cfg(not(feature = "unchecked"))] if let Err(err) = self diff --git a/src/func/native.rs b/src/func/native.rs index 6b3d46de..26801793 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -426,10 +426,11 @@ pub type FnBuiltin = fn(NativeCallContext, &mut FnCallArgs) -> RhaiResult; /// Function that gets an iterator from a type. #[cfg(not(feature = "sync"))] -pub type IteratorFn = dyn Fn(Dynamic) -> Box>; +pub type IteratorFn = dyn Fn(Dynamic) -> Box>>; /// Function that gets an iterator from a type. #[cfg(feature = "sync")] -pub type IteratorFn = dyn Fn(Dynamic) -> Box> + Send + Sync; +pub type IteratorFn = + dyn Fn(Dynamic) -> Box>> + Send + Sync; #[cfg(not(feature = "sync"))] pub type FnPlugin = dyn PluginFunction; diff --git a/src/func/register.rs b/src/func/register.rs index 41944cf6..d9e45e76 100644 --- a/src/func/register.rs +++ b/src/func/register.rs @@ -60,7 +60,7 @@ pub fn by_value(data: &mut Dynamic) -> T { } /// Trait to register custom Rust functions. -pub trait RegisterNativeFunction { +pub trait RegisterNativeFunction { /// Convert this function into a [`CallableFunction`]. #[must_use] fn into_callable_function(self) -> CallableFunction; @@ -128,7 +128,7 @@ macro_rules! def_register { FN: Fn($($param),*) -> RET + SendSync + 'static, $($par: Variant + Clone,)* RET: Variant + Clone - > RegisterNativeFunction<($($mark,)*), ()> for FN { + > RegisterNativeFunction<($($mark,)*), RET, ()> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::() } @@ -154,7 +154,7 @@ macro_rules! def_register { FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RET + SendSync + 'static, $($par: Variant + Clone,)* RET: Variant + Clone - > RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), ()> for FN { + > RegisterNativeFunction<($($mark,)*), RET, NativeCallContext<'static>> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::() } @@ -180,7 +180,7 @@ macro_rules! def_register { FN: Fn($($param),*) -> RhaiResultOf + SendSync + 'static, $($par: Variant + Clone,)* RET: Variant + Clone - > RegisterNativeFunction<($($mark,)*), RhaiResultOf> for FN { + > RegisterNativeFunction<($($mark,)*), RET, RhaiResultOf<()>> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::>() } @@ -203,7 +203,7 @@ macro_rules! def_register { FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RhaiResultOf + SendSync + 'static, $($par: Variant + Clone,)* RET: Variant + Clone - > RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), RhaiResultOf> for FN { + > RegisterNativeFunction<($($mark,)*), RET, RhaiResultOf>> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::>() } diff --git a/src/module/mod.rs b/src/module/mod.rs index fb3e47ab..143be2a5 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -1,6 +1,7 @@ //! Module defining external-loaded modules for Rhai. use crate::ast::FnAccess; +use crate::func::register::Mut; use crate::func::{ shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction, SendSync, @@ -1290,11 +1291,11 @@ impl Module { /// assert!(module.contains_fn(hash)); /// ``` #[inline(always)] - pub fn set_native_fn(&mut self, name: N, func: F) -> u64 + pub fn set_native_fn(&mut self, name: N, func: F) -> u64 where N: AsRef + Into, T: Variant + Clone, - F: RegisterNativeFunction>, + F: RegisterNativeFunction>, { self.set_fn( name, @@ -1326,14 +1327,11 @@ impl Module { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn set_getter_fn(&mut self, name: impl AsRef, func: F) -> u64 + pub fn set_getter_fn(&mut self, name: impl AsRef, func: F) -> u64 where A: Variant + Clone, T: Variant + Clone, - F: RegisterNativeFunction> - + Fn(&mut A) -> RhaiResultOf - + SendSync - + 'static, + F: RegisterNativeFunction<(Mut,), T, RhaiResultOf> + SendSync + 'static, { self.set_fn( crate::engine::make_getter(name.as_ref()).as_str(), @@ -1370,14 +1368,11 @@ impl Module { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn set_setter_fn(&mut self, name: impl AsRef, func: F) -> u64 + pub fn set_setter_fn(&mut self, name: impl AsRef, func: F) -> u64 where A: Variant + Clone, - B: Variant + Clone, - F: RegisterNativeFunction> - + Fn(&mut A, B) -> RhaiResultOf<()> - + SendSync - + 'static, + T: Variant + Clone, + F: RegisterNativeFunction<(Mut, T), (), RhaiResultOf> + SendSync + 'static, { self.set_fn( crate::engine::make_setter(name.as_ref()).as_str(), @@ -1389,6 +1384,48 @@ impl Module { ) } + /// Set a pair of Rust getter and setter functions into the [`Module`], returning both non-zero hash keys. + /// This is a short-hand for [`set_getter_fn`][Module::set_getter_fn] and [`set_setter_fn`][Module::set_setter_fn]. + /// + /// These function are automatically exposed to the global namespace. + /// + /// If there are similar existing Rust functions, they are replaced. + /// + /// # Function Metadata + /// + /// No metadata for the function is registered. + /// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata. + /// + /// # Example + /// + /// ``` + /// use rhai::{Module, ImmutableString}; + /// + /// let mut module = Module::new(); + /// let (hash_get, hash_set) = module.set_getter_setter_fn("value", + /// |x: &mut i64| { Ok(x.to_string().into()) }, + /// |x: &mut i64, y: ImmutableString| { + /// *x = y.len() as i64; + /// Ok(()) + /// } + /// ); + /// assert!(module.contains_fn(hash_get)); + /// assert!(module.contains_fn(hash_set)); + /// ``` + #[cfg(not(feature = "no_object"))] + #[inline(always)] + pub fn set_getter_setter_fn( + &mut self, + name: impl AsRef, + getter: impl RegisterNativeFunction<(Mut,), T, RhaiResultOf> + SendSync + 'static, + setter: impl RegisterNativeFunction<(Mut, T), (), RhaiResultOf> + SendSync + 'static, + ) -> (u64, u64) { + ( + self.set_getter_fn(name.as_ref(), getter), + self.set_setter_fn(name.as_ref(), setter), + ) + } + /// Set a Rust index getter taking two parameters (the first one mutable) into the [`Module`], /// returning a non-zero hash key. /// This function is automatically exposed to the global namespace. @@ -1418,15 +1455,12 @@ impl Module { /// ``` #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline] - pub fn set_indexer_get_fn(&mut self, func: F) -> u64 + pub fn set_indexer_get_fn(&mut self, func: F) -> u64 where A: Variant + Clone, B: Variant + Clone, T: Variant + Clone, - F: RegisterNativeFunction> - + Fn(&mut A, B) -> RhaiResultOf - + SendSync - + 'static, + F: RegisterNativeFunction<(Mut, B), T, RhaiResultOf> + SendSync + 'static, { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { @@ -1482,15 +1516,12 @@ impl Module { /// ``` #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline] - pub fn set_indexer_set_fn(&mut self, func: F) -> u64 + pub fn set_indexer_set_fn(&mut self, func: F) -> u64 where A: Variant + Clone, B: Variant + Clone, - C: Variant + Clone, - F: RegisterNativeFunction> - + Fn(&mut A, B, C) -> RhaiResultOf<()> - + SendSync - + 'static, + T: Variant + Clone, + F: RegisterNativeFunction<(Mut, B, T), (), RhaiResultOf> + SendSync + 'static, { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { @@ -1517,10 +1548,12 @@ impl Module { ) } - /// Set a pair of Rust index getter and setter functions, returning both non-zero hash keys. + /// Set a pair of Rust index getter and setter functions into the [`Module`], returning both non-zero hash keys. /// This is a short-hand for [`set_indexer_get_fn`][Module::set_indexer_get_fn] and /// [`set_indexer_set_fn`][Module::set_indexer_set_fn]. /// + /// These functions are automatically exposed to the global namespace. + /// /// If there are similar existing Rust functions, they are replaced. /// /// # Panics @@ -1552,10 +1585,10 @@ impl Module { /// ``` #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline(always)] - pub fn set_indexer_get_set_fn( + pub fn set_indexer_get_set_fn( &mut self, - get_fn: impl Fn(&mut A, B) -> RhaiResultOf + SendSync + 'static, - set_fn: impl Fn(&mut A, B, T) -> RhaiResultOf<()> + SendSync + 'static, + get_fn: impl RegisterNativeFunction<(Mut, B), T, RhaiResultOf> + SendSync + 'static, + set_fn: impl RegisterNativeFunction<(Mut, B, T), (), RhaiResultOf> + SendSync + 'static, ) -> (u64, u64) where A: Variant + Clone, @@ -2016,7 +2049,7 @@ impl Module { if let Some(fn_ptr) = value.downcast_ref::() { if ast.iter_fn_def().any(|f| f.name == fn_ptr.fn_name()) { return Err(crate::ERR::ErrorMismatchDataType( - "".to_string(), + String::new(), if fn_ptr.is_anonymous() { format!("cannot export closure in variable {_name}") } else { @@ -2217,29 +2250,23 @@ impl Module { } /// Set a type iterator into the [`Module`]. - #[cfg(not(feature = "sync"))] - #[inline] - pub fn set_iter( - &mut self, - type_id: TypeId, - func: impl Fn(Dynamic) -> Box> + 'static, - ) -> &mut Self { - let func = Shared::new(func); - if self.indexed { - self.all_type_iterators.insert(type_id, func.clone()); - self.contains_indexed_global_functions = true; - } - self.type_iterators.insert(type_id, func); - self - } - - /// Set a type iterator into the [`Module`]. - #[cfg(feature = "sync")] - #[inline] + #[inline(always)] pub fn set_iter( &mut self, type_id: TypeId, func: impl Fn(Dynamic) -> Box> + SendSync + 'static, + ) -> &mut Self { + self.set_iter_result(type_id, move |x| { + Box::new(func(x).map(Ok)) as Box>> + }) + } + + /// Set a fallible type iterator into the [`Module`]. + #[inline] + pub fn set_iter_result( + &mut self, + type_id: TypeId, + func: impl Fn(Dynamic) -> Box>> + SendSync + 'static, ) -> &mut Self { let func = Shared::new(func); if self.indexed { @@ -2251,7 +2278,7 @@ impl Module { } /// Set a type iterator into the [`Module`]. - #[inline] + #[inline(always)] pub fn set_iterable(&mut self) -> &mut Self where T: Variant + Clone + IntoIterator, @@ -2262,8 +2289,20 @@ impl Module { }) } + /// Set a fallible type iterator into the [`Module`]. + #[inline(always)] + pub fn set_iterable_result(&mut self) -> &mut Self + where + T: Variant + Clone + IntoIterator>, + X: Variant + Clone, + { + self.set_iter_result(TypeId::of::(), |obj: Dynamic| { + Box::new(obj.cast::().into_iter().map(|v| v.map(Dynamic::from))) + }) + } + /// Set an iterator type into the [`Module`] as a type iterator. - #[inline] + #[inline(always)] pub fn set_iterator(&mut self) -> &mut Self where T: Variant + Clone + Iterator, @@ -2274,6 +2313,18 @@ impl Module { }) } + /// Set a iterator type into the [`Module`] as a fallible type iterator. + #[inline(always)] + pub fn set_iterator_result(&mut self) -> &mut Self + where + T: Variant + Clone + Iterator>, + X: Variant + Clone, + { + self.set_iter_result(TypeId::of::(), |obj: Dynamic| { + Box::new(obj.cast::().map(|v| v.map(Dynamic::from))) + }) + } + /// Get the specified type iterator. #[cfg(not(feature = "no_module"))] #[inline] diff --git a/src/parser.rs b/src/parser.rs index 754513c8..48a8a97b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2051,12 +2051,12 @@ impl Engine { Ok(Stmt::Assignment((op_info, (lhs, rhs).into()).into())) } // expr[???] = rhs, expr.??? = rhs - ref expr => Err(PERR::AssignmentToInvalidLHS("".to_string()) + ref expr => Err(PERR::AssignmentToInvalidLHS(String::new()) .into_err(expr.position())), } } Some(err_pos) => { - Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(err_pos)) + Err(PERR::AssignmentToInvalidLHS(String::new()).into_err(err_pos)) } } } @@ -2067,7 +2067,7 @@ impl Engine { ) .into_err(op_pos)), // expr = rhs - _ => Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(lhs.position())), + _ => Err(PERR::AssignmentToInvalidLHS(String::new()).into_err(lhs.position())), } } @@ -3665,8 +3665,9 @@ impl Engine { (Token::Pipe, ..) => break, (Token::Identifier(s), pos) => { if params_list.iter().any(|p| p.as_str() == &*s) { - return Err(PERR::FnDuplicatedParam("".to_string(), s.to_string()) - .into_err(pos)); + return Err( + PERR::FnDuplicatedParam(String::new(), s.to_string()).into_err(pos) + ); } let s = state.get_interned_string(s); state.stack.push(s.clone(), ()); diff --git a/src/types/parse_error.rs b/src/types/parse_error.rs index b1cbf12a..a80255f0 100644 --- a/src/types/parse_error.rs +++ b/src/types/parse_error.rs @@ -51,8 +51,7 @@ impl fmt::Display for LexError { Self::ImproperSymbol(s, d) if d.is_empty() => { write!(f, "Invalid symbol encountered: '{}'", s) } - Self::ImproperSymbol(s, d) if s.is_empty() => f.write_str(d), - Self::ImproperSymbol(s, d) => write!(f, "{}: '{}'", d, s), + Self::ImproperSymbol(.., d) => f.write_str(d), } } } diff --git a/tests/assignments.rs b/tests/assignments.rs index 1be3901b..e2a90d4f 100644 --- a/tests/assignments.rs +++ b/tests/assignments.rs @@ -25,28 +25,28 @@ fn test_assignments_bad_lhs() -> Result<(), Box> { .compile("(x+y) = 42;") .expect_err("should error") .err_type(), - ParseErrorType::AssignmentToInvalidLHS("".to_string()) + ParseErrorType::AssignmentToInvalidLHS(String::new()) ); assert_eq!( *engine .compile("foo(x) = 42;") .expect_err("should error") .err_type(), - ParseErrorType::AssignmentToInvalidLHS("".to_string()) + ParseErrorType::AssignmentToInvalidLHS(String::new()) ); assert_eq!( *engine .compile("true = 42;") .expect_err("should error") .err_type(), - ParseErrorType::AssignmentToConstant("".to_string()) + ParseErrorType::AssignmentToConstant(String::new()) ); assert_eq!( *engine .compile("123 = 42;") .expect_err("should error") .err_type(), - ParseErrorType::AssignmentToConstant("".to_string()) + ParseErrorType::AssignmentToConstant(String::new()) ); #[cfg(not(feature = "no_object"))] @@ -56,21 +56,21 @@ fn test_assignments_bad_lhs() -> Result<(), Box> { .compile("x.foo() = 42;") .expect_err("should error") .err_type(), - ParseErrorType::AssignmentToInvalidLHS("".to_string()) + ParseErrorType::AssignmentToInvalidLHS(String::new()) ); assert_eq!( *engine .compile("x.foo().x.y = 42;") .expect_err("should error") .err_type(), - ParseErrorType::AssignmentToInvalidLHS("".to_string()) + ParseErrorType::AssignmentToInvalidLHS(String::new()) ); assert_eq!( *engine .compile("x.y.z.foo() = 42;") .expect_err("should error") .err_type(), - ParseErrorType::AssignmentToInvalidLHS("".to_string()) + ParseErrorType::AssignmentToInvalidLHS(String::new()) ); #[cfg(not(feature = "no_index"))] assert_eq!( @@ -78,7 +78,7 @@ fn test_assignments_bad_lhs() -> Result<(), Box> { .compile("x.foo()[0] = 42;") .expect_err("should error") .err_type(), - ParseErrorType::AssignmentToInvalidLHS("".to_string()) + ParseErrorType::AssignmentToInvalidLHS(String::new()) ); #[cfg(not(feature = "no_index"))] assert_eq!( @@ -86,7 +86,7 @@ fn test_assignments_bad_lhs() -> Result<(), Box> { .compile("x[y].z.foo() = 42;") .expect_err("should error") .err_type(), - ParseErrorType::AssignmentToInvalidLHS("".to_string()) + ParseErrorType::AssignmentToInvalidLHS(String::new()) ); } diff --git a/tests/custom_syntax.rs b/tests/custom_syntax.rs index 0f7992f4..6c70dcd8 100644 --- a/tests/custom_syntax.rs +++ b/tests/custom_syntax.rs @@ -303,7 +303,7 @@ fn test_custom_syntax_raw() -> Result<(), Box> { .compile("hello hey") .expect_err("should error") .err_type(), - ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string(), "".to_string())) + ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string(), String::new())) ); Ok(()) diff --git a/tests/get_set.rs b/tests/get_set.rs index 2879d56b..d9065952 100644 --- a/tests/get_set.rs +++ b/tests/get_set.rs @@ -1,6 +1,6 @@ #![cfg(not(feature = "no_object"))] -use rhai::{Engine, EvalAltResult, Scope, INT}; +use rhai::{Engine, EvalAltResult, NativeCallContext, Scope, INT}; #[test] fn test_get_set() -> Result<(), Box> { @@ -217,12 +217,14 @@ fn test_get_set_chain_without_write_back() -> Result<(), Box> { .register_get_set( "value", |t: &mut Inner| t.value, - |_: &mut Inner, new: INT| panic!("Inner::value setter called with {}", new), + |_: NativeCallContext, _: &mut Inner, new: INT| { + panic!("Inner::value setter called with {}", new) + }, ) .register_type::() .register_get_set( "inner", - |t: &mut Outer| t.inner.clone(), + |_: NativeCallContext, t: &mut Outer| t.inner.clone(), |_: &mut Outer, new: Inner| panic!("Outer::inner setter called with {:?}", new), );