Skip to content

Commit

Permalink
Allow disabling type safety checks for mutable HashMapContexts
Browse files Browse the repository at this point in the history
  • Loading branch information
FruitieX committed Jan 17, 2024
1 parent fcfe542 commit 582dd37
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 2 deletions.
26 changes: 24 additions & 2 deletions src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ pub trait ContextWithMutableVariables: Context {
fn set_value(&mut self, _identifier: String, _value: Value) -> EvalexprResult<()> {
Err(EvalexprError::ContextNotMutable)
}

/// Checks if type-safety assignment checks have been disabled.
fn are_type_safety_checks_disabled(&self) -> bool;

/// Disables type-safety assignment checks if `disabled` is `true`, and enables them otherwise.
fn set_type_safety_checks_disabled(&mut self, _disabled: bool) -> EvalexprResult<()> {
Err(EvalexprError::ContextNotMutable)
}
}

/// A context that allows to assign to function identifiers.
Expand Down Expand Up @@ -168,7 +176,7 @@ impl IterateVariablesContext for EmptyContextWithBuiltinFunctions {
///
/// *Value and function mappings are stored independently, meaning that there can be a function and a value with the same identifier.*
///
/// This context is type-safe, meaning that an identifier that is assigned a value of some type once cannot be assigned a value of another type.
/// By default, this context is type-safe, meaning that an identifier that is assigned a value of some type once cannot be assigned a value of another type.
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
pub struct HashMapContext {
Expand All @@ -178,6 +186,9 @@ pub struct HashMapContext {

/// True if builtin functions are disabled.
without_builtin_functions: bool,

/// True if type-unsafe assignments are allowed.
without_type_safety_check: bool,
}

impl HashMapContext {
Expand Down Expand Up @@ -258,7 +269,9 @@ impl Context for HashMapContext {
impl ContextWithMutableVariables for HashMapContext {
fn set_value(&mut self, identifier: String, value: Value) -> EvalexprResult<()> {
if let Some(existing_value) = self.variables.get_mut(&identifier) {
if ValueType::from(&existing_value) == ValueType::from(&value) {
if self.without_type_safety_check
|| ValueType::from(&existing_value) == ValueType::from(&value)
{
*existing_value = value;
return Ok(());
} else {
Expand All @@ -270,6 +283,15 @@ impl ContextWithMutableVariables for HashMapContext {
self.variables.insert(identifier, value);
Ok(())
}

fn are_type_safety_checks_disabled(&self) -> bool {
self.without_type_safety_check
}

fn set_type_safety_checks_disabled(&mut self, disabled: bool) -> EvalexprResult<()> {
self.without_type_safety_check = disabled;
Ok(())
}
}

impl ContextWithMutableFunctions for HashMapContext {
Expand Down
37 changes: 37 additions & 0 deletions tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1660,6 +1660,43 @@ fn test_hashmap_context_type_safety() {
);
}

#[test]
fn test_disabled_hashmap_context_type_safety() {
let mut context = context_map! {"a" => 5, "b" => 5.0}.unwrap();
assert!(!context.are_type_safety_checks_disabled());
context.set_type_safety_checks_disabled(true).unwrap();
assert!(context.are_type_safety_checks_disabled());

// Assignment to same type still works
assert_eq!(
eval_with_context_mut("a = 4", &mut context),
Ok(Value::Empty)
);
assert_eq!(context.get_value("a").unwrap().as_int(), Ok(4));

// Assignment to another type works
assert_eq!(
eval_with_context_mut(r#"b = "foo""#, &mut context),
Ok(Value::Empty)
);
assert_eq!(
context.get_value("b").unwrap().as_string(),
Ok("foo".into())
);

// Assignment to empty value then another type works
assert_eq!(
eval_with_context_mut("c = ()", &mut context),
Ok(Value::Empty)
);
assert_eq!(context.get_value("c").unwrap().as_empty(), Ok(()));
assert_eq!(
eval_with_context_mut("c = 5", &mut context),
Ok(Value::Empty)
);
assert_eq!(context.get_value("c").unwrap().as_int(), Ok(5));
}

#[test]
fn test_hashmap_context_clone_debug() {
let mut context = HashMapContext::new();
Expand Down

0 comments on commit 582dd37

Please sign in to comment.