diff --git a/src/context/mod.rs b/src/context/mod.rs index 3306e01..8a77af8 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -4,11 +4,12 @@ //! This crate implements two basic variants, the `EmptyContext`, that returns `None` for each identifier and cannot be manipulated, and the `HashMapContext`, that stores its mappings in hash maps. //! The HashMapContext is type-safe and returns an error if the user tries to assign a value of a different type than before to an identifier. -use std::{collections::HashMap, iter}; +use std::{collections::HashMap, iter, marker::PhantomData}; use crate::{ + error::EvalexprResultValue, function::Function, - value::{value_type::ValueType, Value}, + value::{numeric_types::EvalexprNumericTypes, value_type::ValueType, Value}, EvalexprError, EvalexprResult, }; @@ -16,25 +17,39 @@ mod predefined; /// An immutable context. pub trait Context { + /// The numeric types used for evaluation. + type NumericTypes: EvalexprNumericTypes; + /// Returns the value that is linked to the given identifier. - fn get_value(&self, identifier: &str) -> Option<&Value>; + fn get_value(&self, identifier: &str) -> Option<&Value>; /// Calls the function that is linked to the given identifier with the given argument. /// If no function with the given identifier is found, this method returns `EvalexprError::FunctionIdentifierNotFound`. - fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult; + fn call_function( + &self, + identifier: &str, + argument: &Value, + ) -> EvalexprResultValue; /// Checks if builtin functions are disabled. fn are_builtin_functions_disabled(&self) -> bool; /// 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<(), Self::NumericTypes>; } /// A context that allows to assign to variables. pub trait ContextWithMutableVariables: Context { /// Sets the variable with the given identifier to the given value. - fn set_value(&mut self, _identifier: String, _value: Value) -> EvalexprResult<()> { + fn set_value( + &mut self, + _identifier: String, + _value: Value, + ) -> EvalexprResult<(), Self::NumericTypes> { Err(EvalexprError::ContextNotMutable) } } @@ -42,17 +57,19 @@ pub trait ContextWithMutableVariables: Context { /// A context that allows to assign to function identifiers. pub trait ContextWithMutableFunctions: Context { /// Sets the function with the given identifier to the given function. - fn set_function(&mut self, _identifier: String, _function: Function) -> EvalexprResult<()> { + fn set_function( + &mut self, + _identifier: String, + _function: Function, + ) -> EvalexprResult<(), Self::NumericTypes> { Err(EvalexprError::ContextNotMutable) } } /// A context that allows to iterate over its variable names with their values. -/// -/// **Note:** this trait will change after GATs are stabilised, because then we can get rid of the lifetime in the trait definition. -pub trait IterateVariablesContext { +pub trait IterateVariablesContext: Context { /// The iterator type for iterating over variable name-value pairs. - type VariableIterator<'a>: Iterator + type VariableIterator<'a>: Iterator)> where Self: 'a; /// The iterator type for iterating over variable names. @@ -79,14 +96,20 @@ pub trait GetFunctionContext: Context { /// A context that returns `None` for each identifier. /// Builtin functions are disabled and cannot be enabled. #[derive(Debug, Default)] -pub struct EmptyContext; +pub struct EmptyContext(PhantomData); + +impl Context for EmptyContext { + type NumericTypes = NumericTypes; -impl Context for EmptyContext { - fn get_value(&self, _identifier: &str) -> Option<&Value> { + fn get_value(&self, _identifier: &str) -> Option<&Value> { None } - fn call_function(&self, identifier: &str, _argument: &Value) -> EvalexprResult { + fn call_function( + &self, + identifier: &str, + _argument: &Value, + ) -> EvalexprResultValue { Err(EvalexprError::FunctionIdentifierNotFound( identifier.to_string(), )) @@ -98,7 +121,10 @@ impl Context for EmptyContext { } /// Builtin functions can't be enabled for `EmptyContext`. - fn set_builtin_functions_disabled(&mut self, disabled: bool) -> EvalexprResult<()> { + fn set_builtin_functions_disabled( + &mut self, + disabled: bool, + ) -> EvalexprResult<(), Self::NumericTypes> { if disabled { Ok(()) } else { @@ -107,9 +133,9 @@ impl Context for EmptyContext { } } -impl IterateVariablesContext for EmptyContext { - type VariableIterator<'a> = iter::Empty<(String, Value)>; - type VariableNameIterator<'a> = iter::Empty; +impl IterateVariablesContext for EmptyContext { + type VariableIterator<'a> = iter::Empty<(String, Value)> where Self: 'a; + type VariableNameIterator<'a> = iter::Empty where Self: 'a; fn iter_variables(&self) -> Self::VariableIterator<'_> { iter::empty() @@ -123,14 +149,20 @@ impl IterateVariablesContext for EmptyContext { /// A context that returns `None` for each identifier. /// Builtin functions are enabled and cannot be disabled. #[derive(Debug, Default)] -pub struct EmptyContextWithBuiltinFunctions; +pub struct EmptyContextWithBuiltinFunctions(PhantomData); -impl Context for EmptyContextWithBuiltinFunctions { - fn get_value(&self, _identifier: &str) -> Option<&Value> { +impl Context for EmptyContextWithBuiltinFunctions { + type NumericTypes = NumericTypes; + + fn get_value(&self, _identifier: &str) -> Option<&Value> { None } - fn call_function(&self, identifier: &str, _argument: &Value) -> EvalexprResult { + fn call_function( + &self, + identifier: &str, + _argument: &Value, + ) -> EvalexprResultValue { Err(EvalexprError::FunctionIdentifierNotFound( identifier.to_string(), )) @@ -142,7 +174,10 @@ impl Context for EmptyContextWithBuiltinFunctions { } /// Builtin functions can't be disabled for EmptyContextWithBuiltinFunctions. - fn set_builtin_functions_disabled(&mut self, disabled: bool) -> EvalexprResult<()> { + fn set_builtin_functions_disabled( + &mut self, + disabled: bool, + ) -> EvalexprResult<(), Self::NumericTypes> { if disabled { Err(EvalexprError::BuiltinFunctionsCannotBeDisabled) } else { @@ -151,9 +186,9 @@ impl Context for EmptyContextWithBuiltinFunctions { } } -impl IterateVariablesContext for EmptyContextWithBuiltinFunctions { - type VariableIterator<'a> = iter::Empty<(String, Value)>; - type VariableNameIterator<'a> = iter::Empty; +impl IterateVariablesContext for EmptyContextWithBuiltinFunctions { + type VariableIterator<'a> = iter::Empty<(String, Value)> where Self: 'a; + type VariableNameIterator<'a> = iter::Empty where Self:'a; fn iter_variables(&self) -> Self::VariableIterator<'_> { iter::empty() @@ -169,18 +204,18 @@ 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. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] #[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] -pub struct HashMapContext { - variables: HashMap, +pub struct HashMapContext { + variables: HashMap>, #[cfg_attr(feature = "serde_support", serde(skip))] - functions: HashMap, + functions: HashMap>, /// True if builtin functions are disabled. without_builtin_functions: bool, } -impl HashMapContext { +impl HashMapContext { /// Constructs a `HashMapContext` with no mappings. pub fn new() -> Self { Default::default() @@ -230,12 +265,18 @@ impl HashMapContext { } } -impl Context for HashMapContext { - fn get_value(&self, identifier: &str) -> Option<&Value> { +impl Context for HashMapContext { + type NumericTypes = NumericTypes; + + fn get_value(&self, identifier: &str) -> Option<&Value> { self.variables.get(identifier) } - fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult { + fn call_function( + &self, + identifier: &str, + argument: &Value, + ) -> EvalexprResultValue { if let Some(function) = self.functions.get(identifier) { function.call(argument) } else { @@ -249,14 +290,21 @@ impl Context for HashMapContext { self.without_builtin_functions } - fn set_builtin_functions_disabled(&mut self, disabled: bool) -> EvalexprResult<()> { + fn set_builtin_functions_disabled( + &mut self, + disabled: bool, + ) -> EvalexprResult<(), NumericTypes> { self.without_builtin_functions = disabled; Ok(()) } } -impl ContextWithMutableVariables for HashMapContext { - fn set_value(&mut self, identifier: String, value: Value) -> EvalexprResult<()> { +impl ContextWithMutableVariables for HashMapContext { + fn set_value( + &mut self, + identifier: String, + value: Value, + ) -> EvalexprResult<(), NumericTypes> { if let Some(existing_value) = self.variables.get_mut(&identifier) { if ValueType::from(&existing_value) == ValueType::from(&value) { *existing_value = value; @@ -272,20 +320,24 @@ impl ContextWithMutableVariables for HashMapContext { } } -impl ContextWithMutableFunctions for HashMapContext { - fn set_function(&mut self, identifier: String, function: Function) -> EvalexprResult<()> { +impl ContextWithMutableFunctions for HashMapContext { + fn set_function( + &mut self, + identifier: String, + function: Function, + ) -> EvalexprResult<(), Self::NumericTypes> { self.functions.insert(identifier, function); Ok(()) } } -impl IterateVariablesContext for HashMapContext { +impl IterateVariablesContext for HashMapContext { type VariableIterator<'a> = std::iter::Map< - std::collections::hash_map::Iter<'a, String, Value>, - fn((&String, &Value)) -> (String, Value), - >; + std::collections::hash_map::Iter<'a, String, Value>, + fn((&String, &Value)) -> (String, Value), + > where Self: 'a; type VariableNameIterator<'a> = - std::iter::Cloned>; + std::iter::Cloned>> where Self: 'a; fn iter_variables(&self) -> Self::VariableIterator<'_> { self.variables @@ -298,6 +350,16 @@ impl IterateVariablesContext for HashMapContext { } } +impl Default for HashMapContext { + fn default() -> Self { + Self { + variables: Default::default(), + functions: Default::default(), + without_builtin_functions: false, + } + } +} + /// This macro provides a convenient syntax for creating a static context. /// /// # Examples diff --git a/src/error/mod.rs b/src/error/mod.rs index 7de0651..974086d 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -7,6 +7,7 @@ use std::ops::RangeInclusive; +use crate::value::numeric_types::{DefaultNumericTypes, EvalexprNumericTypes}; use crate::{token::PartialToken, value::value_type::ValueType}; use crate::{operator::Operator, value::Value}; @@ -18,7 +19,7 @@ mod display; /// Errors used in this crate. #[derive(Debug, Clone, PartialEq)] #[non_exhaustive] -pub enum EvalexprError { +pub enum EvalexprError { /// An operator was called with a wrong amount of arguments. WrongOperatorArgumentAmount { /// The expected amount of arguments. @@ -38,45 +39,45 @@ pub enum EvalexprError { /// A string value was expected. ExpectedString { /// The actual value. - actual: Value, + actual: Value, }, /// An integer value was expected. ExpectedInt { /// The actual value. - actual: Value, + actual: Value, }, /// A float value was expected. ExpectedFloat { /// The actual value. - actual: Value, + actual: Value, }, /// A numeric value was expected. /// Numeric values are the variants `Value::Int` and `Value::Float`. ExpectedNumber { /// The actual value. - actual: Value, + actual: Value, }, /// A numeric or string value was expected. /// Numeric values are the variants `Value::Int` and `Value::Float`. ExpectedNumberOrString { /// The actual value. - actual: Value, + actual: Value, }, /// A boolean value was expected. ExpectedBoolean { /// The actual value. - actual: Value, + actual: Value, }, /// A tuple value was expected. ExpectedTuple { /// The actual value. - actual: Value, + actual: Value, }, /// A tuple value of a certain length was expected. @@ -84,7 +85,7 @@ pub enum EvalexprError { /// The expected length. expected_length: usize, /// The actual value. - actual: Value, + actual: Value, }, /// A tuple value of a certain length range was expected. @@ -92,13 +93,13 @@ pub enum EvalexprError { /// The expected length range. expected_length: RangeInclusive, /// The actual value. - actual: Value, + actual: Value, }, /// An empty value was expected. ExpectedEmpty { /// The actual value. - actual: Value, + actual: Value, }, /// Tried to append a child to a leaf node. @@ -122,7 +123,7 @@ pub enum EvalexprError { /// The expected types. expected: Vec, /// The actual value. - actual: Value, + actual: Value, }, /// An operator is used with a wrong combination of types. @@ -159,47 +160,47 @@ pub enum EvalexprError { /// An addition operation performed by Rust failed. AdditionError { /// The first argument of the addition. - augend: Value, + augend: Value, /// The second argument of the addition. - addend: Value, + addend: Value, }, /// A subtraction operation performed by Rust failed. SubtractionError { /// The first argument of the subtraction. - minuend: Value, + minuend: Value, /// The second argument of the subtraction. - subtrahend: Value, + subtrahend: Value, }, /// A negation operation performed by Rust failed. NegationError { /// The argument of the negation. - argument: Value, + argument: Value, }, /// A multiplication operation performed by Rust failed. MultiplicationError { /// The first argument of the multiplication. - multiplicand: Value, + multiplicand: Value, /// The second argument of the multiplication. - multiplier: Value, + multiplier: Value, }, /// A division operation performed by Rust failed. DivisionError { /// The first argument of the division. - dividend: Value, + dividend: Value, /// The second argument of the division. - divisor: Value, + divisor: Value, }, /// A modulation operation performed by Rust failed. ModulationError { /// The first argument of the modulation. - dividend: Value, + dividend: Value, /// The second argument of the modulation. - divisor: Value, + divisor: Value, }, /// A regular expression could not be parsed @@ -229,7 +230,7 @@ pub enum EvalexprError { CustomMessage(String), } -impl EvalexprError { +impl EvalexprError { /// Construct a `WrongOperatorArgumentAmount` error. pub fn wrong_operator_argument_amount(actual: usize, expected: usize) -> Self { EvalexprError::WrongOperatorArgumentAmount { actual, expected } @@ -252,7 +253,7 @@ impl EvalexprError { } /// Constructs `EvalexprError::TypeError{actual, expected}`. - pub fn type_error(actual: Value, expected: Vec) -> Self { + pub fn type_error(actual: Value, expected: Vec) -> Self { EvalexprError::TypeError { actual, expected } } @@ -262,42 +263,42 @@ impl EvalexprError { } /// Constructs `EvalexprError::ExpectedString{actual}`. - pub fn expected_string(actual: Value) -> Self { + pub fn expected_string(actual: Value) -> Self { EvalexprError::ExpectedString { actual } } /// Constructs `EvalexprError::ExpectedInt{actual}`. - pub fn expected_int(actual: Value) -> Self { + pub fn expected_int(actual: Value) -> Self { EvalexprError::ExpectedInt { actual } } /// Constructs `EvalexprError::ExpectedFloat{actual}`. - pub fn expected_float(actual: Value) -> Self { + pub fn expected_float(actual: Value) -> Self { EvalexprError::ExpectedFloat { actual } } /// Constructs `EvalexprError::ExpectedNumber{actual}`. - pub fn expected_number(actual: Value) -> Self { + pub fn expected_number(actual: Value) -> Self { EvalexprError::ExpectedNumber { actual } } /// Constructs `EvalexprError::ExpectedNumberOrString{actual}`. - pub fn expected_number_or_string(actual: Value) -> Self { + pub fn expected_number_or_string(actual: Value) -> Self { EvalexprError::ExpectedNumberOrString { actual } } /// Constructs `EvalexprError::ExpectedBoolean{actual}`. - pub fn expected_boolean(actual: Value) -> Self { + pub fn expected_boolean(actual: Value) -> Self { EvalexprError::ExpectedBoolean { actual } } /// Constructs `EvalexprError::ExpectedTuple{actual}`. - pub fn expected_tuple(actual: Value) -> Self { + pub fn expected_tuple(actual: Value) -> Self { EvalexprError::ExpectedTuple { actual } } /// Constructs `EvalexprError::ExpectedFixedLenTuple{expected_len, actual}`. - pub fn expected_fixed_len_tuple(expected_len: usize, actual: Value) -> Self { + pub fn expected_fixed_len_tuple(expected_len: usize, actual: Value) -> Self { EvalexprError::ExpectedFixedLengthTuple { expected_length: expected_len, actual, @@ -305,7 +306,10 @@ impl EvalexprError { } /// Constructs `EvalexprError::ExpectedFixedLenTuple{expected_len, actual}`. - pub fn expected_ranged_len_tuple(expected_len: RangeInclusive, actual: Value) -> Self { + pub fn expected_ranged_len_tuple( + expected_len: RangeInclusive, + actual: Value, + ) -> Self { EvalexprError::ExpectedRangedLengthTuple { expected_length: expected_len, actual, @@ -313,12 +317,15 @@ impl EvalexprError { } /// Constructs `EvalexprError::ExpectedEmpty{actual}`. - pub fn expected_empty(actual: Value) -> Self { + pub fn expected_empty(actual: Value) -> Self { EvalexprError::ExpectedEmpty { actual } } /// Constructs an error that expresses that the type of `expected` was expected, but `actual` was found. - pub(crate) fn expected_type(expected: &Value, actual: Value) -> Self { + pub(crate) fn expected_type( + expected: &Value, + actual: Value, + ) -> Self { match ValueType::from(expected) { ValueType::String => Self::expected_string(actual), ValueType::Int => Self::expected_int(actual), @@ -336,33 +343,45 @@ impl EvalexprError { EvalexprError::UnmatchedPartialToken { first, second } } - pub(crate) fn addition_error(augend: Value, addend: Value) -> Self { + pub(crate) fn addition_error(augend: Value, addend: Value) -> Self { EvalexprError::AdditionError { augend, addend } } - pub(crate) fn subtraction_error(minuend: Value, subtrahend: Value) -> Self { + pub(crate) fn subtraction_error( + minuend: Value, + subtrahend: Value, + ) -> Self { EvalexprError::SubtractionError { minuend, subtrahend, } } - pub(crate) fn negation_error(argument: Value) -> Self { + pub(crate) fn negation_error(argument: Value) -> Self { EvalexprError::NegationError { argument } } - pub(crate) fn multiplication_error(multiplicand: Value, multiplier: Value) -> Self { + pub(crate) fn multiplication_error( + multiplicand: Value, + multiplier: Value, + ) -> Self { EvalexprError::MultiplicationError { multiplicand, multiplier, } } - pub(crate) fn division_error(dividend: Value, divisor: Value) -> Self { + pub(crate) fn division_error( + dividend: Value, + divisor: Value, + ) -> Self { EvalexprError::DivisionError { dividend, divisor } } - pub(crate) fn modulation_error(dividend: Value, divisor: Value) -> Self { + pub(crate) fn modulation_error( + dividend: Value, + divisor: Value, + ) -> Self { EvalexprError::ModulationError { dividend, divisor } } @@ -373,10 +392,10 @@ impl EvalexprError { } /// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongOperatorArgumentAmount)` otherwise. -pub(crate) fn expect_operator_argument_amount( +pub(crate) fn expect_operator_argument_amount( actual: usize, expected: usize, -) -> EvalexprResult<()> { +) -> EvalexprResult<(), NumericTypes> { if actual == expected { Ok(()) } else { @@ -387,7 +406,10 @@ pub(crate) fn expect_operator_argument_amount( } /// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongFunctionArgumentAmount)` otherwise. -pub fn expect_function_argument_amount(actual: usize, expected: usize) -> EvalexprResult<()> { +pub fn expect_function_argument_amount( + actual: usize, + expected: usize, +) -> EvalexprResult<(), NumericTypes> { if actual == expected { Ok(()) } else { @@ -398,7 +420,9 @@ pub fn expect_function_argument_amount(actual: usize, expected: usize) -> Evalex } /// Returns `Ok(())` if the given value is a string or a numeric -pub fn expect_number_or_string(actual: &Value) -> EvalexprResult<()> { +pub fn expect_number_or_string( + actual: &Value, +) -> EvalexprResult<(), NumericTypes> { match actual { Value::String(_) | Value::Float(_) | Value::Int(_) => Ok(()), _ => Err(EvalexprError::expected_number_or_string(actual.clone())), @@ -408,7 +432,12 @@ pub fn expect_number_or_string(actual: &Value) -> EvalexprResult<()> { impl std::error::Error for EvalexprError {} /// Standard result type used by this crate. -pub type EvalexprResult = Result; +pub type EvalexprResult = + Result>; + +/// Standard result type for [`Value`]s used by this crate. +pub type EvalexprResultValue = + EvalexprResult, NumericTypes>; #[cfg(test)] mod tests { @@ -418,26 +447,32 @@ mod tests { #[test] fn trivial_coverage_tests() { assert_eq!( - EvalexprError::type_error(Value::Int(3), vec![ValueType::String]), + EvalexprError::type_error(Value::::Int(3), vec![ValueType::String]), EvalexprError::TypeError { actual: Value::Int(3), expected: vec![ValueType::String] } ); assert_eq!( - EvalexprError::expected_type(&Value::String("abc".to_string()), Value::Empty), + EvalexprError::expected_type( + &Value::::String("abc".to_string()), + Value::Empty + ), EvalexprError::expected_string(Value::Empty) ); assert_eq!( - EvalexprError::expected_type(&Value::Boolean(false), Value::Empty), + EvalexprError::expected_type(&Value::::Boolean(false), Value::Empty), EvalexprError::expected_boolean(Value::Empty) ); assert_eq!( - EvalexprError::expected_type(&Value::Tuple(vec![]), Value::Empty), + EvalexprError::expected_type(&Value::::Tuple(vec![]), Value::Empty), EvalexprError::expected_tuple(Value::Empty) ); assert_eq!( - EvalexprError::expected_type(&Value::Empty, Value::String("abc".to_string())), + EvalexprError::expected_type( + &Value::::Empty, + Value::String("abc".to_string()) + ), EvalexprError::expected_empty(Value::String("abc".to_string())) ); } diff --git a/src/function/builtin.rs b/src/function/builtin.rs index 9aa6f1a..4f94fcf 100644 --- a/src/function/builtin.rs +++ b/src/function/builtin.rs @@ -2,8 +2,7 @@ use regex::Regex; use crate::{ - value::{FloatType, IntType}, - EvalexprError, Function, Value, ValueType, + value::numeric_types::EvalexprNumericTypes, EvalexprError, Function, Value, ValueType, }; use std::{ convert::TryFrom, @@ -26,7 +25,9 @@ macro_rules! simple_math { }; } -fn float_is(func: fn(FloatType) -> bool) -> Option { +fn float_is( + func: fn(NumericTypes::Float) -> bool, +) -> Option> { Some(Function::new(move |argument| { Ok(func(argument.as_number()?).into()) })) @@ -48,7 +49,9 @@ macro_rules! int_function { }; } -pub fn builtin_function(identifier: &str) -> Option { +pub fn builtin_function( + identifier: &str, +) -> Option> { match identifier { // Log "math::ln" => simple_math!(ln), diff --git a/src/function/mod.rs b/src/function/mod.rs index c590107..c2ff983 100644 --- a/src/function/mod.rs +++ b/src/function/mod.rs @@ -1,25 +1,25 @@ use std::fmt; -use crate::{error::EvalexprResult, value::Value}; +use crate::{error::EvalexprResultValue, value::Value}; pub(crate) mod builtin; /// A helper trait to enable cloning through `Fn` trait objects. -trait ClonableFn +trait ClonableFn where - Self: Fn(&Value) -> EvalexprResult, + Self: Fn(&Value) -> EvalexprResultValue, Self: Send + Sync + 'static, { - fn dyn_clone(&self) -> Box; + fn dyn_clone(&self) -> Box>; } -impl ClonableFn for F +impl ClonableFn for F where - F: Fn(&Value) -> EvalexprResult, + F: Fn(&Value) -> EvalexprResultValue, F: Send + Sync + 'static, F: Clone, { - fn dyn_clone(&self) -> Box { + fn dyn_clone(&self) -> Box> { Box::new(self.clone()) as _ } } @@ -38,11 +38,11 @@ where /// })).unwrap(); // Do proper error handling here /// assert_eq!(eval_with_context("id(4)", &context), Ok(Value::from(4))); /// ``` -pub struct Function { - function: Box, +pub struct Function { + function: Box>, } -impl Clone for Function { +impl Clone for Function { fn clone(&self) -> Self { Self { function: self.function.dyn_clone(), @@ -50,13 +50,13 @@ impl Clone for Function { } } -impl Function { +impl Function { /// Creates a user-defined function. /// /// The `function` is boxed for storage. pub fn new(function: F) -> Self where - F: Fn(&Value) -> EvalexprResult, + F: Fn(&Value) -> EvalexprResultValue, F: Send + Sync + 'static, F: Clone, { @@ -65,12 +65,12 @@ impl Function { } } - pub(crate) fn call(&self, argument: &Value) -> EvalexprResult { + pub(crate) fn call(&self, argument: &Value) -> EvalexprResultValue { (self.function)(argument) } } -impl fmt::Debug for Function { +impl fmt::Debug for Function { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "Function {{ [...] }}") } @@ -82,4 +82,4 @@ impl fmt::Debug for Function { #[doc(hidden)] trait IsSendAndSync: Send + Sync {} -impl IsSendAndSync for Function {} +impl IsSendAndSync for Function {} diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 332b704..a3a69f6 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -1,6 +1,9 @@ use crate::{ - token, tree, value::TupleType, Context, ContextWithMutableVariables, EmptyType, EvalexprError, - EvalexprResult, FloatType, HashMapContext, IntType, Node, Value, EMPTY_VALUE, + error::EvalexprResultValue, + token, tree, + value::{DefaultFloatType, DefaultIntType, TupleType}, + Context, ContextWithMutableVariables, EmptyType, EvalexprError, EvalexprResult, HashMapContext, + Node, Value, EMPTY_VALUE, }; /// Evaluate the given expression string. @@ -14,7 +17,7 @@ use crate::{ /// ``` /// /// *See the [crate doc](index.html) for more examples and explanations of the expression format.* -pub fn eval(string: &str) -> EvalexprResult { +pub fn eval(string: &str) -> EvalexprResultValue { eval_with_context_mut(string, &mut HashMapContext::new()) } @@ -97,14 +100,14 @@ pub fn eval_string(string: &str) -> EvalexprResult { /// Evaluate the given expression string into an integer. /// /// *See the [crate doc](index.html) for more examples and explanations of the expression format.* -pub fn eval_int(string: &str) -> EvalexprResult { +pub fn eval_int(string: &str) -> EvalexprResult { eval_int_with_context_mut(string, &mut HashMapContext::new()) } /// Evaluate the given expression string into a float. /// /// *See the [crate doc](index.html) for more examples and explanations of the expression format.* -pub fn eval_float(string: &str) -> EvalexprResult { +pub fn eval_float(string: &str) -> EvalexprResult { eval_float_with_context_mut(string, &mut HashMapContext::new()) } @@ -112,7 +115,7 @@ pub fn eval_float(string: &str) -> EvalexprResult { /// If the result of the expression is an integer, it is silently converted into a float. /// /// *See the [crate doc](index.html) for more examples and explanations of the expression format.* -pub fn eval_number(string: &str) -> EvalexprResult { +pub fn eval_number(string: &str) -> EvalexprResult { eval_number_with_context_mut(string, &mut HashMapContext::new()) } @@ -151,7 +154,7 @@ pub fn eval_string_with_context(string: &str, context: &C) -> Evalex /// Evaluate the given expression string into an integer with the given context. /// /// *See the [crate doc](index.html) for more examples and explanations of the expression format.* -pub fn eval_int_with_context(string: &str, context: &C) -> EvalexprResult { +pub fn eval_int_with_context(string: &str, context: &C) -> EvalexprResult { match eval_with_context(string, context) { Ok(Value::Int(int)) => Ok(int), Ok(value) => Err(EvalexprError::expected_int(value)), @@ -162,7 +165,10 @@ pub fn eval_int_with_context(string: &str, context: &C) -> EvalexprR /// Evaluate the given expression string into a float with the given context. /// /// *See the [crate doc](index.html) for more examples and explanations of the expression format.* -pub fn eval_float_with_context(string: &str, context: &C) -> EvalexprResult { +pub fn eval_float_with_context( + string: &str, + context: &C, +) -> EvalexprResult { match eval_with_context(string, context) { Ok(Value::Float(float)) => Ok(float), Ok(value) => Err(EvalexprError::expected_float(value)), diff --git a/src/lib.rs b/src/lib.rs index 763e94b..9a325be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -594,7 +594,7 @@ pub use crate::{ operator::Operator, token::PartialToken, tree::Node, - value::{value_type::ValueType, EmptyType, FloatType, IntType, TupleType, Value, EMPTY_VALUE}, + value::{value_type::ValueType, EmptyType, TupleType, Value, EMPTY_VALUE}, }; mod context; diff --git a/src/operator/mod.rs b/src/operator/mod.rs index 386357a..5bda1cc 100644 --- a/src/operator/mod.rs +++ b/src/operator/mod.rs @@ -1,12 +1,13 @@ use crate::function::builtin::builtin_function; +use crate::value::{DefaultFloatType, DefaultIntType}; use crate::{context::Context, error::*, value::Value, ContextWithMutableVariables}; mod display; /// An enum that represents operators in the operator tree. #[derive(Debug, PartialEq, Clone)] -pub enum Operator { +pub enum Operator { /// A root node in the operator tree. /// The whole expression is stored under a root node, as well as each subexpression surrounded by parentheses. RootNode, @@ -72,7 +73,7 @@ pub enum Operator { /// A constant value. Const { /** The value of the constant. */ - value: Value, + value: Value, }, /// A write to a variable identifier. VariableIdentifierWrite { @@ -91,8 +92,8 @@ pub enum Operator { }, } -impl Operator { - pub(crate) fn value(value: Value) -> Self { +impl Operator { + pub(crate) fn value(value: Value) -> Self { Operator::Const { value } } @@ -182,7 +183,7 @@ impl Operator { &self, arguments: &[Value], context: &C, - ) -> EvalexprResult { + ) -> EvalexprResultValue { use crate::operator::Operator::*; match self { RootNode => { @@ -481,7 +482,7 @@ impl Operator { &self, arguments: &[Value], context: &mut C, - ) -> EvalexprResult { + ) -> EvalexprResultValue { use crate::operator::Operator::*; match self { Assign => { diff --git a/src/token/mod.rs b/src/token/mod.rs index ea22890..0074d25 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -1,12 +1,12 @@ use crate::{ error::{EvalexprError, EvalexprResult}, - value::{FloatType, IntType}, + value::{DefaultFloatType, DefaultIntType}, }; mod display; #[derive(Clone, PartialEq, Debug)] -pub enum Token { +pub enum Token { // Arithmetic Plus, Minus, @@ -55,9 +55,9 @@ pub enum Token { /// A partial token is an input character whose meaning depends on the characters around it. #[derive(Clone, Debug, PartialEq)] -pub enum PartialToken { +pub enum PartialToken { /// A partial token that unambiguously maps to a single token. - Token(Token), + Token(Token), /// A partial token that is a literal. Literal(String), /// A plus character '+'. @@ -89,7 +89,7 @@ pub enum PartialToken { } // Make this a const fn as soon as is_whitespace and to_string get stable (issue #57563) -fn char_to_partial_token(c: char) -> PartialToken { +fn char_to_partial_token(c: char) -> PartialToken { match c { '+' => PartialToken::Plus, '-' => PartialToken::Minus, @@ -121,7 +121,7 @@ fn char_to_partial_token(c: char) -> PartialToken { } } -impl Token { +impl Token { #[cfg(not(tarpaulin_include))] pub(crate) const fn is_leftsided_value(&self) -> bool { match self { @@ -229,7 +229,9 @@ impl Token { } /// Parses an escape sequence within a string literal. -fn parse_escape_sequence>(iter: &mut Iter) -> EvalexprResult { +fn parse_escape_sequence, IntType, FloatType>( + iter: &mut Iter, +) -> EvalexprResult { match iter.next() { Some('"') => Ok('"'), Some('\\') => Ok('\\'), @@ -244,9 +246,9 @@ fn parse_escape_sequence>(iter: &mut Iter) -> Evalex /// The string is terminated by a double quote `"`. /// Occurrences of `"` within the string can be escaped with `\`. /// The backslash needs to be escaped with another backslash `\`. -fn parse_string_literal>( +fn parse_string_literal, IntType, FloatType>( mut iter: &mut Iter, -) -> EvalexprResult { +) -> EvalexprResult, IntType, FloatType> { let mut result = String::new(); while let Some(c) = iter.next() { @@ -260,7 +262,9 @@ fn parse_string_literal>( Err(EvalexprError::UnmatchedDoubleQuote) } -fn try_skip_comment(iter: &mut std::iter::Peekable>) -> EvalexprResult { +fn try_skip_comment( + iter: &mut std::iter::Peekable>, +) -> EvalexprResult { let mut matched = false; if let Some(lookahead) = iter.peek() { if *lookahead == '/' { @@ -296,7 +300,9 @@ fn try_skip_comment(iter: &mut std::iter::Peekable>) -> Eval } /// Converts a string to a vector of partial tokens. -fn str_to_partial_tokens(string: &str) -> EvalexprResult> { +fn str_to_partial_tokens( + string: &str, +) -> EvalexprResult, IntType, FloatType> { let mut result = Vec::new(); let mut iter = string.chars().peekable(); @@ -331,7 +337,9 @@ fn str_to_partial_tokens(string: &str) -> EvalexprResult> { } /// Resolves all partial tokens by converting them to complex tokens. -fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult> { +fn partial_tokens_to_tokens( + mut tokens: &[PartialToken], +) -> EvalexprResult>, IntType, FloatType> { let mut result = Vec::new(); while !tokens.is_empty() { let first = tokens[0].clone(); @@ -475,11 +483,13 @@ fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult EvalexprResult> { +pub(crate) fn tokenize( + string: &str, +) -> EvalexprResult>, IntType, FloatType> { partial_tokens_to_tokens(&str_to_partial_tokens(string)?) } -fn parse_dec_or_hex(literal: &str) -> Result { +fn parse_dec_or_hex(literal: &str) -> Result { if let Some(literal) = literal.strip_prefix("0x") { IntType::from_str_radix(literal, 16) } else { diff --git a/src/tree/mod.rs b/src/tree/mod.rs index e835fd3..610a9a3 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1,7 +1,8 @@ use crate::{ + error::EvalexprResultValue, token::Token, - value::{TupleType, EMPTY_VALUE}, - Context, ContextWithMutableVariables, EmptyType, FloatType, HashMapContext, IntType, + value::{DefaultFloatType, DefaultIntType, TupleType, EMPTY_VALUE}, + Context, ContextWithMutableVariables, EmptyType, HashMapContext, }; use crate::{ @@ -34,13 +35,13 @@ mod iter; /// ``` /// #[derive(Debug, PartialEq, Clone)] -pub struct Node { - operator: Operator, - children: Vec, +pub struct Node { + operator: Operator, + children: Vec>, } -impl Node { - fn new(operator: Operator) -> Self { +impl Node { + fn new(operator: Operator) -> Self { Self { children: Vec::new(), operator, @@ -320,7 +321,10 @@ impl Node { /// Evaluates the operator tree rooted at this node with the given context. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_with_context(&self, context: &C) -> EvalexprResult { + pub fn eval_with_context( + &self, + context: &C, + ) -> EvalexprResultValue { let mut arguments = Vec::new(); for child in self.children() { arguments.push(child.eval_with_context(context)?); @@ -334,7 +338,7 @@ impl Node { pub fn eval_with_context_mut( &self, context: &mut C, - ) -> EvalexprResult { + ) -> EvalexprResultValue { let mut arguments = Vec::new(); for child in self.children() { arguments.push(child.eval_with_context_mut(context)?); @@ -345,14 +349,17 @@ impl Node { /// Evaluates the operator tree rooted at this node. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval(&self) -> EvalexprResult { + pub fn eval(&self) -> EvalexprResultValue { self.eval_with_context_mut(&mut HashMapContext::new()) } /// Evaluates the operator tree rooted at this node into a string with an the given context. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_string_with_context(&self, context: &C) -> EvalexprResult { + pub fn eval_string_with_context( + &self, + context: &C, + ) -> EvalexprResult { match self.eval_with_context(context) { Ok(Value::String(string)) => Ok(string), Ok(value) => Err(EvalexprError::expected_string(value)), @@ -363,7 +370,10 @@ impl Node { /// Evaluates the operator tree rooted at this node into a float with an the given context. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_float_with_context(&self, context: &C) -> EvalexprResult { + pub fn eval_float_with_context( + &self, + context: &C, + ) -> EvalexprResult { match self.eval_with_context(context) { Ok(Value::Float(float)) => Ok(float), Ok(value) => Err(EvalexprError::expected_float(value)), @@ -374,7 +384,10 @@ impl Node { /// Evaluates the operator tree rooted at this node into an integer with an the given context. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_int_with_context(&self, context: &C) -> EvalexprResult { + pub fn eval_int_with_context( + &self, + context: &C, + ) -> EvalexprResult { match self.eval_with_context(context) { Ok(Value::Int(int)) => Ok(int), Ok(value) => Err(EvalexprError::expected_int(value)), @@ -386,7 +399,10 @@ impl Node { /// If the result of the expression is an integer, it is silently converted into a float. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_number_with_context(&self, context: &C) -> EvalexprResult { + pub fn eval_number_with_context( + &self, + context: &C, + ) -> EvalexprResult { match self.eval_with_context(context) { Ok(Value::Int(int)) => Ok(int as FloatType), Ok(Value::Float(float)) => Ok(float), @@ -398,7 +414,10 @@ impl Node { /// Evaluates the operator tree rooted at this node into a boolean with an the given context. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_boolean_with_context(&self, context: &C) -> EvalexprResult { + pub fn eval_boolean_with_context( + &self, + context: &C, + ) -> EvalexprResult { match self.eval_with_context(context) { Ok(Value::Boolean(boolean)) => Ok(boolean), Ok(value) => Err(EvalexprError::expected_boolean(value)), @@ -409,7 +428,10 @@ impl Node { /// Evaluates the operator tree rooted at this node into a tuple with an the given context. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_tuple_with_context(&self, context: &C) -> EvalexprResult { + pub fn eval_tuple_with_context( + &self, + context: &C, + ) -> EvalexprResult { match self.eval_with_context(context) { Ok(Value::Tuple(tuple)) => Ok(tuple), Ok(value) => Err(EvalexprError::expected_tuple(value)), @@ -420,7 +442,10 @@ impl Node { /// Evaluates the operator tree rooted at this node into an empty value with an the given context. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_empty_with_context(&self, context: &C) -> EvalexprResult { + pub fn eval_empty_with_context( + &self, + context: &C, + ) -> EvalexprResult { match self.eval_with_context(context) { Ok(Value::Empty) => Ok(EMPTY_VALUE), Ok(value) => Err(EvalexprError::expected_empty(value)), @@ -434,7 +459,7 @@ impl Node { pub fn eval_string_with_context_mut( &self, context: &mut C, - ) -> EvalexprResult { + ) -> EvalexprResult { match self.eval_with_context_mut(context) { Ok(Value::String(string)) => Ok(string), Ok(value) => Err(EvalexprError::expected_string(value)), @@ -448,7 +473,7 @@ impl Node { pub fn eval_float_with_context_mut( &self, context: &mut C, - ) -> EvalexprResult { + ) -> EvalexprResult { match self.eval_with_context_mut(context) { Ok(Value::Float(float)) => Ok(float), Ok(value) => Err(EvalexprError::expected_float(value)), @@ -462,7 +487,7 @@ impl Node { pub fn eval_int_with_context_mut( &self, context: &mut C, - ) -> EvalexprResult { + ) -> EvalexprResult { match self.eval_with_context_mut(context) { Ok(Value::Int(int)) => Ok(int), Ok(value) => Err(EvalexprError::expected_int(value)), @@ -477,7 +502,7 @@ impl Node { pub fn eval_number_with_context_mut( &self, context: &mut C, - ) -> EvalexprResult { + ) -> EvalexprResult { match self.eval_with_context_mut(context) { Ok(Value::Int(int)) => Ok(int as FloatType), Ok(Value::Float(float)) => Ok(float), @@ -492,7 +517,7 @@ impl Node { pub fn eval_boolean_with_context_mut( &self, context: &mut C, - ) -> EvalexprResult { + ) -> EvalexprResult { match self.eval_with_context_mut(context) { Ok(Value::Boolean(boolean)) => Ok(boolean), Ok(value) => Err(EvalexprError::expected_boolean(value)), @@ -506,7 +531,7 @@ impl Node { pub fn eval_tuple_with_context_mut( &self, context: &mut C, - ) -> EvalexprResult { + ) -> EvalexprResult { match self.eval_with_context_mut(context) { Ok(Value::Tuple(tuple)) => Ok(tuple), Ok(value) => Err(EvalexprError::expected_tuple(value)), @@ -520,7 +545,7 @@ impl Node { pub fn eval_empty_with_context_mut( &self, context: &mut C, - ) -> EvalexprResult { + ) -> EvalexprResult { match self.eval_with_context_mut(context) { Ok(Value::Empty) => Ok(EMPTY_VALUE), Ok(value) => Err(EvalexprError::expected_empty(value)), @@ -531,21 +556,21 @@ impl Node { /// Evaluates the operator tree rooted at this node into a string. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_string(&self) -> EvalexprResult { + pub fn eval_string(&self) -> EvalexprResult { self.eval_string_with_context_mut(&mut HashMapContext::new()) } /// Evaluates the operator tree rooted at this node into a float. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_float(&self) -> EvalexprResult { + pub fn eval_float(&self) -> EvalexprResult { self.eval_float_with_context_mut(&mut HashMapContext::new()) } /// Evaluates the operator tree rooted at this node into an integer. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_int(&self) -> EvalexprResult { + pub fn eval_int(&self) -> EvalexprResult { self.eval_int_with_context_mut(&mut HashMapContext::new()) } @@ -553,28 +578,28 @@ impl Node { /// If the result of the expression is an integer, it is silently converted into a float. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_number(&self) -> EvalexprResult { + pub fn eval_number(&self) -> EvalexprResult { self.eval_number_with_context_mut(&mut HashMapContext::new()) } /// Evaluates the operator tree rooted at this node into a boolean. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_boolean(&self) -> EvalexprResult { + pub fn eval_boolean(&self) -> EvalexprResult { self.eval_boolean_with_context_mut(&mut HashMapContext::new()) } /// Evaluates the operator tree rooted at this node into a tuple. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_tuple(&self) -> EvalexprResult { + pub fn eval_tuple(&self) -> EvalexprResult { self.eval_tuple_with_context_mut(&mut HashMapContext::new()) } /// Evaluates the operator tree rooted at this node into an empty value. /// /// Fails, if one of the operators in the expression tree fails. - pub fn eval_empty(&self) -> EvalexprResult { + pub fn eval_empty(&self) -> EvalexprResult { self.eval_empty_with_context_mut(&mut HashMapContext::new()) } @@ -614,7 +639,11 @@ impl Node { } } - fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> EvalexprResult<()> { + fn insert_back_prioritized( + &mut self, + node: Node, + is_root_node: bool, + ) -> EvalexprResult<(), IntType, FloatType> { // println!( // "Inserting {:?} into {:?}, is_root_node = {is_root_node}", // node.operator(), @@ -695,11 +724,11 @@ impl Node { } } -fn collapse_root_stack_to( - root_stack: &mut Vec, - mut root: Node, - collapse_goal: &Node, -) -> EvalexprResult { +fn collapse_root_stack_to( + root_stack: &mut Vec>, + mut root: Node, + collapse_goal: &Node, +) -> EvalexprResult, IntType, FloatType> { loop { if let Some(mut potential_higher_root) = root_stack.pop() { // TODO I'm not sure about this >, as I have no example for different sequence operators with the same precedence @@ -720,7 +749,9 @@ fn collapse_root_stack_to( Ok(root) } -fn collapse_all_sequences(root_stack: &mut Vec) -> EvalexprResult<()> { +fn collapse_all_sequences( + root_stack: &mut Vec>, +) -> EvalexprResult<(), IntType, FloatType> { // println!("Collapsing all sequences"); // println!("Initial root stack is: {:?}", root_stack); let mut root = if let Some(root) = root_stack.pop() { @@ -765,7 +796,9 @@ fn collapse_all_sequences(root_stack: &mut Vec) -> EvalexprResult<()> { Ok(()) } -pub(crate) fn tokens_to_operator_tree(tokens: Vec) -> EvalexprResult { +pub(crate) fn tokens_to_operator_tree( + tokens: Vec>, +) -> EvalexprResult { let mut root_stack = vec![Node::root_node()]; let mut last_token_is_rightsided_value = false; let mut token_iter = tokens.iter().peekable(); diff --git a/src/value/mod.rs b/src/value/mod.rs index 12630de..a2f1cc5 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,15 +1,12 @@ -use crate::error::{EvalexprError, EvalexprResult}; +use crate::error::{EvalexprError, EvalexprResult, EvalexprResultValue}; use std::{convert::TryFrom, ops::RangeInclusive}; +use self::numeric_types::{DefaultNumericTypes, EvalexprNumericTypes}; + mod display; +pub mod numeric_types; pub mod value_type; -/// The type used to represent integers in `Value::Int`. -pub type IntType = i64; - -/// The type used to represent floats in `Value::Float`. -pub type FloatType = f64; - /// The type used to represent tuples in `Value::Tuple`. pub type TupleType = Vec; @@ -23,13 +20,13 @@ pub const EMPTY_VALUE: () = (); /// Values can be of different subtypes that are the variants of this enum. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] -pub enum Value { +pub enum Value { /// A string value. String(String), /// A float value. - Float(FloatType), + Float(NumericTypes::Float), /// An integer value. - Int(IntType), + Int(NumericTypes::Int), /// A boolean value. Boolean(bool), /// A tuple value. @@ -38,7 +35,7 @@ pub enum Value { Empty, } -impl Value { +impl Value { /// Returns true if `self` is a `Value::String`. pub fn is_string(&self) -> bool { matches!(self, Value::String(_)) @@ -74,7 +71,7 @@ impl Value { } /// Clones the value stored in `self` as `String`, or returns `Err` if `self` is not a `Value::String`. - pub fn as_string(&self) -> EvalexprResult { + pub fn as_string(&self) -> EvalexprResult { match self { Value::String(string) => Ok(string.clone()), value => Err(EvalexprError::expected_string(value.clone())), @@ -82,7 +79,7 @@ impl Value { } /// Clones the value stored in `self` as `IntType`, or returns `Err` if `self` is not a `Value::Int`. - pub fn as_int(&self) -> EvalexprResult { + pub fn as_int(&self) -> EvalexprResult { match self { Value::Int(i) => Ok(*i), value => Err(EvalexprError::expected_int(value.clone())), @@ -90,7 +87,7 @@ impl Value { } /// Clones the value stored in `self` as `FloatType`, or returns `Err` if `self` is not a `Value::Float`. - pub fn as_float(&self) -> EvalexprResult { + pub fn as_float(&self) -> EvalexprResult { match self { Value::Float(f) => Ok(*f), value => Err(EvalexprError::expected_float(value.clone())), @@ -99,16 +96,16 @@ impl Value { /// Clones the value stored in `self` as `FloatType`, or returns `Err` if `self` is not a `Value::Float` or `Value::Int`. /// Note that this method silently converts `IntType` to `FloatType`, if `self` is a `Value::Int`. - pub fn as_number(&self) -> EvalexprResult { + pub fn as_number(&self) -> EvalexprResult { match self { - Value::Float(f) => Ok(*f), - Value::Int(i) => Ok(*i as FloatType), + Value::Float(f) => Ok(f.clone()), + Value::Int(i) => Ok(i.as_float()), value => Err(EvalexprError::expected_number(value.clone())), } } /// Clones the value stored in `self` as `bool`, or returns `Err` if `self` is not a `Value::Boolean`. - pub fn as_boolean(&self) -> EvalexprResult { + pub fn as_boolean(&self) -> EvalexprResult { match self { Value::Boolean(boolean) => Ok(*boolean), value => Err(EvalexprError::expected_boolean(value.clone())), @@ -116,7 +113,7 @@ impl Value { } /// Clones the value stored in `self` as `TupleType`, or returns `Err` if `self` is not a `Value::Tuple`. - pub fn as_tuple(&self) -> EvalexprResult { + pub fn as_tuple(&self) -> EvalexprResult { match self { Value::Tuple(tuple) => Ok(tuple.clone()), value => Err(EvalexprError::expected_tuple(value.clone())), @@ -124,7 +121,7 @@ impl Value { } /// Clones the value stored in `self` as `TupleType` or returns `Err` if `self` is not a `Value::Tuple` of the required length. - pub fn as_fixed_len_tuple(&self, len: usize) -> EvalexprResult { + pub fn as_fixed_len_tuple(&self, len: usize) -> EvalexprResult { match self { Value::Tuple(tuple) => { if tuple.len() == len { @@ -138,7 +135,10 @@ impl Value { } /// Clones the value stored in `self` as `TupleType` or returns `Err` if `self` is not a `Value::Tuple` with length in the required range. - pub fn as_ranged_len_tuple(&self, range: RangeInclusive) -> EvalexprResult { + pub fn as_ranged_len_tuple( + &self, + range: RangeInclusive, + ) -> EvalexprResult { match self { Value::Tuple(tuple) => { if range.contains(&tuple.len()) { @@ -155,7 +155,7 @@ impl Value { } /// Returns `()`, or returns`Err` if `self` is not a `Value::Tuple`. - pub fn as_empty(&self) -> EvalexprResult<()> { + pub fn as_empty(&self) -> EvalexprResult<(), IntType, FloatType> { match self { Value::Empty => Ok(()), value => Err(EvalexprError::expected_empty(value.clone())), @@ -173,60 +173,58 @@ impl Value { Value::Empty => String::from("()"), } } -} -impl From for Value { - fn from(string: String) -> Self { - Value::String(string) + pub fn from_float(float: FloatType) -> Self { + Self::Float(float) } -} -impl From<&str> for Value { - fn from(string: &str) -> Self { - Value::String(string.to_string()) + pub fn from_int(int: IntType) -> Self { + Self::Int(int) } } -impl From for Value { - fn from(float: FloatType) -> Self { - Value::Float(float) +impl From for Value { + fn from(string: String) -> Self { + Value::String(string) } } -impl From for Value { - fn from(int: IntType) -> Self { - Value::Int(int) +impl From<&str> for Value { + fn from(string: &str) -> Self { + Value::String(string.to_string()) } } -impl From for Value { +impl From for Value { fn from(boolean: bool) -> Self { Value::Boolean(boolean) } } -impl From for Value { +impl From for Value { fn from(tuple: TupleType) -> Self { Value::Tuple(tuple) } } -impl From for EvalexprResult { - fn from(value: Value) -> Self { +impl From> + for EvalexprResultValue +{ + fn from(value: Value) -> Self { Ok(value) } } -impl From<()> for Value { +impl From<()> for Value { fn from(_: ()) -> Self { Value::Empty } } -impl TryFrom for String { +impl TryFrom> for String { type Error = EvalexprError; - fn try_from(value: Value) -> Result { + fn try_from(value: Value) -> Result { if let Value::String(value) = value { Ok(value) } else { @@ -235,34 +233,10 @@ impl TryFrom for String { } } -impl TryFrom for FloatType { - type Error = EvalexprError; - - fn try_from(value: Value) -> Result { - if let Value::Float(value) = value { - Ok(value) - } else { - Err(EvalexprError::ExpectedFloat { actual: value }) - } - } -} - -impl TryFrom for IntType { - type Error = EvalexprError; - - fn try_from(value: Value) -> Result { - if let Value::Int(value) = value { - Ok(value) - } else { - Err(EvalexprError::ExpectedInt { actual: value }) - } - } -} - -impl TryFrom for bool { +impl TryFrom> for bool { type Error = EvalexprError; - fn try_from(value: Value) -> Result { + fn try_from(value: Value) -> Result { if let Value::Boolean(value) = value { Ok(value) } else { @@ -271,10 +245,10 @@ impl TryFrom for bool { } } -impl TryFrom for TupleType { +impl TryFrom> for TupleType { type Error = EvalexprError; - fn try_from(value: Value) -> Result { + fn try_from(value: Value) -> Result { if let Value::Tuple(value) = value { Ok(value) } else { @@ -283,10 +257,10 @@ impl TryFrom for TupleType { } } -impl TryFrom for () { +impl TryFrom> for () { type Error = EvalexprError; - fn try_from(value: Value) -> Result { + fn try_from(value: Value) -> Result { if let Value::Empty = value { Ok(()) } else { @@ -302,42 +276,45 @@ mod tests { #[test] fn test_value_conversions() { assert_eq!( - Value::from("string").as_string(), + Value::::from("string").as_string(), Ok(String::from("string")) ); - assert_eq!(Value::from(3).as_int(), Ok(3)); - assert_eq!(Value::from(3.3).as_float(), Ok(3.3)); - assert_eq!(Value::from(true).as_boolean(), Ok(true)); + assert_eq!(Value::::from_int(3).as_int(), Ok(3)); + assert_eq!(Value::::from_float(3.3).as_float(), Ok(3.3)); + assert_eq!(Value::::from(true).as_boolean(), Ok(true)); assert_eq!( - Value::from(TupleType::new()).as_tuple(), + Value::::from(TupleType::new()).as_tuple(), Ok(TupleType::new()) ); } #[test] fn test_value_checks() { - assert!(Value::from("string").is_string()); - assert!(Value::from(3).is_int()); - assert!(Value::from(3.3).is_float()); - assert!(Value::from(true).is_boolean()); - assert!(Value::from(TupleType::new()).is_tuple()); + assert!(Value::::from("string").is_string()); + assert!(Value::::from_int(3).is_int()); + assert!(Value::::from_float(3.3).is_float()); + assert!(Value::::from(true).is_boolean()); + assert!(Value::::from(TupleType::new()).is_tuple()); } #[test] fn test_value_str_from() { - assert_eq!(Value::from("string").str_from(), "string"); - assert_eq!(Value::from(3.3).str_from(), "3.3"); - assert_eq!(Value::from(3).str_from(), "3"); - assert_eq!(Value::from(true).str_from(), "true"); - assert_eq!(Value::from(()).str_from(), "()"); + assert_eq!(Value::::from("string").str_from(), "string"); + assert_eq!(Value::::from_float(3.3).str_from(), "3.3"); + assert_eq!(Value::::from_int(3).str_from(), "3"); + assert_eq!(Value::::from(true).str_from(), "true"); + assert_eq!(Value::::from(()).str_from(), "()"); assert_eq!( - Value::from(TupleType::from([ - Value::from("string"), - Value::from(3.3), - Value::from(3), - Value::from(TupleType::from([Value::from(42), Value::from(4.2),])), - Value::from(()), - Value::from(true), + Value::::from(TupleType::from([ + Value::::from("string"), + Value::::from_float(3.3), + Value::::from_int(3), + Value::::from(TupleType::from([ + Value::::from_int(42), + Value::::from_float(4.2), + ])), + Value::::from(()), + Value::::from(true), ])) .str_from(), r#"("string", 3.3, 3, (42, 4.2), (), true)"# diff --git a/src/value/numeric_types.rs b/src/value/numeric_types.rs new file mode 100644 index 0000000..414948e --- /dev/null +++ b/src/value/numeric_types.rs @@ -0,0 +1,26 @@ +pub trait EvalexprNumericTypes { + type Int: Clone; + type Float: Clone; + + /// Convert an integer to a float using the `as` operator or a similar mechanic. + fn int_as_float(int: &Self::Int) -> Self::Float; + + /// Convert a float to an integer using the `as` operator or a similar mechanic. + fn float_as_int(float: &Self::Float) -> Self::Int; +} + +pub struct DefaultNumericTypes; + +impl EvalexprNumericTypes for DefaultNumericTypes { + type Int = i64; + + type Float = f64; + + fn int_as_float(int: &Self::Int) -> Self::Float { + int as Self::Float + } + + fn float_as_int(float: &Self::Float) -> Self::Int { + float as Self::Int + } +} diff --git a/src/value/value_type.rs b/src/value/value_type.rs index 4ea7395..a3186e8 100644 --- a/src/value/value_type.rs +++ b/src/value/value_type.rs @@ -17,8 +17,8 @@ pub enum ValueType { Empty, } -impl From<&Value> for ValueType { - fn from(value: &Value) -> Self { +impl From<&Value> for ValueType { + fn from(value: &Value) -> Self { match value { Value::String(_) => ValueType::String, Value::Float(_) => ValueType::Float, @@ -30,14 +30,14 @@ impl From<&Value> for ValueType { } } -impl From<&mut Value> for ValueType { - fn from(value: &mut Value) -> Self { - From::<&Value>::from(value) +impl From<&mut Value> for ValueType { + fn from(value: &mut Value) -> Self { + From::<&Value>::from(value) } } -impl From<&&mut Value> for ValueType { - fn from(value: &&mut Value) -> Self { - From::<&Value>::from(*value) +impl From<&&mut Value> for ValueType { + fn from(value: &&mut Value) -> Self { + From::<&Value>::from(*value) } }