datalogic_rs/arena/
custom.rs

1use crate::arena::DataArena;
2use crate::logic::Result;
3use crate::value::DataValue;
4use crate::LogicError;
5use std::collections::HashMap;
6use std::fmt;
7
8/// Trait for custom JSONLogic operators
9pub trait CustomOperator: fmt::Debug + Send + Sync {
10    /// Evaluate the custom operator with the given arguments
11    ///
12    /// This function takes owned DataValue arguments and returns an owned DataValue.
13    /// The actual allocation in the arena is handled internally.
14    fn evaluate<'a>(
15        &self,
16        args: &'a [DataValue<'a>],
17        arena: &'a DataArena,
18    ) -> Result<&'a DataValue<'a>>;
19}
20
21/// Registry for custom operator functions
22#[derive(Default)]
23pub struct CustomOperatorRegistry {
24    operators: HashMap<String, Box<dyn CustomOperator>>,
25}
26
27impl CustomOperatorRegistry {
28    /// Creates a new empty custom operator registry
29    pub fn new() -> Self {
30        Self {
31            operators: HashMap::new(),
32        }
33    }
34
35    /// Registers a custom operator function
36    pub fn register(&mut self, name: &str, operator: Box<dyn CustomOperator>) {
37        self.operators.insert(name.to_string(), operator);
38    }
39
40    /// Returns a reference to a custom operator by name
41    pub fn get(&self, name: &str) -> Option<&dyn CustomOperator> {
42        self.operators.get(name).map(|op| op.as_ref())
43    }
44}
45
46/// A function type that works with owned DataValues rather than arena references
47///
48/// This type allows implementing custom operators without dealing with
49/// arena allocation or lifetimes. The function takes owned DataValues
50/// and returns an owned DataValue.
51pub type SimpleOperatorFn = fn(Vec<DataValue>) -> std::result::Result<DataValue, String>;
52
53/// An adapter that converts between the simple owned-value API and the arena-based API
54///
55/// This adapter wraps a function that works with owned DataValues and implements
56/// the CustomOperator trait, handling all arena allocation details internally.
57#[derive(Debug)]
58pub struct SimpleOperatorAdapter {
59    function: SimpleOperatorFn,
60    name: String,
61}
62
63impl SimpleOperatorAdapter {
64    /// Create a new adapter wrapping a simple operator function
65    pub fn new(name: &str, function: SimpleOperatorFn) -> Self {
66        Self {
67            function,
68            name: name.to_string(),
69        }
70    }
71}
72
73impl CustomOperator for SimpleOperatorAdapter {
74    fn evaluate<'a>(
75        &self,
76        args: &'a [DataValue<'a>],
77        arena: &'a DataArena,
78    ) -> Result<&'a DataValue<'a>> {
79        // Convert arena-referenced DataValues to owned DataValues
80        let owned_args = args.iter().map(|arg| arg.to_owned()).collect::<Vec<_>>();
81
82        // Call the user's simple function that works with owned values
83        match (self.function)(owned_args) {
84            Ok(result) => {
85                // Handle basic scalar types directly
86                match result {
87                    DataValue::Null => Ok(arena.null_value()),
88                    DataValue::Bool(true) => Ok(arena.true_value()),
89                    DataValue::Bool(false) => Ok(arena.false_value()),
90                    DataValue::Number(n) => Ok(arena.alloc(DataValue::Number(n))),
91                    DataValue::String(s) => {
92                        let s_arena = arena.alloc_str(s);
93                        Ok(arena.alloc(DataValue::String(s_arena)))
94                    }
95                    // For complex types like Array and Object, convert to string as a fallback
96                    DataValue::Array(_) | DataValue::Object(_) => {
97                        let str_rep = format!("{:?}", result);
98                        let s_arena = arena.alloc_str(&str_rep);
99                        Ok(arena.alloc(DataValue::String(s_arena)))
100                    }
101                    // Handle DateTime and Duration types
102                    DataValue::DateTime(dt) => Ok(arena.alloc(DataValue::DateTime(dt))),
103                    DataValue::Duration(dur) => Ok(arena.alloc(DataValue::Duration(dur))),
104                }
105            }
106            Err(msg) => Err(LogicError::ParseError {
107                reason: format!("Error in operator '{}': {}", self.name, msg),
108            }),
109        }
110    }
111}