diff --git a/src/dynamic.rs b/src/dynamic.rs index 10042587..750c07c6 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -569,13 +569,19 @@ impl Dynamic { | Union::Str(_, access) | Union::Char(_, access) | Union::Int(_, access) - | Union::Float(_, access) - | Union::Array(_, access) - | Union::Map(_, access) | Union::FnPtr(_, access) - | Union::TimeStamp(_, access) - | Union::Variant(_, access) - | Union::Shared(_, access) => access, + | Union::Variant(_, access) => access, + + #[cfg(not(feature = "no_float"))] + Union::Float(_, access) => access, + #[cfg(not(feature = "no_index"))] + Union::Array(_, access) => access, + #[cfg(not(feature = "no_object"))] + Union::Map(_, access) => access, + #[cfg(not(feature = "no_std"))] + Union::TimeStamp(_, access) => access, + #[cfg(not(feature = "no_closure"))] + Union::Shared(_, access) => access, } } /// Set the [`AccessType`] for this [`Dynamic`]. @@ -586,17 +592,29 @@ impl Dynamic { | Union::Str(_, access) | Union::Char(_, access) | Union::Int(_, access) - | Union::Float(_, access) - | Union::Array(_, access) - | Union::Map(_, access) | Union::FnPtr(_, access) - | Union::TimeStamp(_, access) - | Union::Variant(_, access) - | Union::Shared(_, access) => *access = typ, + | Union::Variant(_, access) => *access = typ, + + #[cfg(not(feature = "no_float"))] + Union::Float(_, access) => *access = typ, + #[cfg(not(feature = "no_index"))] + Union::Array(_, access) => *access = typ, + #[cfg(not(feature = "no_object"))] + Union::Map(_, access) => *access = typ, + #[cfg(not(feature = "no_std"))] + Union::TimeStamp(_, access) => *access = typ, + #[cfg(not(feature = "no_closure"))] + Union::Shared(_, access) => *access = typ, } } - /// Is this [`Dynamic`] constant? - pub(crate) fn is_constant(&self) -> bool { + /// Is this [`Dynamic`] read-only? + /// + /// Constant [`Dynamic`] values are read-only. If a [`&mut Dynamic`][Dynamic] to such a constant + /// is passed to a Rust function, the function can use this information to return an error of + /// [`EvalAltResult::ErrorAssignmentToConstant`][crate::EvalAltResult::ErrorAssignmentToConstant] + /// if its value is going to be modified. This safe-guards constant values from being modified + /// from within Rust functions. + pub fn is_read_only(&self) -> bool { self.access_type().is_constant() } /// Create a [`Dynamic`] from any type. A [`Dynamic`] value is simply returned as is. diff --git a/src/engine.rs b/src/engine.rs index b399c6e7..7fcb0dbd 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1285,7 +1285,7 @@ impl Engine { self.search_namespace(scope, mods, state, lib, this_ptr, lhs)?; // Constants cannot be modified - if target.as_ref().is_constant() && new_val.is_some() { + if target.as_ref().is_read_only() && new_val.is_some() { return EvalAltResult::ErrorAssignmentToConstant(var_name.to_string(), pos) .into(); } @@ -1569,7 +1569,7 @@ impl Engine { lib: &[&Module], this_ptr: &'s mut Option<&mut Dynamic>, expr: &Expr, - no_const: bool, + _no_const: bool, level: usize, ) -> Result<(Target<'s>, Position), Box> { match expr { @@ -1579,7 +1579,7 @@ impl Engine { self.search_namespace(scope, mods, state, lib, this_ptr, expr)?; // If necessary, constants are cloned - if target.as_ref().is_constant() { + if target.as_ref().is_read_only() { target = target.into_owned(); } @@ -1598,7 +1598,7 @@ impl Engine { let idx = self.eval_expr(scope, mods, state, lib, this_ptr, &x.rhs, level)?; let idx_pos = x.rhs.position(); let (mut target, pos) = self.eval_expr_as_target( - scope, mods, state, lib, this_ptr, &x.lhs, no_const, level, + scope, mods, state, lib, this_ptr, &x.lhs, _no_const, level, )?; let is_ref = target.is_ref(); @@ -1625,7 +1625,7 @@ impl Engine { // var.prop Expr::Property(ref p) => { let (mut target, _) = self.eval_expr_as_target( - scope, mods, state, lib, this_ptr, &x.lhs, no_const, level, + scope, mods, state, lib, this_ptr, &x.lhs, _no_const, level, )?; let is_ref = target.is_ref(); @@ -1919,7 +1919,7 @@ impl Engine { self.inc_operations(state) .map_err(|err| err.fill_position(pos))?; - if lhs_ptr.as_ref().is_constant() { + if lhs_ptr.as_ref().is_read_only() { // Assignment to constant variable Err(Box::new(EvalAltResult::ErrorAssignmentToConstant( name.to_string(), diff --git a/src/fn_call.rs b/src/fn_call.rs index bdcd4cb7..8e2c88bd 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -997,7 +997,7 @@ impl Engine { let (mut target, _, pos) = self.search_namespace(scope, mods, state, lib, this_ptr, &args_expr[0])?; - if target.as_ref().is_constant() { + if target.as_ref().is_read_only() { target = target.into_owned(); } diff --git a/src/scope.rs b/src/scope.rs index 7cef2ca8..42216538 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -436,7 +436,7 @@ impl<'a> Scope<'a> { self.names .iter() .zip(self.values.iter()) - .map(|((name, _), value)| (name.as_ref(), value.is_constant(), value)) + .map(|((name, _), value)| (name.as_ref(), value.is_read_only(), value)) } } diff --git a/src/serde_impl/de.rs b/src/serde_impl/de.rs index 6d7fcfed..0aa00a6e 100644 --- a/src/serde_impl/de.rs +++ b/src/serde_impl/de.rs @@ -132,39 +132,39 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_any>(self, visitor: V) -> Result> { match &self.value.0 { - Union::Unit(_) => self.deserialize_unit(visitor), - Union::Bool(_) => self.deserialize_bool(visitor), - Union::Str(_) => self.deserialize_str(visitor), - Union::Char(_) => self.deserialize_char(visitor), + Union::Unit(_, _) => self.deserialize_unit(visitor), + Union::Bool(_, _) => self.deserialize_bool(visitor), + Union::Str(_, _) => self.deserialize_str(visitor), + Union::Char(_, _) => self.deserialize_char(visitor), #[cfg(not(feature = "only_i32"))] - Union::Int(_) => self.deserialize_i64(visitor), + Union::Int(_, _) => self.deserialize_i64(visitor), #[cfg(feature = "only_i32")] - Union::Int(_) => self.deserialize_i32(visitor), + Union::Int(_, _) => self.deserialize_i32(visitor), #[cfg(not(feature = "no_float"))] - Union::Float(_) => self.deserialize_f64(visitor), + Union::Float(_, _) => self.deserialize_f64(visitor), #[cfg(not(feature = "no_index"))] - Union::Array(_) => self.deserialize_seq(visitor), + Union::Array(_, _) => self.deserialize_seq(visitor), #[cfg(not(feature = "no_object"))] - Union::Map(_) => self.deserialize_map(visitor), - Union::FnPtr(_) => self.type_error(), + Union::Map(_, _) => self.deserialize_map(visitor), + Union::FnPtr(_, _) => self.type_error(), #[cfg(not(feature = "no_std"))] - Union::TimeStamp(_) => self.type_error(), + Union::TimeStamp(_, _) => self.type_error(), - Union::Variant(value) if value.is::() => self.deserialize_i8(visitor), - Union::Variant(value) if value.is::() => self.deserialize_i16(visitor), - Union::Variant(value) if value.is::() => self.deserialize_i32(visitor), - Union::Variant(value) if value.is::() => self.deserialize_i64(visitor), - Union::Variant(value) if value.is::() => self.deserialize_i128(visitor), - Union::Variant(value) if value.is::() => self.deserialize_u8(visitor), - Union::Variant(value) if value.is::() => self.deserialize_u16(visitor), - Union::Variant(value) if value.is::() => self.deserialize_u32(visitor), - Union::Variant(value) if value.is::() => self.deserialize_u64(visitor), - Union::Variant(value) if value.is::() => self.deserialize_u128(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_i8(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_i16(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_i32(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_i64(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_i128(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_u8(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_u16(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_u32(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_u64(visitor), + Union::Variant(value, _) if value.is::() => self.deserialize_u128(visitor), - Union::Variant(_) => self.type_error(), + Union::Variant(_, _) => self.type_error(), #[cfg(not(feature = "no_closure"))] - Union::Shared(_) => self.type_error(), + Union::Shared(_, _) => self.type_error(), } }