Enum DataValue

Source
pub enum DataValue<'a> {
    Null,
    Bool(bool),
    Number(NumberValue),
    String(&'a str),
    Array(&'a [DataValue<'a>]),
    Object(&'a [(&'a str, DataValue<'a>)]),
    DateTime(DateTime<Utc>),
    Duration(Duration),
}
Expand description

A memory-efficient value type that leverages arena allocation.

This replaces the direct dependency on serde_json::Value with a custom implementation optimized for rule evaluation.

Variants§

§

Null

Represents a null value

§

Bool(bool)

Represents a boolean value

§

Number(NumberValue)

Represents a numeric value (integer or floating point)

§

String(&'a str)

Represents a string value (arena-allocated)

§

Array(&'a [DataValue<'a>])

Represents an array of values (arena-allocated)

§

Object(&'a [(&'a str, DataValue<'a>)])

Represents an object with key-value pairs (arena-allocated)

§

DateTime(DateTime<Utc>)

Represents a datetime value

§

Duration(Duration)

Represents a duration value

Implementations§

Source§

impl<'a> DataValue<'a>

Source

pub fn null() -> Self

Creates a null value.

Source

pub fn bool(value: bool) -> Self

Creates a boolean value.

Source

pub fn integer(value: i64) -> Self

Creates an integer value.

Source

pub fn float(value: f64) -> Self

Creates a floating-point value.

Source

pub fn string(arena: &'a DataArena, value: &str) -> Self

Creates a string value.

If the string is empty, returns a string value with the preallocated empty string.

Source

pub fn datetime(value: DateTime<Utc>) -> Self

Creates a datetime value from a chrono::DateTime<Utc>.

Source

pub fn duration(value: Duration) -> Self

Creates a duration value from a chrono::Duration.

Source

pub fn array(arena: &'a DataArena, values: &[DataValue<'a>]) -> Self

Creates an array value.

If the array is empty, returns a value with the preallocated empty array. For small arrays (up to 8 elements), uses an optimized allocation method.

Source

pub fn object( arena: &'a DataArena, entries: &[(&'a str, DataValue<'a>)], ) -> Self

Creates an object value.

If the entries array is empty, returns an object with an empty entries array.

Source

pub fn is_null(&self) -> bool

Returns true if the value is null.

Source

pub fn is_bool(&self) -> bool

Returns true if the value is a boolean.

Source

pub fn is_number(&self) -> bool

Returns true if the value is a number.

Source

pub fn is_string(&self) -> bool

Returns true if the value is a string.

Source

pub fn is_array(&self) -> bool

Returns true if the value is an array.

Examples found in repository?
examples/custom_advance.rs (line 49)
40    fn evaluate<'a>(
41        &self,
42        args: &'a [DataValue<'a>],
43        arena: &'a DataArena,
44    ) -> Result<&'a DataValue<'a>> {
45        // Collect all numeric values
46        let mut numbers = Vec::new();
47
48        // Handle the case where a single array is passed
49        if args.len() == 1 && args[0].is_array() {
50            if let Some(items) = args[0].as_array() {
51                for item in items {
52                    if let Some(n) = item.as_f64() {
53                        numbers.push(n);
54                    }
55                }
56            }
57        } else {
58            // Handle the case where multiple arguments are passed
59            for arg in args {
60                if let Some(n) = arg.as_f64() {
61                    numbers.push(n);
62                }
63            }
64        }
65
66        // Return 0 for empty arrays
67        if numbers.is_empty() {
68            return Ok(arena.alloc(DataValue::Number(NumberValue::from_i64(0))));
69        }
70
71        // Sort the numbers
72        numbers.sort_by(|a, b| a.partial_cmp(b).unwrap());
73
74        // Calculate the median
75        let median = if numbers.len() % 2 == 0 {
76            // Even number of elements - average the middle two
77            let mid = numbers.len() / 2;
78            (numbers[mid - 1] + numbers[mid]) / 2.0
79        } else {
80            // Odd number of elements - take the middle one
81            numbers[numbers.len() / 2]
82        };
83
84        // Return the result
85        Ok(arena.alloc(DataValue::Number(NumberValue::from_f64(median))))
86    }
Source

pub fn is_object(&self) -> bool

Returns true if the value is an object.

Source

pub fn is_datetime(&self) -> bool

Returns true if the value is a datetime.

Source

pub fn is_duration(&self) -> bool

Returns true if the value is a duration.

Source

pub fn as_bool(&self) -> Option<bool>

Returns the value as a boolean, if it is one.

Source

pub fn as_i64(&self) -> Option<i64>

Returns the value as an i64, if it is a number that can be represented as an i64.

Examples found in repository?
examples/custom_simple.rs (line 42)
37fn is_even(args: Vec<DataValue>) -> std::result::Result<DataValue, String> {
38    if args.is_empty() {
39        return Err("is_even requires a number argument".to_string());
40    }
41
42    if let Some(n) = args[0].as_i64() {
43        return Ok(DataValue::Bool(n % 2 == 0));
44    }
45
46    Err("Argument must be a number".to_string())
47}
Source

pub fn as_f64(&self) -> Option<f64>

Returns the value as an f64, if it is a number.

Examples found in repository?
examples/custom_simple.rs (line 13)
8fn double(args: Vec<DataValue>) -> std::result::Result<DataValue, String> {
9    if args.is_empty() {
10        return Err("double operator requires at least one argument".to_string());
11    }
12
13    if let Some(n) = args[0].as_f64() {
14        return Ok(DataValue::Number(NumberValue::from_f64(n * 2.0)));
15    }
16
17    Err("Argument must be a number".to_string())
18}
More examples
Hide additional examples
examples/custom_advance.rs (line 25)
12    fn evaluate<'a>(
13        &self,
14        args: &'a [DataValue<'a>],
15        arena: &'a DataArena,
16    ) -> Result<&'a DataValue<'a>> {
17        // Default to 1 if no arguments provided
18        if args.is_empty() {
19            return Ok(arena.alloc(DataValue::Number(NumberValue::from_i64(1))));
20        }
21
22        // Calculate product of all numeric values
23        let mut product = 1.0;
24        for arg in args {
25            if let Some(n) = arg.as_f64() {
26                product *= n;
27            }
28        }
29
30        // Return the result
31        Ok(arena.alloc(DataValue::Number(NumberValue::from_f64(product))))
32    }
33}
34
35// Define a custom operator that returns the median of a set of numbers
36#[derive(Debug)]
37struct Median;
38
39impl CustomOperator for Median {
40    fn evaluate<'a>(
41        &self,
42        args: &'a [DataValue<'a>],
43        arena: &'a DataArena,
44    ) -> Result<&'a DataValue<'a>> {
45        // Collect all numeric values
46        let mut numbers = Vec::new();
47
48        // Handle the case where a single array is passed
49        if args.len() == 1 && args[0].is_array() {
50            if let Some(items) = args[0].as_array() {
51                for item in items {
52                    if let Some(n) = item.as_f64() {
53                        numbers.push(n);
54                    }
55                }
56            }
57        } else {
58            // Handle the case where multiple arguments are passed
59            for arg in args {
60                if let Some(n) = arg.as_f64() {
61                    numbers.push(n);
62                }
63            }
64        }
65
66        // Return 0 for empty arrays
67        if numbers.is_empty() {
68            return Ok(arena.alloc(DataValue::Number(NumberValue::from_i64(0))));
69        }
70
71        // Sort the numbers
72        numbers.sort_by(|a, b| a.partial_cmp(b).unwrap());
73
74        // Calculate the median
75        let median = if numbers.len() % 2 == 0 {
76            // Even number of elements - average the middle two
77            let mid = numbers.len() / 2;
78            (numbers[mid - 1] + numbers[mid]) / 2.0
79        } else {
80            // Odd number of elements - take the middle one
81            numbers[numbers.len() / 2]
82        };
83
84        // Return the result
85        Ok(arena.alloc(DataValue::Number(NumberValue::from_f64(median))))
86    }
Source

pub fn as_str(&self) -> Option<&str>

Returns the value as a string slice, if it is a string.

Examples found in repository?
examples/custom_simple.rs (line 26)
21fn to_uppercase(args: Vec<DataValue>) -> std::result::Result<DataValue, String> {
22    if args.is_empty() {
23        return Err("to_uppercase requires a string argument".to_string());
24    }
25
26    if let Some(s) = args[0].as_str() {
27        // Use Box::leak to create a static string
28        let upper = s.to_uppercase();
29        let upper_str = Box::leak(upper.into_boxed_str());
30        return Ok(DataValue::String(upper_str));
31    }
32
33    Err("Argument must be a string".to_string())
34}
Source

pub fn as_array(&self) -> Option<&[DataValue<'a>]>

Returns the value as an array slice, if it is an array.

Examples found in repository?
examples/custom_advance.rs (line 50)
40    fn evaluate<'a>(
41        &self,
42        args: &'a [DataValue<'a>],
43        arena: &'a DataArena,
44    ) -> Result<&'a DataValue<'a>> {
45        // Collect all numeric values
46        let mut numbers = Vec::new();
47
48        // Handle the case where a single array is passed
49        if args.len() == 1 && args[0].is_array() {
50            if let Some(items) = args[0].as_array() {
51                for item in items {
52                    if let Some(n) = item.as_f64() {
53                        numbers.push(n);
54                    }
55                }
56            }
57        } else {
58            // Handle the case where multiple arguments are passed
59            for arg in args {
60                if let Some(n) = arg.as_f64() {
61                    numbers.push(n);
62                }
63            }
64        }
65
66        // Return 0 for empty arrays
67        if numbers.is_empty() {
68            return Ok(arena.alloc(DataValue::Number(NumberValue::from_i64(0))));
69        }
70
71        // Sort the numbers
72        numbers.sort_by(|a, b| a.partial_cmp(b).unwrap());
73
74        // Calculate the median
75        let median = if numbers.len() % 2 == 0 {
76            // Even number of elements - average the middle two
77            let mid = numbers.len() / 2;
78            (numbers[mid - 1] + numbers[mid]) / 2.0
79        } else {
80            // Odd number of elements - take the middle one
81            numbers[numbers.len() / 2]
82        };
83
84        // Return the result
85        Ok(arena.alloc(DataValue::Number(NumberValue::from_f64(median))))
86    }
Source

pub fn as_datetime(&self) -> Option<&DateTime<Utc>>

Returns the value as a datetime, if it is a datetime.

Source

pub fn as_duration(&self) -> Option<&Duration>

Returns the value as a duration, if it is a duration.

Source

pub fn as_object(&self) -> Option<&[(&'a str, DataValue<'a>)]>

Returns the value as an object slice, if it is an object.

Source

pub fn coerce_to_bool(&self) -> bool

Coerces the value to a boolean.

The coercion follows JSON Logic rules:

  • null is false
  • false is false
  • Empty string is false
  • Empty array is false
  • Empty object is false
  • 0 is false
  • Everything else is true
Source

pub fn coerce_to_number(&self) -> Option<NumberValue>

Coerces the value to a number according to JSONLogic rules.

Source

pub fn coerce_to_string(&self, arena: &'a DataArena) -> DataValue<'a>

Coerces the value to a string according to JSONLogic rules.

Source

pub fn get(&self, key: &str) -> Option<&DataValue<'a>>

Gets a value from an object by key.

Source

pub fn get_index(&self, index: usize) -> Option<&DataValue<'a>>

Gets a value from an array by index.

Source

pub fn type_name(&self) -> &'static str

Returns a string representation of the type of this value.

Source

pub fn equals(&self, other: &DataValue<'a>) -> bool

Checks if this value equals another value, with type coercion.

Source

pub fn strict_equals(&self, other: &DataValue<'a>) -> bool

Checks if this value strictly equals another value, without type coercion.

Trait Implementations§

Source§

impl<'a> Clone for DataValue<'a>

Source§

fn clone(&self) -> DataValue<'a>

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<'a> Debug for DataValue<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for DataValue<'_>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'a> FromJson<'a> for DataValue<'a>

Source§

fn from_json(json: &JsonValue, arena: &'a DataArena) -> DataValue<'a>

Converts a JSON value to a DataValue, allocating in the given arena.
Source§

impl<'a> PartialEq for DataValue<'a>

Source§

fn eq(&self, other: &DataValue<'a>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl PartialOrd for DataValue<'_>

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl ToJson for DataValue<'_>

Source§

fn to_json(&self) -> JsonValue

Converts a DataValue to a JSON value.
Source§

impl<'a> ValueAccess<'a> for DataValue<'a>

Source§

fn get_path(&self, path: &[PathSegment<'a>]) -> Option<&DataValue<'a>>

Gets a value using a path expression.
Source§

fn get_path_str( &self, arena: &'a DataArena, path: &str, ) -> Option<&DataValue<'a>>

Gets a value using a dot-separated path string.
Source§

impl<'a> StructuralPartialEq for DataValue<'a>

Auto Trait Implementations§

§

impl<'a> Freeze for DataValue<'a>

§

impl<'a> RefUnwindSafe for DataValue<'a>

§

impl<'a> Send for DataValue<'a>

§

impl<'a> Sync for DataValue<'a>

§

impl<'a> Unpin for DataValue<'a>

§

impl<'a> UnwindSafe for DataValue<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.