Skip to main content

datalogic_rs/
eval_input.rs

1//! Input adapter for [`crate::Engine::evaluate`] (the raw-arena tier) and
2//! [`crate::Session::eval_borrowed`].
3//!
4//! [`EvalInput`] lets the borrowed-result entry points accept any of the
5//! input shapes a caller is likely to have on hand:
6//!
7//! - `&'a DataValue<'a>` — already arena-resident; passed through unchanged.
8//! - `DataValue<'a>` — single bumpalo allocation into the arena.
9//! - `&OwnedDataValue` — deep-borrowed into the arena.
10//! - `&ParsedData` — parse-once handle; passed through unchanged (zero cost).
11//! - `&str` — JSON-parsed via [`datavalue::DataValue::from_str`].
12//! - `&serde_json::Value` (`serde_json`) — deep-converted into the arena.
13//!
14//! `EvalInput` carries the arena lifetime in its trait parameter, so it
15//! is the right adapter when the **caller** supplies the arena. For the
16//! one-shot owned-result methods on [`crate::Engine`] and the module-
17//! level `eval*` helpers (where the arena lives **inside** the call),
18//! the engine instead uses [`OwnedInput`], which doesn't carry an arena
19//! lifetime — see that trait for the supported shapes.
20//!
21//! Conversion is fallible because the `&str` impl can return a parse
22//! error; the borrow / owned-clone impls always succeed and return
23//! [`Ok`] without touching the arena beyond the documented per-impl
24//! cost.
25
26use bumpalo::Bump;
27use datavalue::OwnedDataValue;
28
29use crate::Result;
30use crate::arena::DataValue;
31
32/// Sealed-trait scaffolding — the [`Sealed`] super-bound lives in this
33/// private module so external crates cannot implement [`EvalInput`].
34/// The set of supported input shapes is a closed class defined entirely
35/// in this file.
36mod sealed {
37    pub trait Sealed {}
38}
39
40/// Adapter trait that converts a value into a `&'a DataValue<'a>` borrowed
41/// from the caller-supplied arena. **Sealed** — the supported input
42/// shapes are listed in this file; external crates cannot add new ones.
43pub trait EvalInput<'a>: sealed::Sealed {
44    /// Materialise `self` as a `&'a DataValue<'a>` in `arena`.
45    ///
46    /// Implementations either pass through an existing arena reference (zero
47    /// cost), allocate one node, or deep-convert from an owned tree.
48    fn into_arena_value(self, arena: &'a Bump) -> Result<&'a DataValue<'a>>;
49}
50
51impl<'a> sealed::Sealed for &'a DataValue<'a> {}
52impl<'a> EvalInput<'a> for &'a DataValue<'a> {
53    #[inline]
54    fn into_arena_value(self, _arena: &'a Bump) -> Result<&'a DataValue<'a>> {
55        Ok(self)
56    }
57}
58
59impl<'a> sealed::Sealed for DataValue<'a> {}
60impl<'a> EvalInput<'a> for DataValue<'a> {
61    #[inline]
62    fn into_arena_value(self, arena: &'a Bump) -> Result<&'a DataValue<'a>> {
63        Ok(arena.alloc(self))
64    }
65}
66
67impl sealed::Sealed for &str {}
68impl<'a> EvalInput<'a> for &'a str {
69    #[inline]
70    fn into_arena_value(self, arena: &'a Bump) -> Result<&'a DataValue<'a>> {
71        let av = DataValue::from_str(self, arena)?;
72        Ok(arena.alloc(av))
73    }
74}
75
76// `&String` derefs to `&str`, but trait resolution doesn't autoderef
77// across trait impls — accepting `&String` directly here saves callers
78// from writing `payload.as_str()` at every call site.
79impl sealed::Sealed for &String {}
80impl<'a> EvalInput<'a> for &'a String {
81    #[inline]
82    fn into_arena_value(self, arena: &'a Bump) -> Result<&'a DataValue<'a>> {
83        <&'a str as EvalInput<'a>>::into_arena_value(self.as_str(), arena)
84    }
85}
86
87impl sealed::Sealed for &OwnedDataValue {}
88impl<'a> EvalInput<'a> for &'a OwnedDataValue {
89    #[inline]
90    fn into_arena_value(self, arena: &'a Bump) -> Result<&'a DataValue<'a>> {
91        Ok(arena.alloc(self.to_arena(arena)))
92    }
93}
94
95impl sealed::Sealed for &crate::ParsedData {}
96impl<'a> EvalInput<'a> for &'a crate::ParsedData {
97    #[inline]
98    fn into_arena_value(self, _arena: &'a Bump) -> Result<&'a DataValue<'a>> {
99        Ok(self.value())
100    }
101}
102
103#[cfg(feature = "serde_json")]
104impl sealed::Sealed for &serde_json::Value {}
105#[cfg(feature = "serde_json")]
106impl<'a> EvalInput<'a> for &'a serde_json::Value {
107    #[inline]
108    fn into_arena_value(self, arena: &'a Bump) -> Result<&'a DataValue<'a>> {
109        let av = crate::arena::value_to_data(self, arena);
110        Ok(arena.alloc(av))
111    }
112}
113
114// ============================================================
115// OwnedInput — arena-lifetime-free counterpart for one-shot calls
116// ============================================================
117
118/// Adapter trait for [`crate::Engine::eval`] / [`crate::Engine::eval_str`]
119// `Engine::eval_into` is gated behind `serde_json`. Link it when the
120// feature is on; otherwise reference it as code text to keep the docs
121// resolvable in a default-features build.
122#[cfg_attr(
123    feature = "serde_json",
124    doc = "/ [`crate::Engine::eval_into`] and the module-level `datalogic::eval*`"
125)]
126#[cfg_attr(
127    not(feature = "serde_json"),
128    doc = "(plus `Engine::eval_into` with the `serde_json` feature) and the module-level `datalogic::eval*`"
129)]
130/// helpers, where the engine creates and owns the arena per call.
131///
132/// Unlike [`EvalInput`] (which carries an arena lifetime), `OwnedInput`
133/// produces an [`OwnedDataValue`] without borrowing into a caller arena.
134/// The engine then deep-borrows that owned value into its per-call
135/// bump. Sealed; the supported set is closed:
136///
137/// - `&str` — JSON-parsed.
138/// - `&String` — JSON-parsed.
139/// - `&OwnedDataValue` — cloned.
140/// - `OwnedDataValue` — moved.
141/// - `&serde_json::Value` (`serde_json`) — deep-converted.
142///
143/// For the borrowed-result paths, use [`EvalInput`] instead.
144pub trait OwnedInput: sealed::Sealed {
145    /// Materialise `self` as an owned data value.
146    fn into_owned_input(self) -> Result<OwnedDataValue>;
147}
148
149impl OwnedInput for &str {
150    #[inline]
151    fn into_owned_input(self) -> Result<OwnedDataValue> {
152        Ok(OwnedDataValue::from_json(self)?)
153    }
154}
155
156impl OwnedInput for &String {
157    #[inline]
158    fn into_owned_input(self) -> Result<OwnedDataValue> {
159        Ok(OwnedDataValue::from_json(self.as_str())?)
160    }
161}
162
163impl OwnedInput for &OwnedDataValue {
164    #[inline]
165    fn into_owned_input(self) -> Result<OwnedDataValue> {
166        Ok(self.clone())
167    }
168}
169
170impl sealed::Sealed for OwnedDataValue {}
171impl OwnedInput for OwnedDataValue {
172    #[inline]
173    fn into_owned_input(self) -> Result<OwnedDataValue> {
174        Ok(self)
175    }
176}
177
178#[cfg(feature = "serde_json")]
179impl OwnedInput for &serde_json::Value {
180    #[inline]
181    fn into_owned_input(self) -> Result<OwnedDataValue> {
182        Ok(crate::serde_bridge::owned_from_serde(self))
183    }
184}