Fix docs and error types.

This commit is contained in:
Sebastian Schmidt 2023-05-21 10:19:26 +03:00
parent 24c1749143
commit 5a4dcf9516
6 changed files with 66 additions and 48 deletions

View File

@ -287,10 +287,6 @@ assert_eq!(eval_with_context_mut("a = 5.5", &mut context),
Err(EvalexprError::ExpectedInt { actual: Value::from(5.5) })); Err(EvalexprError::ExpectedInt { actual: Value::from(5.5) }));
// Reading a variable does not require a mutable context // Reading a variable does not require a mutable context
assert_eq!(eval_with_context("a", &context), Ok(Value::from(5))); assert_eq!(eval_with_context("a", &context), Ok(Value::from(5)));
// Builtin functions are enabled by default.
assert_eq!(eval_with_context("max(1,3)",&context),Ok(Value::from(3)));
context.set_builtin_functions_disabled(true);
assert_eq!(eval_with_context("max(1,3)",&context),Err(EvalexprError::FunctionIdentifierNotFound(String::from("max"))));
``` ```
@ -304,8 +300,6 @@ This means that assigning to `a` again with a different type yields an error.
Type unsafe contexts may be implemented if requested. Type unsafe contexts may be implemented if requested.
For reading `a`, it is enough to pass an immutable reference. For reading `a`, it is enough to pass an immutable reference.
EmptyContext have builtin functions disabled and can't be enabled.
EmptyContextWithBuiltinFunctions have builtin functions enabled and can't be disabled.
Contexts can also be manipulated in code. Contexts can also be manipulated in code.
Take a look at the following example: Take a look at the following example:
@ -339,14 +333,21 @@ assert_eq!(eval_int_with_context("f 5", &context), Ok(10));
For more information about user-defined functions, refer to the respective [section](#user-defined-functions). For more information about user-defined functions, refer to the respective [section](#user-defined-functions).
### Builtin Functions ### Builtin Functions
Builtin functions are enabled by default for HashMap Context. It can be disabled by calling Context::
set_builtin_functions_disabled
It's disabled for EmptyContext. It can't be enabled for EmptyContext This crate offers a set of builtin functions (see below for a full list).
They can be disabled if needed as follows:
It's enabled for EmptyContextWithBuiltinfunctions. It can't be disabled. ```rust
use evalexpr::*;
let mut context = HashMapContext::new();
assert_eq!(eval_with_context("max(1,3)",&context),Ok(Value::from(3)));
context.set_builtin_functions_disabled(true).unwrap(); // Do proper error handling here
assert_eq!(eval_with_context("max(1,3)",&context),Err(EvalexprError::FunctionIdentifierNotFound(String::from("max"))));
```
This crate offers a set of builtin functions. Not all contexts support enabling or disabling builtin functions.
Specifically the `EmptyContext` has builtin functions disabled by default, and they cannot be enabled.
Symmetrically, the `EmptyContextWithBuiltinFunctions` has builtin functions enabled by default, and they cannot be disabled.
| Identifier | Argument Amount | Argument Types | Description | | Identifier | Argument Amount | Argument Types | Description |
|----------------------|-----------------|-------------------------------|-------------| |----------------------|-----------------|-------------------------------|-------------|
@ -407,9 +408,6 @@ Otherwise, a float is returned.
The regex functions require the feature flag `regex_support`. The regex functions require the feature flag `regex_support`.
Builtin functions are enabled by Default.
It can be disabled by calling Context::disable_builtin_fn().
### Values ### Values
Operators take values as arguments and produce values as results. Operators take values as arguments and produce values as results.

View File

@ -23,10 +23,11 @@ pub trait Context {
/// If no function with the given identifier is found, this method returns `EvalexprError::FunctionIdentifierNotFound`. /// If no function with the given identifier is found, this method returns `EvalexprError::FunctionIdentifierNotFound`.
fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult<Value>; fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult<Value>;
/// Checks if builtin function has been disabled. /// Checks if builtin functions are disabled.
fn are_builtin_functions_disabled(&self) -> bool; fn are_builtin_functions_disabled(&self) -> bool;
/// Disables Builtin function. /// Disables builtin functions if `disabled` is `true`, and enables them otherwise.
/// If the context does not support enabling or disabling builtin functions, an error is returned.
fn set_builtin_functions_disabled(&mut self, disabled: bool) -> EvalexprResult<()>; fn set_builtin_functions_disabled(&mut self, disabled: bool) -> EvalexprResult<()>;
} }
@ -72,7 +73,7 @@ pub trait GetFunctionContext: Context {
}*/ }*/
/// A context that returns `None` for each identifier. /// A context that returns `None` for each identifier.
/// Builtin functiions are disabled. /// Builtin functions are disabled and cannot be enabled.
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EmptyContext; pub struct EmptyContext;
@ -86,14 +87,16 @@ impl Context for EmptyContext {
identifier.to_string(), identifier.to_string(),
)) ))
} }
/// Builtin functions can't be enabled for Empty Context.
fn set_builtin_functions_disabled(&mut self, _disabled: bool) -> EvalexprResult<()> { /// Builtin functions are always disabled for `EmptyContext`.
Err(EvalexprError::InvalidBuiltinFunctionsContext)
}
/// Builtin functions are always disabled for Empty Context.
fn are_builtin_functions_disabled(&self) -> bool { fn are_builtin_functions_disabled(&self) -> bool {
true true
} }
/// Builtin functions can't be enabled for `EmptyContext`.
fn set_builtin_functions_disabled(&mut self, _disabled: bool) -> EvalexprResult<()> {
Err(EvalexprError::BuiltinFunctionsCannotBeEnabled)
}
} }
impl<'a> IterateVariablesContext<'a> for EmptyContext { impl<'a> IterateVariablesContext<'a> for EmptyContext {
@ -109,7 +112,8 @@ impl<'a> IterateVariablesContext<'a> for EmptyContext {
} }
} }
/// Same as Empty Context except Builtin functions are enabled. /// A context that returns `None` for each identifier.
/// Builtin functions are enabled and cannot be disabled.
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EmptyContextWithBuiltinFunctions; pub struct EmptyContextWithBuiltinFunctions;
@ -123,14 +127,16 @@ impl Context for EmptyContextWithBuiltinFunctions {
identifier.to_string(), identifier.to_string(),
)) ))
} }
/// Builtin functions can't be disbaled for EmptyContextWithBuiltinFunctions.
fn set_builtin_functions_disabled(&mut self, _disabled: bool) -> EvalexprResult<()> {
Err(EvalexprError::InvalidBuiltinFunctionsContext)
}
/// Builtin functions are always enabled for EmptyContextWithBuiltinFunctions. /// Builtin functions are always enabled for EmptyContextWithBuiltinFunctions.
fn are_builtin_functions_disabled(&self) -> bool { fn are_builtin_functions_disabled(&self) -> bool {
false false
} }
/// Builtin functions can't be disabled for EmptyContextWithBuiltinFunctions.
fn set_builtin_functions_disabled(&mut self, _disabled: bool) -> EvalexprResult<()> {
Err(EvalexprError::BuiltinFunctionsCannotBeDisabled)
}
} }
impl<'a> IterateVariablesContext<'a> for EmptyContextWithBuiltinFunctions { impl<'a> IterateVariablesContext<'a> for EmptyContextWithBuiltinFunctions {
@ -145,6 +151,7 @@ impl<'a> IterateVariablesContext<'a> for EmptyContextWithBuiltinFunctions {
iter::empty() iter::empty()
} }
} }
/// A context that stores its mappings in hash maps. /// A context that stores its mappings in hash maps.
/// ///
/// *Value and function mappings are stored independently, meaning that there can be a function and a value with the same identifier.* /// *Value and function mappings are stored independently, meaning that there can be a function and a value with the same identifier.*
@ -156,6 +163,8 @@ pub struct HashMapContext {
variables: HashMap<String, Value>, variables: HashMap<String, Value>,
#[cfg_attr(feature = "serde_support", serde(skip))] #[cfg_attr(feature = "serde_support", serde(skip))]
functions: HashMap<String, Function>, functions: HashMap<String, Function>,
/// True if builtin functions are disabled.
without_builtin_functions: bool, without_builtin_functions: bool,
} }

View File

@ -113,7 +113,12 @@ impl fmt::Display for EvalexprError {
regex, message regex, message
), ),
ContextNotMutable => write!(f, "Cannot manipulate context"), ContextNotMutable => write!(f, "Cannot manipulate context"),
InvalidBuiltinFunctionsContext => write!(f, "Invalid Builtin Functions Context"), BuiltinFunctionsCannotBeEnabled => {
write!(f, "This context does not allow enabling builtin functions")
},
BuiltinFunctionsCannotBeDisabled => {
write!(f, "This context does not allow disabling builtin functions")
},
IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string), IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string),
CustomMessage(message) => write!(f, "Error: {}", message), CustomMessage(message) => write!(f, "Error: {}", message),
} }

View File

@ -203,8 +203,11 @@ pub enum EvalexprError {
/// An escape sequence within a string literal is illegal. /// An escape sequence within a string literal is illegal.
IllegalEscapeSequence(String), IllegalEscapeSequence(String),
/// Empty Context can't have builtin functions enabled /// This context does not allow enabling builtin functions.
InvalidBuiltinFunctionsContext, BuiltinFunctionsCannotBeEnabled,
/// This context does not allow disabling builtin functions.
BuiltinFunctionsCannotBeDisabled,
/// A custom error explained by its message. /// A custom error explained by its message.
CustomMessage(String), CustomMessage(String),

View File

@ -270,10 +270,6 @@
//! Err(EvalexprError::ExpectedInt { actual: Value::from(5.5) })); //! Err(EvalexprError::ExpectedInt { actual: Value::from(5.5) }));
//! // Reading a variable does not require a mutable context //! // Reading a variable does not require a mutable context
//! assert_eq!(eval_with_context("a", &context), Ok(Value::from(5))); //! assert_eq!(eval_with_context("a", &context), Ok(Value::from(5)));
//! // Builtin functions are enabled by default.
//! assert_eq!(eval_with_context("max(1,3)",&context),Ok(Value::from(3)));
//! context.set_builtin_functions_disabled(true);
//! assert_eq!(eval_with_context("max(1,3)",&context),Err(EvalexprError::FunctionIdentifierNotFound(String::from("max"))));
//! //!
//! ``` //! ```
//! //!
@ -287,8 +283,6 @@
//! Type unsafe contexts may be implemented if requested. //! Type unsafe contexts may be implemented if requested.
//! For reading `a`, it is enough to pass an immutable reference. //! For reading `a`, it is enough to pass an immutable reference.
//! //!
//! EmptyContext have builtin functions disabled and can't be enabled.
//! EmptyContextWithBuiltinFunctions have builtin functions enabled and can't be disabled.
//! Contexts can also be manipulated in code. //! Contexts can also be manipulated in code.
//! Take a look at the following example: //! Take a look at the following example:
//! //!
@ -322,14 +316,21 @@
//! For more information about user-defined functions, refer to the respective [section](#user-defined-functions). //! For more information about user-defined functions, refer to the respective [section](#user-defined-functions).
//! //!
//! ### Builtin Functions //! ### Builtin Functions
//! Builtin functions are enabled by default for HashMap Context. It can be disabled by calling Context::
//! set_builtin_functions_disabled
//! //!
//! It's disabled for EmptyContext. It can't be enabled for EmptyContext //! This crate offers a set of builtin functions (see below for a full list).
//! They can be disabled if needed as follows:
//! //!
//! It's enabled for EmptyContextWithBuiltinfunctions. It can't be disabled. //! ```rust
//! use evalexpr::*;
//! let mut context = HashMapContext::new();
//! assert_eq!(eval_with_context("max(1,3)",&context),Ok(Value::from(3)));
//! context.set_builtin_functions_disabled(true).unwrap(); // Do proper error handling here
//! assert_eq!(eval_with_context("max(1,3)",&context),Err(EvalexprError::FunctionIdentifierNotFound(String::from("max"))));
//! ```
//! //!
//! This crate offers a set of builtin functions. //! Not all contexts support enabling or disabling builtin functions.
//! Specifically the `EmptyContext` has builtin functions disabled by default, and they cannot be enabled.
//! Symmetrically, the `EmptyContextWithBuiltinFunctions` has builtin functions enabled by default, and they cannot be disabled.
//! //!
//! | Identifier | Argument Amount | Argument Types | Description | //! | Identifier | Argument Amount | Argument Types | Description |
//! |----------------------|-----------------|-------------------------------|-------------| //! |----------------------|-----------------|-------------------------------|-------------|
@ -390,9 +391,6 @@
//! //!
//! The regex functions require the feature flag `regex_support`. //! The regex functions require the feature flag `regex_support`.
//! //!
//! Builtin functions are enabled by Default.
//! It can be disabled by calling Context::disable_builtin_fn().
//!
//! ### Values //! ### Values
//! //!
//! Operators take values as arguments and produce values as results. //! Operators take values as arguments and produce values as results.

View File

@ -1529,17 +1529,22 @@ fn test_empty_context() {
); );
assert_eq!( assert_eq!(
context.set_builtin_functions_disabled(false), context.set_builtin_functions_disabled(false),
Err(EvalexprError::InvalidBuiltinFunctionsContext) Err(EvalexprError::BuiltinFunctionsCannotBeEnabled)
) )
} }
#[test] #[test]
fn test_empty_context_with_builtin_functions() { fn test_empty_context_with_builtin_functions() {
let mut context = EmptyContextWithBuiltinFunctions; let mut context = EmptyContextWithBuiltinFunctions;
assert_eq!(context.get_value("abc"), None);
assert_eq!(
context.call_function("abc", &Value::Empty),
Err(EvalexprError::FunctionIdentifierNotFound("abc".to_owned()))
);
assert_eq!(eval_with_context("max(1,3)", &context), Ok(Value::Int(3))); assert_eq!(eval_with_context("max(1,3)", &context), Ok(Value::Int(3)));
assert_eq!( assert_eq!(
context.set_builtin_functions_disabled(true), context.set_builtin_functions_disabled(true),
Err(EvalexprError::InvalidBuiltinFunctionsContext) Err(EvalexprError::BuiltinFunctionsCannotBeEnabled)
); );
} }
@ -2270,8 +2275,8 @@ fn test_builtin_functions_context() {
// Builtin functions are enabled by default for HashMapContext. // Builtin functions are enabled by default for HashMapContext.
assert_eq!(eval_with_context("max(1,3)", &context), Ok(Value::from(3))); assert_eq!(eval_with_context("max(1,3)", &context), Ok(Value::from(3)));
// Disabling builtin function in Context. // Disabling builtin function in Context.
context.set_builtin_functions_disabled(true); context.set_builtin_functions_disabled(true).unwrap();
// Builting functions are disabled and using them returns Error. // Builtin functions are disabled and using them returns an error.
assert_eq!( assert_eq!(
eval_with_context("max(1,3)", &context), eval_with_context("max(1,3)", &context),
Err(EvalexprError::FunctionIdentifierNotFound(String::from( Err(EvalexprError::FunctionIdentifierNotFound(String::from(