From 0354f154cef8540d1bb516e31e9550f52cd216e1 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 13 Aug 2021 22:47:03 +0800 Subject: [PATCH] Add Scope::is_constant. --- CHANGELOG.md | 1 + src/scope.rs | 24 ++++++++++++++++++++++++ tests/custom_syntax.rs | 13 ++++++------- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37515af0..dbfdbdb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Enhancements * Added `log10()` for `Decimal`. * `ln` for `Decimal` is now checked and won't panic. * `Scope::set_value` now takes anything that implements `Into>`. +* Added `Scope::is_constant` to check if a variable is constant. Version 1.0.2 diff --git a/src/scope.rs b/src/scope.rs index 8e6fccb6..33bf4600 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -339,6 +339,30 @@ impl<'a> Scope<'a> { .find(|(_, (key, _))| name == key.as_ref()) .and_then(|(index, _)| self.values[index].flatten_clone().try_cast()) } + /// Check if the named entry in the [`Scope`] is constant. + /// + /// Search starts backwards from the last, stopping at the first entry matching the specified name. + /// + /// Returns [`None`] if no entry matching the specified name is found. + /// + /// # Example + /// + /// ``` + /// use rhai::Scope; + /// + /// let mut my_scope = Scope::new(); + /// + /// my_scope.push_constant("x", 42_i64); + /// assert_eq!(my_scope.is_constant("x"), Some(true)); + /// assert_eq!(my_scope.is_constant("y"), None); + /// ``` + #[inline] + pub fn is_constant(&self, name: &str) -> Option { + self.get_index(name).and_then(|(_, access)| match access { + AccessMode::ReadWrite => None, + AccessMode::ReadOnly => Some(true), + }) + } /// Update the value of the named entry in the [`Scope`]. /// /// Search starts backwards from the last, and only the first entry matching the specified name is updated. diff --git a/tests/custom_syntax.rs b/tests/custom_syntax.rs index 32832332..f1b5a297 100644 --- a/tests/custom_syntax.rs +++ b/tests/custom_syntax.rs @@ -157,13 +157,12 @@ fn test_custom_syntax() -> Result<(), Box> { // Evaluate the expression let value = context.eval_expression_tree(expr)?; - // Push new variable into the scope if it doesn't already exist. - // Otherwise set its value. - // WARNING - This panics if 'var_name' already exists and is constant! - // - In a real implementation, check this before doing anything! - context.scope_mut().set_value(var_name, value); - - Ok(Dynamic::UNIT) + if !context.scope().is_constant(&var_name).unwrap_or(false) { + context.scope_mut().set_value(var_name, value); + Ok(Dynamic::UNIT) + } else { + Err(format!("variable {} is constant", var_name).into()) + } }, )?;