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