diff --git a/Cargo.toml b/Cargo.toml index 6065a13..84d0a68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,11 +26,13 @@ path = "src/lib.rs" regex = { version = "1.11.1", optional = true } serde = { version = "1.0.213", features = ["derive"], optional = true } rand = { version = "0.8.5", optional = true } +# num-traits = { version = "0.2.19", optional = true } [features] serde = ["dep:serde"] regex = ["dep:regex"] rand = ["dep:rand"] +# num-traits = ["dep:num-traits"] [dev-dependencies] ron = "0.8.1" diff --git a/src/context/mod.rs b/src/context/mod.rs index 3aba764..82a83f2 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -10,7 +10,7 @@ use crate::{ error::EvalexprResultValue, function::Function, value::{ - numeric_types::{DefaultNumericTypes, EvalexprNumericTypes}, + numeric_types::{default_numeric_types::DefaultNumericTypes, EvalexprNumericTypes}, value_type::ValueType, Value, }, diff --git a/src/error/mod.rs b/src/error/mod.rs index a52a216..3af244e 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -10,7 +10,7 @@ use std::ops::RangeInclusive; use crate::{ token::PartialToken, value::{ - numeric_types::{DefaultNumericTypes, EvalexprNumericTypes}, + numeric_types::{default_numeric_types::DefaultNumericTypes, EvalexprNumericTypes}, value_type::ValueType, }, }; @@ -464,7 +464,10 @@ pub type EvalexprResultValue = #[cfg(test)] mod tests { - use crate::{value::numeric_types::DefaultNumericTypes, EvalexprError, Value, ValueType}; + use crate::{ + value::numeric_types::default_numeric_types::DefaultNumericTypes, EvalexprError, Value, + ValueType, + }; /// Tests whose only use is to bring test coverage of trivial lines up, like trivial constructors. #[test] diff --git a/src/function/mod.rs b/src/function/mod.rs index e61fde1..b6fe297 100644 --- a/src/function/mod.rs +++ b/src/function/mod.rs @@ -3,7 +3,7 @@ use std::fmt; use crate::{ error::EvalexprResultValue, value::{ - numeric_types::{DefaultNumericTypes, EvalexprNumericTypes}, + numeric_types::{default_numeric_types::DefaultNumericTypes, EvalexprNumericTypes}, Value, }, }; diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 0d3ea00..54785c6 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -2,7 +2,7 @@ use crate::{ error::EvalexprResultValue, token, tree, value::{ - numeric_types::{DefaultNumericTypes, EvalexprNumericTypes}, + numeric_types::{default_numeric_types::DefaultNumericTypes, EvalexprNumericTypes}, TupleType, }, Context, ContextWithMutableVariables, EmptyType, EvalexprError, EvalexprResult, HashMapContext, diff --git a/src/lib.rs b/src/lib.rs index f983020..4f8a35a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -592,7 +592,10 @@ pub use crate::{ token::PartialToken, tree::Node, value::{ - numeric_types::{DefaultNumericTypes, EvalexprFloat, EvalexprInt, EvalexprNumericTypes}, + numeric_types::{ + default_numeric_types::DefaultNumericTypes, EvalexprFloat, EvalexprInt, + EvalexprNumericTypes, + }, value_type::ValueType, EmptyType, TupleType, Value, EMPTY_VALUE, }, diff --git a/src/operator/mod.rs b/src/operator/mod.rs index 13ca5f0..a815f79 100644 --- a/src/operator/mod.rs +++ b/src/operator/mod.rs @@ -4,7 +4,10 @@ use crate::{ context::Context, error::*, value::{ - numeric_types::{DefaultNumericTypes, EvalexprFloat, EvalexprInt, EvalexprNumericTypes}, + numeric_types::{ + default_numeric_types::DefaultNumericTypes, EvalexprFloat, EvalexprInt, + EvalexprNumericTypes, + }, Value, }, ContextWithMutableVariables, diff --git a/src/token/mod.rs b/src/token/mod.rs index f4183d0..998cfda 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -2,7 +2,9 @@ use std::str::FromStr; use crate::{ error::{EvalexprError, EvalexprResult}, - value::numeric_types::{DefaultNumericTypes, EvalexprInt, EvalexprNumericTypes}, + value::numeric_types::{ + default_numeric_types::DefaultNumericTypes, EvalexprInt, EvalexprNumericTypes, + }, }; mod display; @@ -507,7 +509,7 @@ fn parse_dec_or_hex( mod tests { use crate::{ token::{char_to_partial_token, tokenize, Token}, - value::numeric_types::DefaultNumericTypes, + value::numeric_types::default_numeric_types::DefaultNumericTypes, }; use std::fmt::Write; diff --git a/src/tree/mod.rs b/src/tree/mod.rs index d5f6166..51d200c 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -2,7 +2,7 @@ use crate::{ error::EvalexprResultValue, token::Token, value::{ - numeric_types::{DefaultNumericTypes, EvalexprNumericTypes}, + numeric_types::{default_numeric_types::DefaultNumericTypes, EvalexprNumericTypes}, TupleType, EMPTY_VALUE, }, Context, ContextWithMutableVariables, EmptyType, HashMapContext, diff --git a/src/value/mod.rs b/src/value/mod.rs index 5e2aa3a..1ecf7d3 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,7 +1,7 @@ use crate::error::{EvalexprError, EvalexprResult, EvalexprResultValue}; use std::{convert::TryFrom, ops::RangeInclusive}; -use self::numeric_types::{DefaultNumericTypes, EvalexprNumericTypes}; +use self::numeric_types::{default_numeric_types::DefaultNumericTypes, EvalexprNumericTypes}; mod display; pub mod numeric_types; @@ -276,7 +276,9 @@ impl TryFrom> for () { #[cfg(test)] mod tests { - use crate::value::{numeric_types::DefaultNumericTypes, TupleType, Value}; + use crate::value::{ + numeric_types::default_numeric_types::DefaultNumericTypes, TupleType, Value, + }; #[test] fn test_value_conversions() { diff --git a/src/value/numeric_types.rs b/src/value/numeric_types.rs index 1da4c11..b74e9b6 100644 --- a/src/value/numeric_types.rs +++ b/src/value/numeric_types.rs @@ -1,11 +1,14 @@ use std::{ - convert::TryInto, fmt::{Debug, Display}, - ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub}, + ops::{Add, Div, Mul, Neg, Rem, Sub}, str::FromStr, }; -use crate::{EvalexprError, EvalexprResult, Value}; +use crate::EvalexprResult; + +pub mod default_numeric_types; +/*#[cfg(feature = "num-traits")] +pub mod num_traits_numeric_types;*/ /// A trait to parameterise `evalexpr` with an int type and a float type. /// @@ -224,292 +227,3 @@ pub trait EvalexprFloat>: /// If the feature `rand` is not enabled, then this method always returns [`EvalexprError::RandNotEnabled`]. fn random() -> EvalexprResult; } - -/// See [`EvalexprNumericTypes`]. -/// -/// This empty struct uses [`i64`] as its integer type and [`f64`] as its float type. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] -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 - } -} - -impl> EvalexprInt for i64 { - const MIN: Self = Self::MIN; - const MAX: Self = Self::MAX; - - fn from_usize(int: usize) -> EvalexprResult { - int.try_into() - .map_err(|_| EvalexprError::IntFromUsize { usize_int: int }) - } - - fn into_usize(&self) -> EvalexprResult { - if *self >= 0 { - (*self as u64) - .try_into() - .map_err(|_| EvalexprError::IntIntoUsize { int: *self }) - } else { - Err(EvalexprError::IntIntoUsize { int: *self }) - } - } - - fn from_hex_str(literal: &str) -> Result { - Self::from_str_radix(literal, 16).map_err(|_| ()) - } - - fn checked_add(&self, rhs: &Self) -> EvalexprResult { - let result = (*self).checked_add(*rhs); - if let Some(result) = result { - Ok(result) - } else { - Err(EvalexprError::addition_error( - Value::::from_int(*self), - Value::::from_int(*rhs), - )) - } - } - - fn checked_sub(&self, rhs: &Self) -> EvalexprResult { - let result = (*self).checked_sub(*rhs); - if let Some(result) = result { - Ok(result) - } else { - Err(EvalexprError::subtraction_error( - Value::::from_int(*self), - Value::::from_int(*rhs), - )) - } - } - - fn checked_neg(&self) -> EvalexprResult { - let result = (*self).checked_neg(); - if let Some(result) = result { - Ok(result) - } else { - Err(EvalexprError::negation_error( - Value::::from_int(*self), - )) - } - } - - fn checked_mul(&self, rhs: &Self) -> EvalexprResult { - let result = (*self).checked_mul(*rhs); - if let Some(result) = result { - Ok(result) - } else { - Err(EvalexprError::multiplication_error( - Value::::from_int(*self), - Value::::from_int(*rhs), - )) - } - } - - fn checked_div(&self, rhs: &Self) -> EvalexprResult { - let result = (*self).checked_div(*rhs); - if let Some(result) = result { - Ok(result) - } else { - Err(EvalexprError::division_error( - Value::::from_int(*self), - Value::::from_int(*rhs), - )) - } - } - - fn checked_rem(&self, rhs: &Self) -> EvalexprResult { - let result = (*self).checked_rem(*rhs); - if let Some(result) = result { - Ok(result) - } else { - Err(EvalexprError::modulation_error( - Value::::from_int(*self), - Value::::from_int(*rhs), - )) - } - } - - fn abs(&self) -> EvalexprResult { - Ok((*self).abs()) - } - - fn bitand(&self, rhs: &Self) -> Self { - BitAnd::bitand(*self, *rhs) - } - - fn bitor(&self, rhs: &Self) -> Self { - BitOr::bitor(*self, *rhs) - } - - fn bitxor(&self, rhs: &Self) -> Self { - BitXor::bitxor(*self, *rhs) - } - - fn bitnot(&self) -> Self { - Not::not(*self) - } - - fn bit_shift_left(&self, rhs: &Self) -> Self { - Shl::shl(*self, *rhs) - } - - fn bit_shift_right(&self, rhs: &Self) -> Self { - Shr::shr(*self, *rhs) - } -} - -impl> EvalexprFloat for f64 { - const MIN: Self = Self::NEG_INFINITY; - const MAX: Self = Self::INFINITY; - - fn pow(&self, exponent: &Self) -> Self { - (*self).powf(*exponent) - } - - fn ln(&self) -> Self { - (*self).ln() - } - - fn log(&self, base: &Self) -> Self { - (*self).log(*base) - } - - fn log2(&self) -> Self { - (*self).log2() - } - - fn log10(&self) -> Self { - (*self).log10() - } - - fn exp(&self) -> Self { - (*self).exp() - } - - fn exp2(&self) -> Self { - (*self).exp2() - } - - fn cos(&self) -> Self { - (*self).cos() - } - - fn cosh(&self) -> Self { - (*self).cosh() - } - - fn acos(&self) -> Self { - (*self).acos() - } - - fn acosh(&self) -> Self { - (*self).acosh() - } - - fn sin(&self) -> Self { - (*self).sin() - } - - fn sinh(&self) -> Self { - (*self).sinh() - } - - fn asin(&self) -> Self { - (*self).asin() - } - - fn asinh(&self) -> Self { - (*self).asinh() - } - - fn tan(&self) -> Self { - (*self).tan() - } - - fn tanh(&self) -> Self { - (*self).tanh() - } - - fn atan(&self) -> Self { - (*self).atan() - } - - fn atanh(&self) -> Self { - (*self).atanh() - } - - fn atan2(&self, x: &Self) -> Self { - (*self).atan2(*x) - } - - fn sqrt(&self) -> Self { - (*self).sqrt() - } - - fn cbrt(&self) -> Self { - (*self).cbrt() - } - - fn hypot(&self, other: &Self) -> Self { - (*self).hypot(*other) - } - - fn floor(&self) -> Self { - (*self).floor() - } - - fn round(&self) -> Self { - (*self).round() - } - - fn ceil(&self) -> Self { - (*self).ceil() - } - - fn is_nan(&self) -> bool { - (*self).is_nan() - } - - fn is_finite(&self) -> bool { - (*self).is_finite() - } - - fn is_infinite(&self) -> bool { - (*self).is_infinite() - } - - fn is_normal(&self) -> bool { - (*self).is_normal() - } - - fn abs(&self) -> Self { - (*self).abs() - } - - fn min(&self, other: &Self) -> Self { - (*self).min(*other) - } - - fn max(&self, other: &Self) -> Self { - (*self).max(*other) - } - - fn random() -> EvalexprResult { - #[cfg(feature = "rand")] - let result = Ok(rand::random()); - - #[cfg(not(feature = "rand"))] - let result = Err(EvalexprError::RandNotEnabled); - - result - } -} diff --git a/src/value/numeric_types/default_numeric_types.rs b/src/value/numeric_types/default_numeric_types.rs new file mode 100644 index 0000000..1780a8b --- /dev/null +++ b/src/value/numeric_types/default_numeric_types.rs @@ -0,0 +1,294 @@ +use std::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; + +use crate::{EvalexprError, EvalexprResult, Value}; + +use super::{EvalexprFloat, EvalexprInt, EvalexprNumericTypes}; + +/// See [`EvalexprNumericTypes`]. +/// +/// This empty struct uses [`i64`] as its integer type and [`f64`] as its float type. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +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 + } +} + +impl> EvalexprInt for i64 { + const MIN: Self = Self::MIN; + const MAX: Self = Self::MAX; + + fn from_usize(int: usize) -> EvalexprResult { + int.try_into() + .map_err(|_| EvalexprError::IntFromUsize { usize_int: int }) + } + + fn into_usize(&self) -> EvalexprResult { + if *self >= 0 { + (*self as u64) + .try_into() + .map_err(|_| EvalexprError::IntIntoUsize { int: *self }) + } else { + Err(EvalexprError::IntIntoUsize { int: *self }) + } + } + + fn from_hex_str(literal: &str) -> Result { + Self::from_str_radix(literal, 16).map_err(|_| ()) + } + + fn checked_add(&self, rhs: &Self) -> EvalexprResult { + let result = (*self).checked_add(*rhs); + if let Some(result) = result { + Ok(result) + } else { + Err(EvalexprError::addition_error( + Value::::from_int(*self), + Value::::from_int(*rhs), + )) + } + } + + fn checked_sub(&self, rhs: &Self) -> EvalexprResult { + let result = (*self).checked_sub(*rhs); + if let Some(result) = result { + Ok(result) + } else { + Err(EvalexprError::subtraction_error( + Value::::from_int(*self), + Value::::from_int(*rhs), + )) + } + } + + fn checked_neg(&self) -> EvalexprResult { + let result = (*self).checked_neg(); + if let Some(result) = result { + Ok(result) + } else { + Err(EvalexprError::negation_error( + Value::::from_int(*self), + )) + } + } + + fn checked_mul(&self, rhs: &Self) -> EvalexprResult { + let result = (*self).checked_mul(*rhs); + if let Some(result) = result { + Ok(result) + } else { + Err(EvalexprError::multiplication_error( + Value::::from_int(*self), + Value::::from_int(*rhs), + )) + } + } + + fn checked_div(&self, rhs: &Self) -> EvalexprResult { + let result = (*self).checked_div(*rhs); + if let Some(result) = result { + Ok(result) + } else { + Err(EvalexprError::division_error( + Value::::from_int(*self), + Value::::from_int(*rhs), + )) + } + } + + fn checked_rem(&self, rhs: &Self) -> EvalexprResult { + let result = (*self).checked_rem(*rhs); + if let Some(result) = result { + Ok(result) + } else { + Err(EvalexprError::modulation_error( + Value::::from_int(*self), + Value::::from_int(*rhs), + )) + } + } + + fn abs(&self) -> EvalexprResult { + Ok((*self).abs()) + } + + fn bitand(&self, rhs: &Self) -> Self { + BitAnd::bitand(*self, *rhs) + } + + fn bitor(&self, rhs: &Self) -> Self { + BitOr::bitor(*self, *rhs) + } + + fn bitxor(&self, rhs: &Self) -> Self { + BitXor::bitxor(*self, *rhs) + } + + fn bitnot(&self) -> Self { + Not::not(*self) + } + + fn bit_shift_left(&self, rhs: &Self) -> Self { + Shl::shl(*self, *rhs) + } + + fn bit_shift_right(&self, rhs: &Self) -> Self { + Shr::shr(*self, *rhs) + } +} + +impl> EvalexprFloat for f64 { + const MIN: Self = Self::NEG_INFINITY; + const MAX: Self = Self::INFINITY; + + fn pow(&self, exponent: &Self) -> Self { + (*self).powf(*exponent) + } + + fn ln(&self) -> Self { + (*self).ln() + } + + fn log(&self, base: &Self) -> Self { + (*self).log(*base) + } + + fn log2(&self) -> Self { + (*self).log2() + } + + fn log10(&self) -> Self { + (*self).log10() + } + + fn exp(&self) -> Self { + (*self).exp() + } + + fn exp2(&self) -> Self { + (*self).exp2() + } + + fn cos(&self) -> Self { + (*self).cos() + } + + fn cosh(&self) -> Self { + (*self).cosh() + } + + fn acos(&self) -> Self { + (*self).acos() + } + + fn acosh(&self) -> Self { + (*self).acosh() + } + + fn sin(&self) -> Self { + (*self).sin() + } + + fn sinh(&self) -> Self { + (*self).sinh() + } + + fn asin(&self) -> Self { + (*self).asin() + } + + fn asinh(&self) -> Self { + (*self).asinh() + } + + fn tan(&self) -> Self { + (*self).tan() + } + + fn tanh(&self) -> Self { + (*self).tanh() + } + + fn atan(&self) -> Self { + (*self).atan() + } + + fn atanh(&self) -> Self { + (*self).atanh() + } + + fn atan2(&self, x: &Self) -> Self { + (*self).atan2(*x) + } + + fn sqrt(&self) -> Self { + (*self).sqrt() + } + + fn cbrt(&self) -> Self { + (*self).cbrt() + } + + fn hypot(&self, other: &Self) -> Self { + (*self).hypot(*other) + } + + fn floor(&self) -> Self { + (*self).floor() + } + + fn round(&self) -> Self { + (*self).round() + } + + fn ceil(&self) -> Self { + (*self).ceil() + } + + fn is_nan(&self) -> bool { + (*self).is_nan() + } + + fn is_finite(&self) -> bool { + (*self).is_finite() + } + + fn is_infinite(&self) -> bool { + (*self).is_infinite() + } + + fn is_normal(&self) -> bool { + (*self).is_normal() + } + + fn abs(&self) -> Self { + (*self).abs() + } + + fn min(&self, other: &Self) -> Self { + (*self).min(*other) + } + + fn max(&self, other: &Self) -> Self { + (*self).max(*other) + } + + fn random() -> EvalexprResult { + #[cfg(feature = "rand")] + let result = Ok(rand::random()); + + #[cfg(not(feature = "rand"))] + let result = Err(EvalexprError::RandNotEnabled); + + result + } +} diff --git a/src/value/numeric_types/num_traits_numeric_types.rs b/src/value/numeric_types/num_traits_numeric_types.rs new file mode 100644 index 0000000..d48554d --- /dev/null +++ b/src/value/numeric_types/num_traits_numeric_types.rs @@ -0,0 +1,10 @@ +use std::marker::PhantomData; + +/// See [`EvalexprNumericTypes`]. +/// +/// This empty struct uses the given type parameters as int and float types. +/// Note that the type parameters need to fulfil the right set of `num-traits` traits for this type to implement `EvalexprNumericTypes`. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct NumTraitsNumericTypes { + phantom_data: PhantomData<(Int, Float)>, +}