use datavalue::OwnedDataValue;
use std::sync::Arc;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct EvaluationConfig {
pub arithmetic_nan_handling: NanHandling,
pub division_by_zero: DivisionByZeroHandling,
pub loose_equality_errors: bool,
pub truthy_evaluator: TruthyEvaluator,
pub numeric_coercion: NumericCoercionConfig,
pub max_recursion_depth: u32,
}
#[derive(Clone, Debug, PartialEq)]
pub enum NanHandling {
ThrowError,
IgnoreValue,
CoerceToZero,
ReturnNull,
}
#[derive(Clone, Debug, PartialEq)]
pub enum DivisionByZeroHandling {
ReturnSaturated,
ThrowError,
ReturnNull,
ReturnInfinity,
}
#[derive(Clone)]
pub enum TruthyEvaluator {
JavaScript,
Python,
StrictBoolean,
Custom(Arc<dyn Fn(&OwnedDataValue) -> bool + Send + Sync>),
}
impl std::fmt::Debug for TruthyEvaluator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::JavaScript => f.write_str("JavaScript"),
Self::Python => f.write_str("Python"),
Self::StrictBoolean => f.write_str("StrictBoolean"),
Self::Custom(_) => f.write_str("Custom(<fn>)"),
}
}
}
impl TruthyEvaluator {
pub fn custom<F>(f: F) -> Self
where
F: Fn(&OwnedDataValue) -> bool + Send + Sync + 'static,
{
Self::Custom(Arc::new(f))
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct NumericCoercionConfig {
pub empty_string_to_zero: bool,
pub null_to_zero: bool,
pub bool_to_number: bool,
pub reject_non_numeric: bool,
pub undefined_to_zero: bool,
}
impl Default for EvaluationConfig {
fn default() -> Self {
Self {
arithmetic_nan_handling: NanHandling::ThrowError,
division_by_zero: DivisionByZeroHandling::ReturnSaturated,
loose_equality_errors: true,
truthy_evaluator: TruthyEvaluator::JavaScript,
numeric_coercion: NumericCoercionConfig::default(),
max_recursion_depth: 256,
}
}
}
impl Default for NumericCoercionConfig {
fn default() -> Self {
Self {
empty_string_to_zero: true,
null_to_zero: true,
bool_to_number: true,
reject_non_numeric: false,
undefined_to_zero: false,
}
}
}
impl NumericCoercionConfig {
#[must_use]
pub fn with_empty_string_to_zero(mut self, value: bool) -> Self {
self.empty_string_to_zero = value;
self
}
#[must_use]
pub fn with_null_to_zero(mut self, value: bool) -> Self {
self.null_to_zero = value;
self
}
#[must_use]
pub fn with_bool_to_number(mut self, value: bool) -> Self {
self.bool_to_number = value;
self
}
#[must_use]
pub fn with_reject_non_numeric(mut self, value: bool) -> Self {
self.reject_non_numeric = value;
self
}
#[must_use]
pub fn with_undefined_to_zero(mut self, value: bool) -> Self {
self.undefined_to_zero = value;
self
}
}
impl EvaluationConfig {
#[must_use]
pub fn with_arithmetic_nan_handling(mut self, value: NanHandling) -> Self {
self.arithmetic_nan_handling = value;
self
}
#[must_use]
pub fn with_division_by_zero(mut self, value: DivisionByZeroHandling) -> Self {
self.division_by_zero = value;
self
}
#[must_use]
pub fn with_loose_equality_errors(mut self, value: bool) -> Self {
self.loose_equality_errors = value;
self
}
#[must_use]
pub fn with_truthy_evaluator(mut self, value: TruthyEvaluator) -> Self {
self.truthy_evaluator = value;
self
}
#[must_use]
pub fn with_numeric_coercion(mut self, value: NumericCoercionConfig) -> Self {
self.numeric_coercion = value;
self
}
#[must_use]
pub fn with_max_recursion_depth(mut self, value: u32) -> Self {
self.max_recursion_depth = value;
self
}
pub fn safe_arithmetic() -> Self {
Self {
arithmetic_nan_handling: NanHandling::IgnoreValue,
division_by_zero: DivisionByZeroHandling::ReturnNull,
loose_equality_errors: false,
..Default::default()
}
}
pub fn strict() -> Self {
Self {
arithmetic_nan_handling: NanHandling::ThrowError,
division_by_zero: DivisionByZeroHandling::ThrowError,
loose_equality_errors: true,
numeric_coercion: NumericCoercionConfig {
empty_string_to_zero: false,
null_to_zero: false,
bool_to_number: false,
reject_non_numeric: true,
undefined_to_zero: false,
},
..Default::default()
}
}
}