From db3049e5741be4cd506d453e30419266838dc39f Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 23 Aug 2021 23:10:54 +0800 Subject: [PATCH 1/8] Engine::register_type_XXX available under no_object. --- CHANGELOG.md | 1 + src/engine_api.rs | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c12e8938..e1c751a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Enhancements * `Scope::set_value` now takes anything that implements `Into>`. * Added `Scope::is_constant` to check if a variable is constant. * Added `Scope::set_or_push` to add a new variable only if one doesn't already exist. +* `Engine::register_type_XXX` are now available even under `no_object`. Version 1.0.2 diff --git a/src/engine_api.rs b/src/engine_api.rs index 181e59d8..7156a2a1 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -184,8 +184,6 @@ impl Engine { /// Register a custom type for use with the [`Engine`]. /// The type must implement [`Clone`]. /// - /// Not available under `no_object`. - /// /// # Example /// /// ``` @@ -219,7 +217,6 @@ impl Engine { /// # Ok(()) /// # } /// ``` - #[cfg(not(feature = "no_object"))] #[inline(always)] pub fn register_type(&mut self) -> &mut Self { self.register_type_with_name::(type_name::()) @@ -227,8 +224,6 @@ impl Engine { /// Register a custom type for use with the [`Engine`], with a pretty-print name /// for the `type_of` function. The type must implement [`Clone`]. /// - /// Not available under `no_object`. - /// /// # Example /// /// ``` @@ -266,7 +261,6 @@ impl Engine { /// # Ok(()) /// # } /// ``` - #[cfg(not(feature = "no_object"))] #[inline(always)] pub fn register_type_with_name(&mut self, name: &str) -> &mut Self { // Add the pretty-print type name into the map From 2a760eb44b09f1af8ecd5c3c951576f237809f20 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 24 Aug 2021 12:04:53 +0800 Subject: [PATCH 2/8] Update doc-comments. --- src/engine_api.rs | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/engine_api.rs b/src/engine_api.rs index 7156a2a1..e8f4a888 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -21,7 +21,6 @@ use crate::Array; #[cfg(not(feature = "no_object"))] use crate::Map; -/// Engine public API impl Engine { /// Register a custom function with the [`Engine`]. /// @@ -193,9 +192,8 @@ impl Engine { /// } /// /// impl TestStruct { - /// fn new() -> Self { Self { field: 1 } } - /// - /// fn update(&mut self, offset: i64) { self.field += offset; } + /// fn new() -> Self { Self { field: 1 } } + /// fn update(&mut self, offset: i64) { self.field += offset; } /// } /// /// # fn main() -> Result<(), Box> { @@ -294,8 +292,7 @@ impl Engine { /// } /// /// impl TestStruct { - /// fn new() -> Self { Self { field: 1 } } - /// + /// fn new() -> Self { Self { field: 1 } } /// // Even a getter must start with `&mut self` and not `&self`. /// fn get_field(&mut self) -> i64 { self.field } /// } @@ -343,7 +340,6 @@ impl Engine { /// /// impl TestStruct { /// fn new() -> Self { Self { field: 1 } } - /// /// // Even a getter must start with `&mut self` and not `&self`. /// fn get_field(&mut self) -> Result> { /// Ok(self.field) @@ -386,9 +382,8 @@ impl Engine { /// } /// /// impl TestStruct { - /// fn new() -> Self { Self { field: 1 } } - /// - /// fn set_field(&mut self, new_val: i64) { self.field = new_val; } + /// fn new() -> Self { Self { field: 1 } } + /// fn set_field(&mut self, new_val: i64) { self.field = new_val; } /// } /// /// # fn main() -> Result<(), Box> { @@ -436,7 +431,6 @@ impl Engine { /// /// impl TestStruct { /// fn new() -> Self { Self { field: 1 } } - /// /// fn set_field(&mut self, new_val: i64) -> Result<(), Box> { /// self.field = new_val; /// Ok(()) @@ -486,12 +480,10 @@ impl Engine { /// } /// /// impl TestStruct { - /// fn new() -> Self { Self { field: 1 } } - /// + /// fn new() -> Self { Self { field: 1 } } /// // Even a getter must start with `&mut self` and not `&self`. - /// fn get_field(&mut self) -> i64 { self.field } - /// - /// fn set_field(&mut self, new_val: i64) { self.field = new_val; } + /// fn get_field(&mut self) -> i64 { self.field } + /// fn set_field(&mut self, new_val: i64) { self.field = new_val; } /// } /// /// # fn main() -> Result<(), Box> { @@ -543,7 +535,6 @@ impl Engine { /// /// impl TestStruct { /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } - /// /// // Even a getter must start with `&mut self` and not `&self`. /// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] } /// } @@ -617,7 +608,6 @@ impl Engine { /// /// impl TestStruct { /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } - /// /// // Even a getter must start with `&mut self` and not `&self`. /// fn get_field(&mut self, index: i64) -> Result> { /// Ok(self.fields[index as usize]) @@ -691,7 +681,6 @@ impl Engine { /// /// impl TestStruct { /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } - /// /// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; } /// } /// @@ -765,7 +754,6 @@ impl Engine { /// /// impl TestStruct { /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } - /// /// fn set_field(&mut self, index: i64, value: i64) -> Result<(), Box> { /// self.fields[index as usize] = value; /// Ok(()) @@ -841,11 +829,9 @@ impl Engine { /// } /// /// impl TestStruct { - /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } - /// + /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } /// // Even a getter must start with `&mut self` and not `&self`. - /// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] } - /// + /// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] } /// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; } /// } /// From aec4417bd5f40fc7efa2cd9ec866da3771f512ee Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 26 Aug 2021 23:58:41 +0800 Subject: [PATCH 3/8] Refine expect messages. --- src/ast.rs | 14 ++-- src/custom_syntax.rs | 29 ++++--- src/dynamic.rs | 18 ++--- src/engine.rs | 119 +++++++++++---------------- src/engine_api.rs | 49 +++++------- src/engine_settings.rs | 2 +- src/error.rs | 2 +- src/fn_builtin.rs | 4 +- src/fn_call.rs | 151 +++++++++++++++++++++-------------- src/fn_native.rs | 2 +- src/fn_register.rs | 17 ++-- src/module/mod.rs | 20 ++--- src/optimize.rs | 73 +++++++++++------ src/packages/fn_basic.rs | 2 +- src/packages/string_basic.rs | 2 +- src/packages/string_more.rs | 6 +- src/parse.rs | 31 +++---- src/scope.rs | 55 +++++-------- src/serde/de.rs | 2 +- src/serde/metadata.rs | 36 +++++---- src/token.rs | 28 +++---- 21 files changed, 328 insertions(+), 334 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 968f7ac7..e7541387 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1490,8 +1490,7 @@ impl Stmt { _ => (), } - path.pop() - .expect("never fails because `path` always contains the current node"); + path.pop().expect("`path` contains current node"); true } @@ -1566,7 +1565,7 @@ impl OpAssignment<'_> { pub fn new(op: Token) -> Self { let op_raw = op .map_op_assignment() - .expect("never fails because token must be an op-assignment operator") + .expect("token is op-assignment operator") .literal_syntax(); let op_assignment = op.literal_syntax(); @@ -2018,7 +2017,7 @@ impl Expr { let mut arr = Array::with_capacity(x.len()); arr.extend(x.iter().map(|v| { v.get_literal_value() - .expect("never fails because a constant array always has a constant value") + .expect("constant array has constant value") })); Dynamic::from_array(arr) } @@ -2028,9 +2027,9 @@ impl Expr { let mut map = x.1.clone(); x.0.iter().for_each(|(k, v)| { *map.get_mut(k.name.as_str()) - .expect("never fails because the template should contain all the keys") = v + .expect("template contains all keys") = v .get_literal_value() - .expect("never fails because a constant map always has a constant value") + .expect("constant map has constant value") }); Dynamic::from_map(map) } @@ -2309,8 +2308,7 @@ impl Expr { _ => (), } - path.pop() - .expect("never fails because `path` always contains the current node"); + path.pop().expect("`path` contains current node"); true } diff --git a/src/custom_syntax.rs b/src/custom_syntax.rs index be4a22e7..678afce3 100644 --- a/src/custom_syntax.rs +++ b/src/custom_syntax.rs @@ -154,8 +154,8 @@ impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> { /// Definition of a custom syntax definition. pub struct CustomSyntax { - /// A parsing function to return the next keyword in a custom syntax based on the - /// keywords parsed so far. + /// A parsing function to return the next token in a custom syntax based on the + /// symbols parsed so far. pub parse: Box, /// Custom syntax implementation function. pub func: Shared, @@ -166,10 +166,17 @@ pub struct CustomSyntax { impl Engine { /// Register a custom syntax with the [`Engine`]. /// - /// * `keywords` holds a slice of strings that define the custom syntax. + /// * `symbols` holds a slice of strings that define the custom syntax. /// * `scope_may_be_changed` specifies variables _may_ be added/removed by this custom syntax. /// * `func` is the implementation function. /// + /// ## Note on `symbols` + /// + /// * Whitespaces around symbols are stripped. + /// * Symbols that are all-whitespace or empty are ignored. + /// * If `symbols` does not contain at least one valid token, then the custom syntax registration + /// is simply ignored. + /// /// ## Note on `scope_may_be_changed` /// /// If `scope_may_be_changed` is `true`, then _size_ of the current [`Scope`][crate::Scope] @@ -185,7 +192,7 @@ impl Engine { /// does NOT count, so `false` should be passed. pub fn register_custom_syntax + Into>( &mut self, - keywords: &[S], + symbols: &[S], scope_may_be_changed: bool, func: impl Fn(&mut EvalContext, &[Expression]) -> RhaiResult + SendSync + 'static, ) -> Result<&mut Self, ParseError> { @@ -193,10 +200,10 @@ impl Engine { let mut segments: StaticVec = Default::default(); - for s in keywords { + for s in symbols { let s = s.as_ref().trim(); - // Skip empty keywords + // Skip empty symbols if s.is_empty() { continue; } @@ -220,10 +227,10 @@ impl Engine { #[cfg(not(feature = "no_float"))] CUSTOM_SYNTAX_MARKER_FLOAT if !segments.is_empty() => s.into(), // Standard or reserved keyword/symbol not in first position - s if !segments.is_empty() && token.is_some() => { + _ if !segments.is_empty() && token.is_some() => { // Make it a custom keyword/symbol if it is disabled or reserved if (self.disabled_symbols.contains(s) - || matches!(token, Some(Token::Reserved(_)))) + || token.map_or(false, |v| v.is_reserved())) && !self.custom_keywords.contains_key(s) { self.custom_keywords.insert(s.into(), None); @@ -273,7 +280,7 @@ impl Engine { segments.push(seg); } - // If the syntax has no keywords, just ignore the registration + // If the syntax has no symbols, just ignore the registration if segments.is_empty() { return Ok(self); } @@ -307,8 +314,8 @@ impl Engine { /// * `parse` is the parsing function. /// * `func` is the implementation function. /// - /// All custom keywords must be manually registered via [`Engine::register_custom_operator`]. - /// Otherwise, custom keywords won't be recognized. + /// All custom keywords used as symbols must be manually registered via [`Engine::register_custom_operator`]. + /// Otherwise, they won't be recognized. pub fn register_custom_syntax_raw( &mut self, key: impl Into, diff --git a/src/dynamic.rs b/src/dynamic.rs index 86eb0487..a71ecca6 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -34,8 +34,8 @@ use fmt::Debug; #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] use instant::Instant; -/// The message: never fails because the type was checked -const CHECKED: &str = "never fails because the type was checked"; +/// The message: data type was checked +const CHECKED: &str = "data type was checked"; mod private { use crate::fn_native::SendSync; @@ -259,9 +259,7 @@ impl<'d, T: Any + Clone> Deref for DynamicReadLock<'d, T> { match self.0 { DynamicReadLockInner::Reference(ref reference) => *reference, #[cfg(not(feature = "no_closure"))] - DynamicReadLockInner::Guard(ref guard) => guard.downcast_ref().expect( - "never fails because the read guard was created after checking the data type", - ), + DynamicReadLockInner::Guard(ref guard) => guard.downcast_ref().expect(CHECKED), } } } @@ -302,9 +300,7 @@ impl<'d, T: Any + Clone> Deref for DynamicWriteLock<'d, T> { match self.0 { DynamicWriteLockInner::Reference(ref reference) => *reference, #[cfg(not(feature = "no_closure"))] - DynamicWriteLockInner::Guard(ref guard) => guard.downcast_ref().expect( - "never fails because the write guard was created after checking the data type", - ), + DynamicWriteLockInner::Guard(ref guard) => guard.downcast_ref().expect(CHECKED), } } } @@ -315,9 +311,7 @@ impl<'d, T: Any + Clone> DerefMut for DynamicWriteLock<'d, T> { match self.0 { DynamicWriteLockInner::Reference(ref mut reference) => *reference, #[cfg(not(feature = "no_closure"))] - DynamicWriteLockInner::Guard(ref mut guard) => guard.downcast_mut().expect( - "never fails because the write guard was created after checking the data type", - ), + DynamicWriteLockInner::Guard(ref mut guard) => guard.downcast_mut().expect(CHECKED), } } } @@ -1261,7 +1255,7 @@ impl Dynamic { /// /// let x = Dynamic::from(42_u32); /// - /// assert_eq!(x.try_cast::().unwrap(), 42); + /// assert_eq!(x.try_cast::().expect("x should be u32"), 42); /// ``` #[inline] #[must_use] diff --git a/src/engine.rs b/src/engine.rs index 8d9df163..79864466 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -501,7 +501,7 @@ impl<'a> Target<'a> { let value = &mut *value .write_lock::() - .expect("never fails because `BitField` always holds an `INT`"); + .expect("`BitField` holds `INT`"); let index = *index; @@ -529,7 +529,7 @@ impl<'a> Target<'a> { let s = &mut *s .write_lock::() - .expect("never fails because `StringChar` always holds an `ImmutableString`"); + .expect("`StringChar` holds `ImmutableString`"); let index = *index; @@ -553,9 +553,7 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> { // Cloning is cheap for a shared value let container = value.clone(); return Self::LockGuard(( - value - .write_lock::() - .expect("never fails when casting to `Dynamic`"), + value.write_lock::().expect("cast to `Dynamic`"), container, )); } @@ -701,9 +699,9 @@ impl EvalState { // Push a new function resolution cache if the stack is empty self.fn_resolution_caches.push(Default::default()); } - self.fn_resolution_caches.last_mut().expect( - "never fails because there is at least one function resolution cache by this point", - ) + self.fn_resolution_caches + .last_mut() + .expect("at least one function resolution cache") } /// Push an empty function resolution cache onto the stack and make it current. #[allow(dead_code)] @@ -720,7 +718,7 @@ impl EvalState { pub fn pop_fn_resolution_cache(&mut self) { self.fn_resolution_caches .pop() - .expect("there should be at least one function resolution cache"); + .expect("at least one function resolution cache"); } } @@ -1088,16 +1086,10 @@ impl Engine { if let Some(index) = index { let offset = mods.len() - index.get(); - Some( - mods.get(offset) - .expect("never fails because offset should be within range"), - ) + Some(mods.get(offset).expect("offset within range")) } else { mods.find(root) - .map(|n| { - mods.get(n) - .expect("never fails because the index came from `find`") - }) + .map(|n| mods.get(n).expect("index is valid")) .or_else(|| self.global_sub_modules.get(root).cloned()) } } @@ -1191,8 +1183,7 @@ impl Engine { level: 0, }; match resolve_var( - expr.get_variable_name(true) - .expect("`expr` should be `Variable`"), + expr.get_variable_name(true).expect("`expr` is `Variable`"), index, &context, ) { @@ -1209,9 +1200,7 @@ impl Engine { scope.len() - index } else { // Find the variable in the scope - let var_name = expr - .get_variable_name(true) - .expect("`expr` should be `Variable`"); + let var_name = expr.get_variable_name(true).expect("`expr` is `Variable`"); scope .get_index(var_name) .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(var_name.to_string(), var_pos))? @@ -1245,9 +1234,7 @@ impl Engine { let _terminate_chaining = terminate_chaining; // Pop the last index value - let idx_val = idx_values - .pop() - .expect("never fails because an index chain is never empty"); + let idx_val = idx_values.pop().expect("index chain is never empty"); match chain_type { #[cfg(not(feature = "no_index"))] @@ -1255,7 +1242,7 @@ impl Engine { let pos = rhs.position(); let idx_val = idx_val .into_index_value() - .expect("never fails because `chain_type` is `ChainType::Index`"); + .expect("`chain_type` is `ChainType::Index`"); match rhs { // xxx[idx].expr... | xxx[idx][expr]... @@ -1277,7 +1264,7 @@ impl Engine { // xxx[rhs] op= new_val _ if new_val.is_some() => { let ((new_val, new_pos), (op_info, op_pos)) = - new_val.expect("never fails because `new_val` is `Some`"); + new_val.expect("`new_val` is `Some`"); let mut idx_val_for_setter = idx_val.clone(); let try_setter = match self.get_indexed_mut( @@ -1333,7 +1320,7 @@ impl Engine { let FnCallExpr { name, hashes, .. } = x.as_ref(); let call_args = &mut idx_val .into_fn_call_args() - .expect("never fails because `chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`"); + .expect("`chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`"); self.make_method_call( mods, state, lib, name, *hashes, target, call_args, *pos, level, ) @@ -1350,7 +1337,7 @@ impl Engine { Expr::Property(x) if target.is::() && new_val.is_some() => { let (name, pos) = &x.2; let ((new_val, new_pos), (op_info, op_pos)) = - new_val.expect("never fails because `new_val` is `Some`"); + new_val.expect("`new_val` is `Some`"); let index = name.into(); { let val_target = &mut self.get_indexed_mut( @@ -1378,7 +1365,7 @@ impl Engine { Expr::Property(x) if new_val.is_some() => { let ((getter, hash_get), (setter, hash_set), (name, pos)) = x.as_ref(); let ((mut new_val, new_pos), (op_info, op_pos)) = - new_val.expect("never fails because `new_val` is `Some`"); + new_val.expect("`new_val` is `Some`"); if op_info.is_some() { let hash = FnCallHashes::from_native(*hash_get); @@ -1498,9 +1485,9 @@ impl Engine { // {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr Expr::FnCall(ref x, pos) if !x.is_qualified() => { let FnCallExpr { name, hashes, .. } = x.as_ref(); - let call_args = &mut idx_val - .into_fn_call_args() - .expect("never fails because `chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`"); + let call_args = &mut idx_val.into_fn_call_args().expect( + "`chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`", + ); let (val, _) = self.make_method_call( mods, state, lib, name, *hashes, target, call_args, pos, level, )?; @@ -1620,9 +1607,9 @@ impl Engine { Expr::FnCall(ref f, pos) if !f.is_qualified() => { let FnCallExpr { name, hashes, .. } = f.as_ref(); let rhs_chain = match_chaining_type(rhs); - let args = &mut idx_val - .into_fn_call_args() - .expect("never fails because `chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`"); + let args = &mut idx_val.into_fn_call_args().expect( + "`chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`", + ); let (mut val, _) = self.make_method_call( mods, state, lib, name, *hashes, target, args, pos, level, )?; @@ -2117,7 +2104,7 @@ impl Engine { for (Ident { name: key, .. }, expr) in &x.0 { let value_ref = map .get_mut(key.as_str()) - .expect("never fails because the template should contain all the keys"); + .expect("template contains all keys"); *value_ref = self .eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .flatten(); @@ -2135,9 +2122,7 @@ impl Engine { constants, .. } = x.as_ref(); - let namespace = namespace - .as_ref() - .expect("never fails because function call is qualified"); + let namespace = namespace.as_ref().expect("qualified function call"); let hash = hashes.native; self.make_qualified_function_call( scope, mods, state, lib, this_ptr, namespace, name, args, constants, hash, @@ -2192,12 +2177,14 @@ impl Engine { Expr::Custom(custom, _) => { let expressions: StaticVec<_> = custom.keywords.iter().map(Into::into).collect(); - let key_token = custom.tokens.first().expect( - "never fails because a custom syntax stream must contain at least one token", - ); + let key_token = custom + .tokens + .first() + .expect("custom syntax stream contains at least one token"); let custom_def = self - .custom_syntax.get(key_token) - .expect("never fails because the custom syntax leading token should match with definition"); + .custom_syntax + .get(key_token) + .expect("custom syntax leading token matches with definition"); let mut context = EvalContext { engine: self, scope, @@ -2329,9 +2316,7 @@ impl Engine { let target_is_shared = false; if target_is_shared { - lock_guard = target - .write_lock::() - .expect("never fails when casting to `Dynamic`"); + lock_guard = target.write_lock::().expect("cast to `Dynamic`"); lhs_ptr_inner = &mut *lock_guard; } else { lhs_ptr_inner = &mut *target; @@ -2403,7 +2388,7 @@ impl Engine { let var_name = lhs_expr .get_variable_name(false) - .expect("never fails because `lhs_ptr` is a `Variable`s"); + .expect("`lhs_ptr` is `Variable`"); if !lhs_ptr.is_ref() { return EvalAltResult::ErrorAssignmentToConstant(var_name.to_string(), pos) @@ -2667,10 +2652,7 @@ impl Engine { if x > INT::MAX as usize { return EvalAltResult::ErrorArithmetic( format!("for-loop counter overflow: {}", x), - counter - .as_ref() - .expect("never fails because `counter` is `Some`") - .pos, + counter.as_ref().expect("`counter` is `Some`").pos, ) .into(); } @@ -2678,7 +2660,7 @@ impl Engine { let mut counter_var = scope .get_mut_by_index(c) .write_lock::() - .expect("never fails because the counter always holds an `INT`"); + .expect("counter holds `INT`"); *counter_var = x as INT; } @@ -2691,9 +2673,7 @@ impl Engine { let loop_var_is_shared = false; if loop_var_is_shared { - let mut value_ref = loop_var - .write_lock() - .expect("never fails when casting to `Dynamic`"); + let mut value_ref = loop_var.write_lock().expect("cast to `Dynamic`"); *value_ref = value; } else { *loop_var = value; @@ -2744,9 +2724,7 @@ impl Engine { constants, .. } = x.as_ref(); - let namespace = namespace - .as_ref() - .expect("never fails because function call is qualified"); + let namespace = namespace.as_ref().expect("qualified function call"); let hash = hashes.native; self.make_qualified_function_call( scope, mods, state, lib, this_ptr, namespace, name, args, constants, hash, @@ -2805,11 +2783,16 @@ impl Engine { if err_pos.is_none() { // No position info } else { - let line = err_pos.line().expect("never fails because a non-NONE `Position` always has a line number") as INT; + let line = err_pos + .line() + .expect("non-NONE `Position` has line number") + as INT; let position = if err_pos.is_beginning_of_line() { 0 } else { - err_pos.position().expect("never fails because a non-NONE `Position` always has a character position") + err_pos + .position() + .expect("non-NONE `Position` has character position") } as INT; err_map.insert("line".into(), line.into()); err_map.insert("position".into(), position.into()); @@ -2893,10 +2876,7 @@ impl Engine { #[cfg(not(feature = "no_function"))] if entry_type == AccessMode::ReadOnly && lib.iter().any(|&m| !m.is_empty()) { let global = if let Some(index) = mods.find(KEYWORD_GLOBAL) { - match mods - .get_mut(index) - .expect("never fails because the index came from `find`") - { + match mods.get_mut(index).expect("index is valid") { m if m.internal => Some(m), _ => None, } @@ -2905,15 +2885,12 @@ impl Engine { let mut global = Module::new(); global.internal = true; mods.push(KEYWORD_GLOBAL, global); - Some( - mods.get_mut(mods.len() - 1) - .expect("never fails because the global module was just added"), - ) + Some(mods.get_mut(mods.len() - 1).expect("global module exists")) }; if let Some(global) = global { Shared::get_mut(global) - .expect("never fails because the global module is never shared") + .expect("global module is not shared") .set_var(name.clone(), value.clone()); } } diff --git a/src/engine_api.rs b/src/engine_api.rs index e8f4a888..20082612 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -937,14 +937,8 @@ impl Engine { } } else { let mut iter = name.as_ref().splitn(2, separator.as_ref()); - let sub_module = iter - .next() - .expect("never fails because the name contains a separator") - .trim(); - let remainder = iter - .next() - .expect("never fails because the name contains a separator") - .trim(); + let sub_module = iter.next().expect("name contains separator").trim(); + let remainder = iter.next().expect("name contains separator").trim(); if !root.contains_key(sub_module) { let mut m: Module = Default::default(); @@ -954,7 +948,7 @@ impl Engine { } else { let m = root .remove(sub_module) - .expect("never fails because the root contains the sub-module"); + .expect("root contains the sub-module"); let mut m = crate::fn_native::shared_take_or_clone(m); register_static_module_raw(m.sub_modules_mut(), remainder, module); m.build_index(); @@ -1059,19 +1053,18 @@ impl Engine { resolver: &StaticModuleResolver, imports: &mut BTreeSet, ) { - ast.walk(&mut |path| match path - .last() - .expect("never fails because `path` always contains the current node") - { - // Collect all `import` statements with a string constant path - ASTNode::Stmt(Stmt::Import(Expr::StringConstant(s, _), _, _)) - if !resolver.contains_path(s) && !imports.contains(s.as_str()) => - { - imports.insert(s.clone().into()); - true - } - _ => true, - }); + ast.walk( + &mut |path| match path.last().expect("`path` contains the current node") { + // Collect all `import` statements with a string constant path + ASTNode::Stmt(Stmt::Import(Expr::StringConstant(s, _), _, _)) + if !resolver.contains_path(s) && !imports.contains(s.as_str()) => + { + imports.insert(s.clone().into()); + true + } + _ => true, + }, + ); } let mut ast = self.compile_scripts_with_scope(scope, &[script])?; @@ -1315,12 +1308,12 @@ impl Engine { /// true)?; /// /// assert_eq!(map.len(), 4); - /// assert_eq!(map["a"].as_int().unwrap(), 123); - /// assert_eq!(map["b"].as_int().unwrap(), 42); + /// assert_eq!(map["a"].as_int().expect("a should exist"), 123); + /// assert_eq!(map["b"].as_int().expect("b should exist"), 42); /// assert!(map["d"].is::<()>()); /// - /// let c = map["c"].read_lock::().unwrap(); - /// assert_eq!(c["x"].as_bool().unwrap(), false); + /// let c = map["c"].read_lock::().expect("c should exist"); + /// assert_eq!(c["x"].as_bool().expect("x should be bool"), false); /// # Ok(()) /// # } /// ``` @@ -1913,7 +1906,7 @@ impl Engine { /// let mut value: Dynamic = 1_i64.into(); /// let result = engine.call_fn_dynamic(&mut scope, &ast, true, "action", Some(&mut value), [ 41_i64.into() ])?; /// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer - /// assert_eq!(value.as_int().unwrap(), 42); + /// assert_eq!(value.as_int().expect("value should be INT"), 42); /// # } /// # Ok(()) /// # } @@ -2018,7 +2011,7 @@ impl Engine { .map(|f| { f.func .get_script_fn_def() - .expect("never fails because the function is scripted") + .expect("scripted function") .clone() }) .collect(); diff --git a/src/engine_settings.rs b/src/engine_settings.rs index e7e000b5..f1558638 100644 --- a/src/engine_settings.rs +++ b/src/engine_settings.rs @@ -279,7 +279,7 @@ impl Engine { /// /// // Register a custom operator called 'foo' and give it /// // a precedence of 160 (i.e. between +|- and *|/). - /// engine.register_custom_operator("foo", 160).unwrap(); + /// engine.register_custom_operator("foo", 160).expect("should succeed"); /// /// // Register a binary function named 'foo' /// engine.register_fn("foo", |x: i64, y: i64| (x * y) - (x + y)); diff --git a/src/error.rs b/src/error.rs index 270bfacd..83ed5dd1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -303,7 +303,7 @@ impl EvalAltResult { format!("{:?}", self) .split('(') .next() - .expect("never fails because the debug format of an error is `ErrorXXX(...)`") + .expect("debug format of error is `ErrorXXX(...)`") .into(), ); diff --git a/src/fn_builtin.rs b/src/fn_builtin.rs index 2230804a..1315d366 100644 --- a/src/fn_builtin.rs +++ b/src/fn_builtin.rs @@ -14,8 +14,8 @@ use crate::FLOAT; #[cfg(feature = "decimal")] use rust_decimal::Decimal; -/// The message: never fails because this is built-in code and the type is already checked -const BUILTIN: &str = "never fails because this is built-in code and the type is already checked"; +/// The message: data type was checked +const BUILTIN: &str = "data type was checked"; /// Is the type a numeric type? #[inline] diff --git a/src/fn_call.rs b/src/fn_call.rs index 4ad24723..ec049173 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -190,17 +190,45 @@ impl Engine { let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic` loop { - let func = lib.iter().find_map(|m| m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { - func, source: m.id_raw().cloned() - })).or_else(|| self.global_namespace.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { - func, source: None - })).or_else(|| self.global_modules.iter().find_map(|m| m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { - func, source: m.id_raw().cloned() - }))).or_else(|| mods.get_fn(hash).map(|(func, source)| FnResolutionCacheEntry { - func: func.clone(), source: source.cloned() - })).or_else(|| self.global_sub_modules.values().find_map(|m| m.get_qualified_fn(hash).cloned().map(|func| FnResolutionCacheEntry { - func, source: m.id_raw().cloned() - }))); + let func = lib + .iter() + .find_map(|m| { + m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { + func, + source: m.id_raw().cloned(), + }) + }) + .or_else(|| { + self.global_namespace + .get_fn(hash) + .cloned() + .map(|func| FnResolutionCacheEntry { func, source: None }) + }) + .or_else(|| { + self.global_modules.iter().find_map(|m| { + m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { + func, + source: m.id_raw().cloned(), + }) + }) + }) + .or_else(|| { + mods.get_fn(hash) + .map(|(func, source)| FnResolutionCacheEntry { + func: func.clone(), + source: source.cloned(), + }) + }) + .or_else(|| { + self.global_sub_modules.values().find_map(|m| { + m.get_qualified_fn(hash).cloned().map(|func| { + FnResolutionCacheEntry { + func, + source: m.id_raw().cloned(), + } + }) + }) + }); match func { // Specific version found @@ -215,17 +243,26 @@ impl Engine { return args.and_then(|args| { if !is_op_assignment { get_builtin_binary_op_fn(fn_name, &args[0], &args[1]).map(|f| { - FnResolutionCacheEntry { func: CallableFunction::from_method( - Box::new(f) as Box - ), source: None } + FnResolutionCacheEntry { + func: CallableFunction::from_method( + Box::new(f) as Box + ), + source: None, + } }) } else { - let (first, second) = args.split_first() - .expect("never fails because an op-assignment must have two arguments"); + let (first, second) = args + .split_first() + .expect("op-assignment has two arguments"); - get_builtin_op_assignment_fn(fn_name, *first, second[0]).map(|f| FnResolutionCacheEntry { - func: CallableFunction::from_method(Box::new(f) as Box), source: None - }) + get_builtin_op_assignment_fn(fn_name, *first, second[0]).map( + |f| FnResolutionCacheEntry { + func: CallableFunction::from_method( + Box::new(f) as Box + ), + source: None, + }, + ) } .map(Box::new) }); @@ -234,17 +271,19 @@ impl Engine { // Try all permutations with `Dynamic` wildcards None => { let hash_params = calc_fn_params_hash( - args.as_ref().expect("never fails because there are no permutations if there are no arguments") - .iter().enumerate().map(|(i, a)| - { - let mask = 1usize << (num_args - i - 1); - if bitmask & mask != 0 { - // Replace with `Dynamic` - TypeId::of::() - } else { - a.type_id() - } - }), + args.as_ref() + .expect("no permutations if no arguments") + .iter() + .enumerate() + .map(|(i, a)| { + let mask = 1usize << (num_args - i - 1); + if bitmask & mask != 0 { + // Replace with `Dynamic` + TypeId::of::() + } else { + a.type_id() + } + }), ); hash = combine_hashes(hash_script, hash_params); @@ -290,7 +329,10 @@ impl Engine { let mut backup: Option = None; if is_method_call && func.is_pure() && !args.is_empty() { backup = Some(Default::default()); - backup.as_mut().unwrap().change_first_arg_to_copy(args); + backup + .as_mut() + .expect("`backup` is `Some`") + .change_first_arg_to_copy(args); } // Run external function @@ -301,12 +343,10 @@ impl Engine { let result = if func.is_plugin_fn() { func.get_plugin_fn() - .expect("never fails because the function is a plugin") + .expect("plugin function") .call((self, name, source, mods, lib).into(), args) } else { - let func = func - .get_native_fn() - .expect("never fails because the function is native"); + let func = func.get_native_fn().expect("native function"); func((self, name, source, mods, lib).into(), args) }; @@ -644,10 +684,8 @@ impl Engine { { let fn_name = args[0] .read_lock::() - .expect("never fails because `args[0]` is `FnPtr`"); - let num_params = args[1] - .as_int() - .expect("never fails because `args[1]` is `INT`"); + .expect("`args[0]` is `FnPtr`"); + let num_params = args[1].as_int().expect("`args[1]` is `INT`"); return Ok(( if num_params < 0 { @@ -691,9 +729,7 @@ impl Engine { // Script function call assert!(func.is_script()); - let func = func - .get_script_fn_def() - .expect("never fails because the function is scripted"); + let func = func.get_script_fn_def().expect("scripted function"); if func.body.is_empty() { return Ok((Dynamic::UNIT, false)); @@ -719,7 +755,7 @@ impl Engine { // Method call of script function - map first argument to `this` let (first, rest) = args .split_first_mut() - .expect("never fails because a method call always has a first parameter"); + .expect("method call has first parameter"); let orig_source = state.source.take(); state.source = source; @@ -748,7 +784,10 @@ impl Engine { let mut backup: Option = None; if is_ref_mut && !args.is_empty() { backup = Some(Default::default()); - backup.as_mut().unwrap().change_first_arg_to_copy(args); + backup + .as_mut() + .expect("`backup` is `Some`") + .change_first_arg_to_copy(args); } let orig_source = state.source.take(); @@ -871,9 +910,7 @@ impl Engine { let (result, updated) = match fn_name { KEYWORD_FN_PTR_CALL if target.is::() => { // FnPtr call - let fn_ptr = target - .read_lock::() - .expect("never fails because `obj` is `FnPtr`"); + let fn_ptr = target.read_lock::().expect("`obj` is `FnPtr`"); // Redirect function name let fn_name = fn_ptr.fn_name(); let args_len = call_args.len() + fn_ptr.curry().len(); @@ -938,9 +975,7 @@ impl Engine { )); } - let fn_ptr = target - .read_lock::() - .expect("never fails because `obj` is `FnPtr`"); + let fn_ptr = target.read_lock::().expect("`obj` is `FnPtr`"); // Curry call Ok(( @@ -1264,7 +1299,7 @@ impl Engine { } else { // Turn it into a method call only if the object is not shared and not a simple value is_ref_mut = true; - let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared"); + let obj_ref = target.take_ref().expect("`target` is reference"); args.push(obj_ref); args.extend(arg_values.iter_mut()); } @@ -1345,9 +1380,9 @@ impl Engine { // Turn it into a method call only if the object is not shared and not a simple value let (first, rest) = arg_values .split_first_mut() - .expect("never fails because the arguments list is not empty"); + .expect("arguments list is not empty"); first_arg_value = Some(first); - let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared"); + let obj_ref = target.take_ref().expect("`target` is reference"); args.push(obj_ref); args.extend(rest.iter_mut()); } @@ -1393,9 +1428,7 @@ impl Engine { match func { #[cfg(not(feature = "no_function"))] Some(f) if f.is_script() => { - let fn_def = f - .get_script_fn_def() - .expect("never fails because the function is scripted"); + let fn_def = f.get_script_fn_def().expect("scripted function"); if fn_def.body.is_empty() { Ok(Dynamic::UNIT) @@ -1419,15 +1452,13 @@ impl Engine { Some(f) if f.is_plugin_fn() => f .get_plugin_fn() - .expect("never fails because the function is a plugin") + .expect("plugin function") .clone() .call((self, fn_name, module.id(), &*mods, lib).into(), &mut args) .map_err(|err| err.fill_position(pos)), Some(f) if f.is_native() => { - let func = f - .get_native_fn() - .expect("never fails because the function is native"); + let func = f.get_native_fn().expect("native function"); func((self, fn_name, module.id(), &*mods, lib).into(), &mut args) .map_err(|err| err.fill_position(pos)) } diff --git a/src/fn_native.rs b/src/fn_native.rs index c7d8cdbd..cf7b9d1c 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -259,7 +259,7 @@ pub fn shared_try_take(value: Shared) -> Result> { pub fn shared_take(value: Shared) -> T { shared_try_take(value) .ok() - .expect("resource should have no outstanding references") + .expect("no outstanding references") } /// A general function trail object. diff --git a/src/fn_register.rs b/src/fn_register.rs index 592c3cac..c20263ff 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -34,8 +34,7 @@ pub struct Mut(T); #[must_use] pub fn by_ref(data: &mut Dynamic) -> DynamicWriteLock { // Directly cast the &mut Dynamic into DynamicWriteLock to access the underlying data. - data.write_lock::() - .expect("never fails because the type was checked") + data.write_lock::().expect("data type was checked") } /// Dereference into value. @@ -47,15 +46,15 @@ pub fn by_value(data: &mut Dynamic) -> T { data.flatten_in_place(); let ref_str = data .as_str_ref() - .expect("never fails because argument passed by value should not be shared"); + .expect("argument passed by value is not shared"); let ref_t = unsafe { mem::transmute::<_, &T>(&ref_str) }; ref_t.clone() } else if TypeId::of::() == TypeId::of::() { // If T is `String`, data must be `ImmutableString`, so map directly to it let value = mem::take(data) .into_string() - .expect("never fails because the type was checked"); - unsafe_try_cast(value).expect("never fails because the type was checked") + .expect("data type was checked"); + unsafe_try_cast(value).expect("data type was checked") } else { // We consume the argument and then replace it with () - the argument is not supposed to be used again. // This way, we avoid having to clone the argument again, because it is already a clone when passed here. @@ -131,7 +130,7 @@ macro_rules! def_register { // The arguments are assumed to be of the correct number and types! let mut _drain = args.iter_mut(); - $($let $par = ($clone)(_drain.next().expect("never fails because arguments list is fixed")); )* + $($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )* // Call the function with each argument value let r = self($($arg),*); @@ -159,7 +158,7 @@ macro_rules! def_register { // The arguments are assumed to be of the correct number and types! let mut _drain = args.iter_mut(); - $($let $par = ($clone)(_drain.next().expect("never fails because arguments list is fixed")); )* + $($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )* // Call the function with each argument value let r = self(ctx, $($arg),*); @@ -187,7 +186,7 @@ macro_rules! def_register { // The arguments are assumed to be of the correct number and types! let mut _drain = args.iter_mut(); - $($let $par = ($clone)(_drain.next().expect("never fails because arguments list is fixed")); )* + $($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )* // Call the function with each argument value self($($arg),*).map(Dynamic::from) @@ -212,7 +211,7 @@ macro_rules! def_register { // The arguments are assumed to be of the correct number and types! let mut _drain = args.iter_mut(); - $($let $par = ($clone)(_drain.next().expect("never fails because arguments list is fixed")); )* + $($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )* // Call the function with each argument value self(ctx, $($arg),*).map(Dynamic::from) diff --git a/src/module/mod.rs b/src/module/mod.rs index 3e80a579..f02391d7 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -238,7 +238,7 @@ impl Module { /// # use rhai::Module; /// let mut module = Module::new(); /// module.set_var("answer", 42_i64); - /// assert_eq!(module.get_var_value::("answer").unwrap(), 42); + /// assert_eq!(module.get_var_value::("answer").expect("answer should exist"), 42); /// ``` #[inline(always)] #[must_use] @@ -400,7 +400,7 @@ impl Module { /// # use rhai::Module; /// let mut module = Module::new(); /// module.set_var("answer", 42_i64); - /// assert_eq!(module.get_var_value::("answer").unwrap(), 42); + /// assert_eq!(module.get_var_value::("answer").expect("answer should exist"), 42); /// ``` #[inline(always)] #[must_use] @@ -416,7 +416,7 @@ impl Module { /// # use rhai::Module; /// let mut module = Module::new(); /// module.set_var("answer", 42_i64); - /// assert_eq!(module.get_var("answer").unwrap().cast::(), 42); + /// assert_eq!(module.get_var("answer").expect("answer should exist").cast::(), 42); /// ``` #[inline(always)] #[must_use] @@ -434,7 +434,7 @@ impl Module { /// # use rhai::Module; /// let mut module = Module::new(); /// module.set_var("answer", 42_i64); - /// assert_eq!(module.get_var_value::("answer").unwrap(), 42); + /// assert_eq!(module.get_var_value::("answer").expect("answer should exist"), 42); /// ``` #[inline] pub fn set_var( @@ -1337,9 +1337,7 @@ impl Module { f.access, f.name.as_str(), f.params, - f.func - .get_script_fn_def() - .expect("never fails because the function is scripted"), + f.func.get_script_fn_def().expect("scripted function"), ) }) } @@ -1407,7 +1405,7 @@ impl Module { /// let ast = engine.compile("let answer = 42; export answer;")?; /// let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?; /// assert!(module.contains_var("answer")); - /// assert_eq!(module.get_var_value::("answer").unwrap(), 42); + /// assert_eq!(module.get_var_value::("answer").expect("answer should exist"), 42); /// # Ok(()) /// # } /// ``` @@ -1431,9 +1429,7 @@ impl Module { match aliases.len() { 0 => (), 1 => { - let alias = aliases - .pop() - .expect("never fails because the list has one item"); + let alias = aliases.pop().expect("list has one item"); module.set_var(alias, value); } _ => aliases.into_iter().for_each(|alias| { @@ -1465,7 +1461,7 @@ impl Module { let mut func = f .func .get_script_fn_def() - .expect("never fails because the function is scripted") + .expect("scripted function") .as_ref() .clone(); func.lib = Some(ast.shared_lib()); diff --git a/src/optimize.rs b/src/optimize.rs index 299098c0..5225eb61 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -282,18 +282,23 @@ fn optimize_stmt_block( if reduce_return && !last_stmt.returns_value() => { state.set_dirty(); - statements.pop().unwrap(); + statements + .pop() + .expect("`statements` contains at least two elements"); } // { ...; return val; } -> { ...; val } [.., Stmt::Return(crate::ast::ReturnType::Return, ref mut expr, pos)] if reduce_return => { state.set_dirty(); - *statements.last_mut().unwrap() = if let Some(expr) = expr { - Stmt::Expr(mem::take(expr)) - } else { - Stmt::Noop(pos) - }; + *statements + .last_mut() + .expect("`statements` contains at least two elements") = + if let Some(expr) = expr { + Stmt::Expr(mem::take(expr)) + } else { + Stmt::Noop(pos) + }; } // { ...; stmt; noop } -> done [.., ref second_last_stmt, Stmt::Noop(_)] @@ -308,9 +313,14 @@ fn optimize_stmt_block( { state.set_dirty(); if second_last_stmt.returns_value() { - *statements.last_mut().unwrap() = Stmt::Noop(last_stmt.position()); + *statements + .last_mut() + .expect("`statements` contains at least two elements") = + Stmt::Noop(last_stmt.position()); } else { - statements.pop().unwrap(); + statements + .pop() + .expect("`statements` contains at least two elements"); } } _ => break, @@ -328,18 +338,24 @@ fn optimize_stmt_block( if reduce_return => { state.set_dirty(); - statements.pop().unwrap(); + statements + .pop() + .expect("`statements` contains at least two elements"); } // { ...; return pure_val; } -> { ... } [.., Stmt::Return(crate::ast::ReturnType::Return, Some(ref expr), _)] if reduce_return && expr.is_pure() => { state.set_dirty(); - statements.pop().unwrap(); + statements + .pop() + .expect("`statements` contains at least two elements"); } [.., ref last_stmt] if is_pure(last_stmt) => { state.set_dirty(); - statements.pop().unwrap(); + statements + .pop() + .expect("`statements` contains at least one element"); } _ => break, } @@ -381,14 +397,18 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b match x.2 { Expr::FnCall(ref mut x2, _) => { state.set_dirty(); - let op = Token::lookup_from_syntax(&x2.name).unwrap(); - let op_assignment = op.make_op_assignment().unwrap(); + let op = Token::lookup_from_syntax(&x2.name).expect("`x2` is operator"); + let op_assignment = op.make_op_assignment().expect("`op` is operator"); x.1 = Some(OpAssignment::new(op_assignment)); let value = mem::take(&mut x2.args[1]); if let Expr::Stack(slot, pos) = value { - let value = mem::take(x2.constants.get_mut(slot).unwrap()); + let value = mem::take( + x2.constants + .get_mut(slot) + .expect("`constants[slot]` is valid"), + ); x.2 = Expr::from_dynamic(value, pos); } else { x.2 = value; @@ -459,7 +479,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b // switch const { ... } Stmt::Switch(match_expr, x, pos) if match_expr.is_constant() => { - let value = match_expr.get_literal_value().unwrap(); + let value = match_expr + .get_literal_value() + .expect("`match_expr` is constant"); let hasher = &mut get_hasher(); value.hash(hasher); let hash = hasher.finish(); @@ -782,13 +804,13 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { (Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < s.chars().count() => { // String literal indexing - get the character state.set_dirty(); - *expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *pos); + *expr = Expr::CharConstant(s.chars().nth(*i as usize).expect("character position is valid"), *pos); } // string[-int] (Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i < 0 && i.checked_abs().map(|n| n as usize <= s.chars().count()).unwrap_or(false) => { // String literal indexing - get the character state.set_dirty(); - *expr = Expr::CharConstant(s.chars().rev().nth(i.abs() as usize - 1).unwrap(), *pos); + *expr = Expr::CharConstant(s.chars().rev().nth(i.abs() as usize - 1).expect("character position is valid"), *pos); } // var[rhs] (Expr::Variable(_, _, _), rhs) => optimize_expr(rhs, state, true), @@ -855,7 +877,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { #[cfg(not(feature = "no_index"))] Expr::Array(_, _) if expr.is_constant() => { state.set_dirty(); - *expr = Expr::DynamicConstant(expr.get_literal_value().unwrap().into(), expr.position()); + *expr = Expr::DynamicConstant(expr.get_literal_value().expect("`expr` is constant").into(), expr.position()); } // [ items .. ] #[cfg(not(feature = "no_index"))] @@ -864,7 +886,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { #[cfg(not(feature = "no_object"))] Expr::Map(_, _) if expr.is_constant() => { state.set_dirty(); - *expr = Expr::DynamicConstant(expr.get_literal_value().unwrap().into(), expr.position()); + *expr = Expr::DynamicConstant(expr.get_literal_value().expect("`expr` is constant").into(), expr.position()); } // #{ key:value, .. } #[cfg(not(feature = "no_object"))] @@ -935,7 +957,10 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { if let Some(fn_name) = fn_name { if fn_name.is::() { state.set_dirty(); - let fn_ptr = FnPtr::new_unchecked(fn_name.as_str_ref().unwrap().into(), Default::default()); + let fn_ptr = FnPtr::new_unchecked( + fn_name.as_str_ref().expect("`fn_name` is `ImmutableString`").into(), + Default::default() + ); *expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), *pos); } } @@ -955,7 +980,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { => { let arg_values = &mut x.args.iter().map(|e| match e { Expr::Stack(slot, _) => x.constants[*slot].clone(), - _ => e.get_literal_value().unwrap() + _ => e.get_literal_value().expect("`e` is constant") }).collect::>(); let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect(); @@ -969,7 +994,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1]) .and_then(|f| { let ctx = (state.engine, x.name.as_ref(), state.lib).into(); - let (first, second) = arg_values.split_first_mut().unwrap(); + let (first, second) = arg_values.split_first_mut().expect("`arg_values` is not empty"); (f)(ctx, &mut [ first, &mut second[0] ]).ok() }) } @@ -1009,7 +1034,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { if !has_script_fn { let arg_values = &mut x.args.iter().map(|e| match e { Expr::Stack(slot, _) => x.constants[*slot].clone(), - _ => e.get_literal_value().unwrap() + _ => e.get_literal_value().expect("`e` is constant") }).collect::>(); let result = match x.name.as_str() { @@ -1044,7 +1069,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { // constant-name Expr::Variable(_, pos, x) if x.1.is_none() && state.find_constant(&x.2).is_some() => { // Replace constant with value - *expr = Expr::from_dynamic(state.find_constant(&x.2).unwrap().clone(), *pos); + *expr = Expr::from_dynamic(state.find_constant(&x.2).expect("constant exists").clone(), *pos); state.set_dirty(); } diff --git a/src/packages/fn_basic.rs b/src/packages/fn_basic.rs index dbe86112..e4496762 100644 --- a/src/packages/fn_basic.rs +++ b/src/packages/fn_basic.rs @@ -45,7 +45,7 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array { namespace: Option, f: &ScriptFnDef, ) -> Map { - const DICT: &str = "never fails because the dictionary is pre-filled with all the keys"; + const DICT: &str = "key exists"; let mut map = Map::new(); diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index 73193a28..71a326a3 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -31,7 +31,7 @@ pub fn print_with_func( match ctx.call_fn_dynamic_raw(fn_name, true, &mut [value]) { Ok(result) if result.is::() => result .into_immutable_string() - .expect("never fails as the result is `ImmutableString`"), + .expect("result is `ImmutableString`"), Ok(result) => ctx.engine().map_type_name(result.type_name()).into(), Err(_) => ctx.engine().map_type_name(value.type_name()).into(), } diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index c72a695a..65980026 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -116,9 +116,7 @@ mod string_functions { #[rhai_fn(name = "to_upper")] pub fn to_upper_char(character: char) -> char { let mut stream = character.to_uppercase(); - let ch = stream - .next() - .expect("never fails because there should be at least one character"); + let ch = stream.next().expect("at least one character"); if stream.next().is_some() { character } else { @@ -134,7 +132,7 @@ mod string_functions { let mut stream = character.to_lowercase(); let ch = stream .next() - .expect("never fails because there should be at least one character"); + .expect("there should be at least one character"); if stream.next().is_some() { character } else { diff --git a/src/parse.rs b/src/parse.rs index 17ddde41..da378114 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -38,8 +38,8 @@ type FunctionsLib = BTreeMap>; /// Invalid variable name that acts as a search barrier in a [`Scope`]. const SCOPE_SEARCH_BARRIER_MARKER: &str = "$BARRIER$"; -/// The message: never fails because `TokenStream` never ends -const NEVER_ENDS: &str = "never fails because `TokenStream` never ends"; +/// The message: `TokenStream` never ends +const NEVER_ENDS: &str = "`TokenStream` never ends"; /// A factory of identifiers from text strings. /// @@ -1602,9 +1602,7 @@ fn make_assignment_stmt( let index = i.map_or_else( || { index - .expect( - "never fails because the long index is `Some` when the short index is `None`", - ) + .expect("the long index is `Some` when the short index is `None`") .get() }, |n| n.get() as usize, @@ -1695,8 +1693,9 @@ fn make_dot_expr( } // lhs.module::id - syntax error (_, Expr::Variable(_, _, x)) => { - return Err(PERR::PropertyExpected - .into_err(x.1.expect("never fails because the namespace is `Some`").0[0].pos)) + return Err( + PERR::PropertyExpected.into_err(x.1.expect("the namespace is `Some`").0[0].pos) + ) } // lhs.prop (lhs, prop @ Expr::Property(_)) => { @@ -1901,12 +1900,8 @@ fn parse_binary_op( | Token::GreaterThanEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos), Token::Or => { - let rhs = args - .pop() - .expect("never fails because `||` has two arguments"); - let current_lhs = args - .pop() - .expect("never fails because `||` has two arguments"); + let rhs = args.pop().expect("`||` has two arguments"); + let current_lhs = args.pop().expect("`||` has two arguments"); Expr::Or( BinaryExpr { lhs: current_lhs.ensure_bool_expr()?, @@ -1917,12 +1912,8 @@ fn parse_binary_op( ) } Token::And => { - let rhs = args - .pop() - .expect("never fails because `&&` has two arguments"); - let current_lhs = args - .pop() - .expect("never fails because `&&` has two arguments"); + let rhs = args.pop().expect("`&&` has two arguments"); + let current_lhs = args.pop().expect("`&&` has two arguments"); Expr::And( BinaryExpr { lhs: current_lhs.ensure_bool_expr()?, @@ -2391,7 +2382,7 @@ fn parse_for( }, counter_var.map(|name| Ident { name, - pos: counter_pos.expect("never fails because `counter_var` is `Some`"), + pos: counter_pos.expect("`counter_var` is `Some`"), }), body.into(), )), diff --git a/src/scope.rs b/src/scope.rs index cb13ccab..323d78fd 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -32,8 +32,8 @@ const SCOPE_ENTRIES_INLINED: usize = 8; /// /// assert_eq!(engine.eval_with_scope::(&mut my_scope, "x + 1")?, 42); /// -/// assert_eq!(my_scope.get_value::("x").unwrap(), 41); -/// assert_eq!(my_scope.get_value::("z").unwrap(), 0); +/// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 41); +/// assert_eq!(my_scope.get_value::("z").expect("z should exist"), 0); /// # Ok(()) /// # } /// ``` @@ -85,7 +85,7 @@ impl<'a> Scope<'a> { /// let mut my_scope = Scope::new(); /// /// my_scope.push("x", 42_i64); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 42); /// ``` #[inline(always)] #[must_use] @@ -163,7 +163,7 @@ impl<'a> Scope<'a> { /// let mut my_scope = Scope::new(); /// /// my_scope.push("x", 42_i64); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 42); /// ``` #[inline(always)] pub fn push( @@ -183,7 +183,7 @@ impl<'a> Scope<'a> { /// let mut my_scope = Scope::new(); /// /// my_scope.push_dynamic("x", Dynamic::from(42_i64)); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 42); /// ``` #[inline(always)] pub fn push_dynamic(&mut self, name: impl Into>, value: Dynamic) -> &mut Self { @@ -202,7 +202,7 @@ impl<'a> Scope<'a> { /// let mut my_scope = Scope::new(); /// /// my_scope.push_constant("x", 42_i64); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 42); /// ``` #[inline(always)] pub fn push_constant( @@ -225,7 +225,7 @@ impl<'a> Scope<'a> { /// let mut my_scope = Scope::new(); /// /// my_scope.push_constant_dynamic("x", Dynamic::from(42_i64)); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 42); /// ``` #[inline(always)] pub fn push_constant_dynamic( @@ -327,7 +327,7 @@ impl<'a> Scope<'a> { /// let mut my_scope = Scope::new(); /// /// my_scope.push("x", 42_i64); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 42); /// ``` #[inline] #[must_use] @@ -377,15 +377,15 @@ impl<'a> Scope<'a> { /// let mut my_scope = Scope::new(); /// /// my_scope.set_or_push("x", 42_i64); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 42); /// assert_eq!(my_scope.len(), 1); /// /// my_scope.set_or_push("x", 0_i64); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 0); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 0); /// assert_eq!(my_scope.len(), 1); /// /// my_scope.set_or_push("y", 123_i64); - /// assert_eq!(my_scope.get_value::("y").unwrap(), 123); + /// assert_eq!(my_scope.get_value::("y").expect("y should exist"), 123); /// assert_eq!(my_scope.len(), 2); /// ``` #[inline] @@ -399,10 +399,7 @@ impl<'a> Scope<'a> { self.push(name, value); } Some((index, AccessMode::ReadWrite)) => { - let value_ref = self - .values - .get_mut(index) - .expect("never fails because the index is returned by `get_index`"); + let value_ref = self.values.get_mut(index).expect("index is valid"); *value_ref = Dynamic::from(value); } } @@ -425,10 +422,10 @@ impl<'a> Scope<'a> { /// let mut my_scope = Scope::new(); /// /// my_scope.push("x", 42_i64); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 42); /// /// my_scope.set_value("x", 0_i64); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 0); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 0); /// ``` #[inline] pub fn set_value( @@ -442,10 +439,7 @@ impl<'a> Scope<'a> { } Some((_, AccessMode::ReadOnly)) => panic!("variable {} is constant", name.as_ref()), Some((index, AccessMode::ReadWrite)) => { - let value_ref = self - .values - .get_mut(index) - .expect("never fails because the index is returned by `get_index`"); + let value_ref = self.values.get_mut(index).expect("index is valid"); *value_ref = Dynamic::from(value); } } @@ -464,12 +458,12 @@ impl<'a> Scope<'a> { /// let mut my_scope = Scope::new(); /// /// my_scope.push("x", 42_i64); - /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 42); /// - /// let ptr = my_scope.get_mut("x").unwrap(); + /// let ptr = my_scope.get_mut("x").expect("x should exist"); /// *ptr = 123_i64.into(); /// - /// assert_eq!(my_scope.get_value::("x").unwrap(), 123); + /// assert_eq!(my_scope.get_value::("x").expect("x should exist"), 123); /// ``` #[inline] #[must_use] @@ -488,9 +482,7 @@ impl<'a> Scope<'a> { #[inline(always)] #[must_use] pub(crate) fn get_mut_by_index(&mut self, index: usize) -> &mut Dynamic { - self.values - .get_mut(index) - .expect("never fails unless the index is out of bounds") + self.values.get_mut(index).expect("index is out of bounds") } /// Update the access type of an entry in the [`Scope`]. /// @@ -500,10 +492,7 @@ impl<'a> Scope<'a> { #[cfg(not(feature = "no_module"))] #[inline] pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self { - let (_, aliases) = self - .names - .get_mut(index) - .expect("never fails unless the index is out of bounds"); + let (_, aliases) = self.names.get_mut(index).expect("index is out of bounds"); match aliases { None => { let mut list = StaticVec::new(); @@ -563,12 +552,12 @@ impl<'a> Scope<'a> { /// /// let mut iter = my_scope.iter(); /// - /// let (name, is_constant, value) = iter.next().unwrap(); + /// let (name, is_constant, value) = iter.next().expect("value should exist"); /// assert_eq!(name, "x"); /// assert!(!is_constant); /// assert_eq!(value.cast::(), 42); /// - /// let (name, is_constant, value) = iter.next().unwrap(); + /// let (name, is_constant, value) = iter.next().expect("value should exist"); /// assert_eq!(name, "foo"); /// assert!(is_constant); /// assert_eq!(value.cast::(), "hello"); diff --git a/src/serde/de.rs b/src/serde/de.rs index 36c27e07..3dfc2548 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -568,7 +568,7 @@ where ) -> Result> { // Deserialize each value item coming out of the iterator. seed.deserialize(&mut DynamicDeserializer::from_dynamic( - self.values.next().unwrap(), + self.values.next().expect("value should exist"), )) } } diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index 9c7655f3..a0ae10df 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -53,21 +53,27 @@ struct FnParam { impl PartialOrd for FnParam { fn partial_cmp(&self, other: &Self) -> Option { - Some(match self.name.partial_cmp(&other.name).unwrap() { - Ordering::Less => Ordering::Less, - Ordering::Greater => Ordering::Greater, - Ordering::Equal => match (self.typ.is_none(), other.typ.is_none()) { - (true, true) => Ordering::Equal, - (true, false) => Ordering::Greater, - (false, true) => Ordering::Less, - (false, false) => self - .typ - .as_ref() - .unwrap() - .partial_cmp(other.typ.as_ref().unwrap()) - .unwrap(), + Some( + match self + .name + .partial_cmp(&other.name) + .expect("String::partial_cmp should succeed") + { + Ordering::Less => Ordering::Less, + Ordering::Greater => Ordering::Greater, + Ordering::Equal => match (self.typ.is_none(), other.typ.is_none()) { + (true, true) => Ordering::Equal, + (true, false) => Ordering::Greater, + (false, true) => Ordering::Less, + (false, false) => self + .typ + .as_ref() + .expect("`typ` is not `None`") + .partial_cmp(other.typ.as_ref().expect("`typ` is not `None`")) + .expect("String::partial_cmp should succeed"), + }, }, - }) + ) } } @@ -157,7 +163,7 @@ impl From<&crate::module::FuncInfo> for FnMetadata { { info.func .get_script_fn_def() - .expect("never fails because the function is scripted") + .expect("scripted function") .comments .to_vec() } diff --git a/src/token.rs b/src/token.rs index 61c447aa..c52a3eb2 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1207,7 +1207,7 @@ pub fn parse_string_literal( { let start_position = start .position() - .expect("never fails because the string must have a starting position"); + .expect("string must have starting position"); skip_whitespace_until = start_position + 1; } } @@ -1229,9 +1229,7 @@ pub fn parse_string_literal( // Whitespace to skip #[cfg(not(feature = "no_position"))] _ if next_char.is_whitespace() - && pos - .position() - .expect("never fails because a character must have a position") + && pos.position().expect("character must have position") < skip_whitespace_until => {} // All other characters @@ -1379,16 +1377,12 @@ fn get_next_token_inner( #[cfg(not(feature = "no_function"))] #[cfg(feature = "metadata")] - let return_comment = return_comment - || is_doc_comment( - comment - .as_ref() - .expect("never fails because `include_comments` is true"), - ); + let return_comment = + return_comment || is_doc_comment(comment.as_ref().expect("`include_comments` is true")); if return_comment { return Some(( - Token::Comment(comment.expect("never fails because `return_comment` is true")), + Token::Comment(comment.expect("`return_comment` is true")), start_pos, )); } @@ -1440,7 +1434,7 @@ fn get_next_token_inner( } #[cfg(any(not(feature = "no_float"), feature = "decimal"))] '.' => { - stream.get_next().expect("never fails because it is `.`"); + stream.get_next().expect("it is `.`"); // Check if followed by digits or something that cannot start a property name match stream.peek_next().unwrap_or('\0') { @@ -1474,7 +1468,7 @@ fn get_next_token_inner( } #[cfg(not(feature = "no_float"))] 'e' => { - stream.get_next().expect("never fails it is `e`"); + stream.get_next().expect("it is `e`"); // Check if followed by digits or +/- match stream.peek_next().unwrap_or('\0') { @@ -1487,11 +1481,7 @@ fn get_next_token_inner( '+' | '-' => { result.push(next_char); pos.advance(); - result.push( - stream - .get_next() - .expect("never fails because it is `+` or `-`"), - ); + result.push(stream.get_next().expect("it is `+` or `-`")); pos.advance(); } // Not a floating-point number @@ -1639,7 +1629,7 @@ fn get_next_token_inner( |(err, err_pos)| (Token::LexError(err), err_pos), |(result, _)| { let mut chars = result.chars(); - let first = chars.next().unwrap(); + let first = chars.next().expect("`chars` is not empty"); if chars.next().is_some() { (Token::LexError(LERR::MalformedChar(result)), start_pos) From 6f3de4c803abf6977cc51f5fd36fd3262dd6ba33 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 27 Aug 2021 12:10:58 +0800 Subject: [PATCH 4/8] Fix doc test. --- src/engine_api.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine_api.rs b/src/engine_api.rs index 20082612..cca1d706 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -208,6 +208,7 @@ impl Engine { /// // Use `register_fn` to register methods on the type. /// .register_fn("update", TestStruct::update); /// + /// # #[cfg(not(feature = "no_object"))] /// assert_eq!( /// engine.eval::("let x = new_ts(); x.update(41); x")?, /// TestStruct { field: 42 } From 6faa6358f0d51f682052dd0becfd2f4f4fe6c8d6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 30 Aug 2021 10:09:28 +0800 Subject: [PATCH 5/8] Simplify code by merging Engine::global_namespace with Engine::global_modules. --- src/engine.rs | 18 +++++++----------- src/engine_api.rs | 18 ++++++++++++++---- src/fn_call.rs | 8 -------- src/optimize.rs | 6 ++---- 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 79864466..abe08f76 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -898,8 +898,6 @@ impl<'x, 'px, 'pt> EvalContext<'_, 'x, 'px, '_, '_, '_, '_, 'pt> { /// # } /// ``` pub struct Engine { - /// A module containing all functions directly loaded into the Engine. - pub(crate) global_namespace: Module, /// A collection of all modules loaded into the global namespace of the Engine. pub(crate) global_modules: StaticVec>, /// A collection of all sub-modules directly loaded into the Engine. @@ -1034,7 +1032,6 @@ impl Engine { #[must_use] pub fn new_raw() -> Self { let mut engine = Self { - global_namespace: Default::default(), global_modules: Default::default(), global_sub_modules: Default::default(), @@ -1061,7 +1058,10 @@ impl Engine { limits: Default::default(), }; - engine.global_namespace.internal = true; + // Add the global namespace module + let mut global_namespace = Module::new(); + global_namespace.internal = true; + engine.global_modules.push(global_namespace.into()); engine } @@ -2618,13 +2618,9 @@ impl Engine { // 3) Imported modules - functions marked with global namespace // 4) Global sub-modules - functions marked with global namespace let func = self - .global_namespace - .get_iter(iter_type) - .or_else(|| { - self.global_modules - .iter() - .find_map(|m| m.get_iter(iter_type)) - }) + .global_modules + .iter() + .find_map(|m| m.get_iter(iter_type)) .or_else(|| mods.get_iter(iter_type)) .or_else(|| { self.global_sub_modules diff --git a/src/engine_api.rs b/src/engine_api.rs index cca1d706..8e6175b0 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -22,6 +22,16 @@ use crate::Array; use crate::Map; impl Engine { + /// Get the global namespace module (which is the last module in `global_modules`). + #[inline(always)] + fn global_namespace(&mut self) -> &mut Module { + Shared::get_mut( + self.global_modules + .last_mut() + .expect("global_modules contains at least one module"), + ) + .expect("global namespace module is never shared") + } /// Register a custom function with the [`Engine`]. /// /// # Example @@ -74,7 +84,7 @@ impl Engine { #[cfg(not(feature = "metadata"))] let param_type_names: Option<[&str; 0]> = None; - self.global_namespace.set_fn( + self.global_namespace().set_fn( name, FnNamespace::Global, FnAccess::Public, @@ -132,7 +142,7 @@ impl Engine { #[cfg(not(feature = "metadata"))] let param_type_names: Option<[&str; 0]> = None; - self.global_namespace.set_fn( + self.global_namespace().set_fn( name, FnNamespace::Global, FnAccess::Public, @@ -171,7 +181,7 @@ impl Engine { N: AsRef + Into, T: Variant + Clone, { - self.global_namespace.set_raw_fn( + self.global_namespace().set_raw_fn( name, FnNamespace::Global, FnAccess::Public, @@ -275,7 +285,7 @@ impl Engine { T: Variant + Clone + IntoIterator, ::Item: Variant + Clone, { - self.global_namespace.set_iterable::(); + self.global_namespace().set_iterable::(); self } /// Register a getter function for a member of a registered type with the [`Engine`]. diff --git a/src/fn_call.rs b/src/fn_call.rs index ec049173..a3e97465 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -198,12 +198,6 @@ impl Engine { source: m.id_raw().cloned(), }) }) - .or_else(|| { - self.global_namespace - .get_fn(hash) - .cloned() - .map(|func| FnResolutionCacheEntry { func, source: None }) - }) .or_else(|| { self.global_modules.iter().find_map(|m| { m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { @@ -619,8 +613,6 @@ impl Engine { // First check script-defined functions let result = lib.iter().any(|&m| m.contains_fn(hash_script)) - // Then check registered functions - || self.global_namespace.contains_fn(hash_script) // Then check packages || self.global_modules.iter().any(|m| m.contains_fn(hash_script)) // Then check imported modules diff --git a/src/optimize.rs b/src/optimize.rs index 5225eb61..32c90183 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -148,10 +148,8 @@ impl<'a> OptimizerState<'a> { let hash_params = calc_fn_params_hash(arg_types.iter().cloned()); let hash = combine_hashes(hash_script, hash_params); - // First check registered functions - self.engine.global_namespace.contains_fn(hash) - // Then check packages - || self.engine.global_modules.iter().any(|m| m.contains_fn(hash)) + // First check packages + self.engine.global_modules.iter().any(|m| m.contains_fn(hash)) // Then check sub-modules || self.engine.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash)) } From a95f07fef52c095285dc2dc50f2f967fc69cdf80 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 30 Aug 2021 10:14:41 +0800 Subject: [PATCH 6/8] Revise CPU/OS support line. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e4746f9f..f63abb9d 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,12 @@ Rhai is an embedded scripting language and evaluation engine for Rust that gives to add scripting to any application. -Supported targets and builds ---------------------------- +Targets and builds +------------------ -* All common CPU targets for Windows, Linux and MacOS. -* WebAssembly (WASM) -* `no-std` +* All CPU and O/S targets supported by Rust, including: + * WebAssembly (WASM) + * `no-std` * Minimum Rust version 1.49 From b6d38a8fc9131378b789d415bc846cbdf3e2275f Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 30 Aug 2021 10:25:24 +0800 Subject: [PATCH 7/8] Fix metadata build. --- .../rhai_fn_non_clonable_return.stderr | 4 ++-- src/engine_api.rs | 22 ++++++++++++++----- src/serde/metadata.rs | 3 ++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/codegen/ui_tests/rhai_fn_non_clonable_return.stderr b/codegen/ui_tests/rhai_fn_non_clonable_return.stderr index f5a3d29c..f2733fce 100644 --- a/codegen/ui_tests/rhai_fn_non_clonable_return.stderr +++ b/codegen/ui_tests/rhai_fn_non_clonable_return.stderr @@ -5,7 +5,7 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable` | note: required by a bound in `rhai::Dynamic::from` - --> $DIR/dynamic.rs:1127:30 + --> $DIR/dynamic.rs:1121:30 | -1127 | pub fn from(mut value: T) -> Self { +1121 | pub fn from(mut value: T) -> Self { | ^^^^^ required by this bound in `rhai::Dynamic::from` diff --git a/src/engine_api.rs b/src/engine_api.rs index 8e6175b0..18918215 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -24,7 +24,16 @@ use crate::Map; impl Engine { /// Get the global namespace module (which is the last module in `global_modules`). #[inline(always)] - fn global_namespace(&mut self) -> &mut Module { + #[allow(dead_code)] + pub(crate) fn global_namespace(&self) -> &Module { + self.global_modules + .last() + .expect("global_modules contains at least one module") + } + /// Get a mutable reference to the global namespace module + /// (which is the last module in `global_modules`). + #[inline(always)] + pub(crate) fn global_namespace_mut(&mut self) -> &mut Module { Shared::get_mut( self.global_modules .last_mut() @@ -84,7 +93,7 @@ impl Engine { #[cfg(not(feature = "metadata"))] let param_type_names: Option<[&str; 0]> = None; - self.global_namespace().set_fn( + self.global_namespace_mut().set_fn( name, FnNamespace::Global, FnAccess::Public, @@ -142,7 +151,7 @@ impl Engine { #[cfg(not(feature = "metadata"))] let param_type_names: Option<[&str; 0]> = None; - self.global_namespace().set_fn( + self.global_namespace_mut().set_fn( name, FnNamespace::Global, FnAccess::Public, @@ -181,7 +190,7 @@ impl Engine { N: AsRef + Into, T: Variant + Clone, { - self.global_namespace().set_raw_fn( + self.global_namespace_mut().set_raw_fn( name, FnNamespace::Global, FnAccess::Public, @@ -285,7 +294,7 @@ impl Engine { T: Variant + Clone + IntoIterator, ::Item: Variant + Clone, { - self.global_namespace().set_iterable::(); + self.global_namespace_mut().set_iterable::(); self } /// Register a getter function for a member of a registered type with the [`Engine`]. @@ -2046,7 +2055,7 @@ impl Engine { pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec { let mut signatures: Vec<_> = Default::default(); - signatures.extend(self.global_namespace.gen_fn_signatures()); + signatures.extend(self.global_namespace().gen_fn_signatures()); self.global_sub_modules.iter().for_each(|(name, m)| { signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f))) @@ -2056,6 +2065,7 @@ impl Engine { signatures.extend( self.global_modules .iter() + .take(self.global_modules.len() - 1) .flat_map(|m| m.gen_fn_signatures()), ); } diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index a0ae10df..68a96e34 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -244,6 +244,7 @@ impl Engine { if include_global { self.global_modules .iter() + .take(self.global_modules.len() - 1) .flat_map(|m| m.iter_fn()) .for_each(|f| global.functions.push(f.into())); } @@ -252,7 +253,7 @@ impl Engine { global.modules.insert(name.to_string(), m.as_ref().into()); }); - self.global_namespace + self.global_namespace() .iter_fn() .for_each(|f| global.functions.push(f.into())); From cb90ce96d256957c15851e3b522bfe0c1f606c11 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 30 Aug 2021 12:12:25 +0800 Subject: [PATCH 8/8] Fix codegen test. --- codegen/ui_tests/rhai_mod_non_clonable_return.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen/ui_tests/rhai_mod_non_clonable_return.stderr b/codegen/ui_tests/rhai_mod_non_clonable_return.stderr index 17e1ae0e..122d2b26 100644 --- a/codegen/ui_tests/rhai_mod_non_clonable_return.stderr +++ b/codegen/ui_tests/rhai_mod_non_clonable_return.stderr @@ -5,7 +5,7 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable` | note: required by a bound in `rhai::Dynamic::from` - --> $DIR/dynamic.rs:1127:30 + --> $DIR/dynamic.rs:1121:30 | -1127 | pub fn from(mut value: T) -> Self { +1121 | pub fn from(mut value: T) -> Self { | ^^^^^ required by this bound in `rhai::Dynamic::from`