diff --git a/CHANGELOG.md b/CHANGELOG.md index dbfdbdb6..93f20647 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Enhancements * `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. +* Added `Scope::set_or_push` to add a new variable only if one doesn't already exist. Version 1.0.2 diff --git a/src/scope.rs b/src/scope.rs index 33bf4600..cb13ccab 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -363,6 +363,51 @@ impl<'a> Scope<'a> { AccessMode::ReadOnly => Some(true), }) } + /// Update the value of the named entry in the [`Scope`] if it already exists and is not constant. + /// Push a new entry with the value into the [`Scope`] if the name doesn't exist or if the + /// existing entry is constant. + /// + /// Search starts backwards from the last, and only the first entry matching the specified name is updated. + /// + /// # Example + /// + /// ``` + /// use rhai::Scope; + /// + /// 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.len(), 1); + /// + /// my_scope.set_or_push("x", 0_i64); + /// assert_eq!(my_scope.get_value::("x").unwrap(), 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.len(), 2); + /// ``` + #[inline] + pub fn set_or_push( + &mut self, + name: impl AsRef + Into>, + value: impl Variant + Clone, + ) -> &mut Self { + match self.get_index(name.as_ref()) { + None | Some((_, AccessMode::ReadOnly)) => { + 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`"); + *value_ref = Dynamic::from(value); + } + } + self + } /// 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.