Skip to main content

datalogic_rs/
roots.rs

1//! [`Roots`]: several values evaluated as one top-level object, without
2//! building that object first.
3
4use bumpalo::Bump;
5use datavalue::OwnedDataValue;
6
7use crate::Result;
8use crate::arena::DataValue;
9use crate::eval_input::sealed;
10use crate::{EvalInput, OwnedInput, ParsedData};
11
12/// Several values evaluated as the fields of one top-level object, each
13/// under its own name, without building that object.
14///
15/// A host that keeps a request's payload, its metadata and its claims in
16/// separate values would otherwise copy all of them into one combined value
17/// for every evaluation (`json!({"data": data, "metadata": metadata})`).
18/// `Roots` borrows each part instead: a rule reads `{"var": "data.user"}`
19/// or `{"var": "metadata.channel"}` exactly as it would from the combined
20/// object, and the engine views each part in place the way it views a
21/// single input of that type.
22///
23/// Accepted wherever the engine takes input, by reference or by value
24/// ([`EvalInput`] and [`OwnedInput`]). Each root may be a
25/// `&serde_json::Value` (`serde_json` feature), `&OwnedDataValue`,
26/// `&ParsedData` or `&DataValue`, mixed freely.
27///
28/// Names keep the order they were first given in, which is the key order
29/// of the object a rule sees (`{"var": ""}`). Giving a name again replaces
30/// its value in place.
31///
32/// # Example
33///
34/// ```rust
35/// # #[cfg(feature = "serde_json")] {
36/// use datalogic_rs::{Engine, Roots};
37/// use serde_json::json;
38///
39/// let data = json!({"user": {"name": "ana"}});
40/// let metadata = json!({"channel": "web"});
41///
42/// let engine = Engine::new();
43/// let rule = engine
44///     .compile(r#"{"cat": [{"var": "data.user.name"}, "@", {"var": "metadata.channel"}]}"#)
45///     .unwrap();
46///
47/// let roots = Roots::from([("data", &data), ("metadata", &metadata)]);
48/// let mut session = engine.session();
49/// assert_eq!(session.eval_str(&rule, &roots).unwrap(), r#""ana@web""#);
50/// # }
51/// ```
52#[derive(Debug, Clone, Default)]
53pub struct Roots<'r> {
54    parts: Vec<(&'r str, RootValue<'r>)>,
55}
56
57/// One value a [`Roots`] holds. Built from a reference to any accepted
58/// input type through `From`; there is nothing else to do with it.
59#[derive(Debug, Clone, Copy)]
60pub struct RootValue<'r>(Part<'r>);
61
62#[derive(Debug, Clone, Copy)]
63enum Part<'r> {
64    Owned(&'r OwnedDataValue),
65    #[cfg(feature = "serde_json")]
66    Json(&'r serde_json::Value),
67    Parsed(&'r ParsedData),
68    Arena(&'r DataValue<'r>),
69}
70
71impl<'r> From<&'r OwnedDataValue> for RootValue<'r> {
72    fn from(v: &'r OwnedDataValue) -> Self {
73        RootValue(Part::Owned(v))
74    }
75}
76
77#[cfg(feature = "serde_json")]
78impl<'r> From<&'r serde_json::Value> for RootValue<'r> {
79    fn from(v: &'r serde_json::Value) -> Self {
80        RootValue(Part::Json(v))
81    }
82}
83
84impl<'r> From<&'r ParsedData> for RootValue<'r> {
85    fn from(v: &'r ParsedData) -> Self {
86        RootValue(Part::Parsed(v))
87    }
88}
89
90impl<'r> From<&'r DataValue<'r>> for RootValue<'r> {
91    fn from(v: &'r DataValue<'r>) -> Self {
92        RootValue(Part::Arena(v))
93    }
94}
95
96impl<'r> RootValue<'r> {
97    /// The part as an arena value: leaves borrowed, spines built in
98    /// `arena`, exactly as the part's own input impl does it.
99    fn view_in<'a>(self, arena: &'a Bump) -> DataValue<'a>
100    where
101        'r: 'a,
102    {
103        match self.0 {
104            Part::Owned(v) => v.view_in(arena),
105            #[cfg(feature = "serde_json")]
106            Part::Json(v) => crate::arena::value_to_data(v, arena),
107            Part::Parsed(v) => *v.value(),
108            Part::Arena(v) => *v,
109        }
110    }
111
112    /// [`Self::view_in`], keeping only what `under` reads.
113    fn project_in<'a>(self, under: &crate::projection::Projection, arena: &'a Bump) -> DataValue<'a>
114    where
115        'r: 'a,
116    {
117        match self.0 {
118            Part::Owned(v) => under.owned(v, arena),
119            #[cfg(feature = "serde_json")]
120            Part::Json(v) => under.serde(v, arena),
121            // Already in an arena: kept as is, at no cost.
122            Part::Parsed(v) => *v.value(),
123            Part::Arena(v) => *v,
124        }
125    }
126
127    fn to_owned_value(self) -> OwnedDataValue {
128        match self.0 {
129            Part::Owned(v) => v.clone(),
130            #[cfg(feature = "serde_json")]
131            Part::Json(v) => crate::serde_bridge::owned_from_serde(v),
132            Part::Parsed(v) => v.value().to_owned(),
133            Part::Arena(v) => v.to_owned(),
134        }
135    }
136}
137
138impl<'r> Roots<'r> {
139    /// No roots: evaluates as an empty object.
140    pub fn new() -> Self {
141        Roots { parts: Vec::new() }
142    }
143
144    /// Add `value` under `name`, or replace the value already under it.
145    #[must_use = "`root` returns the extended `Roots`"]
146    pub fn root(mut self, name: &'r str, value: impl Into<RootValue<'r>>) -> Self {
147        self.insert(name, value);
148        self
149    }
150
151    /// [`Self::root`] in place.
152    pub fn insert(&mut self, name: &'r str, value: impl Into<RootValue<'r>>) {
153        let value = value.into();
154        match self.parts.iter_mut().find(|(n, _)| *n == name) {
155            Some((_, slot)) => *slot = value,
156            None => self.parts.push((name, value)),
157        }
158    }
159
160    /// The names, in order.
161    pub fn names(&self) -> impl Iterator<Item = &'r str> + '_ {
162        self.parts.iter().map(|(name, _)| *name)
163    }
164
165    /// Number of roots.
166    pub fn len(&self) -> usize {
167        self.parts.len()
168    }
169
170    /// Whether there are no roots.
171    pub fn is_empty(&self) -> bool {
172        self.parts.is_empty()
173    }
174
175    /// The combined object, built in `arena`. One object node plus each
176    /// part's own view.
177    fn view_in<'a>(&self, arena: &'a Bump) -> &'a DataValue<'a>
178    where
179        'r: 'a,
180    {
181        let fields = arena.alloc_slice_fill_iter(
182            self.parts
183                .iter()
184                .map(|(name, value)| (*name, value.view_in(arena))),
185        );
186        arena.alloc(DataValue::Object(fields))
187    }
188
189    /// The view a rule compiled as `logic` evaluates on `engine`:
190    /// projected when the rule's reads allow it, whole otherwise.
191    #[inline]
192    fn arena_for<'a>(
193        &self,
194        logic: &crate::Logic,
195        engine: &crate::Engine,
196        arena: &'a Bump,
197    ) -> &'a DataValue<'a>
198    where
199        'r: 'a,
200    {
201        match logic.projection_for(engine) {
202            Some(projection) => self.projected_in(projection, arena),
203            None => self.view_in(arena),
204        }
205    }
206
207    /// [`Self::view_in`] for a rule with read projection `projection`:
208    /// only the roots it reads, each projected.
209    fn projected_in<'a>(
210        &self,
211        projection: &crate::projection::Projection,
212        arena: &'a Bump,
213    ) -> &'a DataValue<'a>
214    where
215        'r: 'a,
216    {
217        let mut kept = bumpalo::collections::Vec::with_capacity_in(self.parts.len(), arena);
218        for (name, value) in &self.parts {
219            if let Some(under) = projection.under(name) {
220                kept.push((*name, value.project_in(under, arena)));
221            }
222        }
223        arena.alloc(DataValue::Object(kept.into_bump_slice()))
224    }
225
226    fn to_owned_value(&self) -> OwnedDataValue {
227        OwnedDataValue::Object(
228            self.parts
229                .iter()
230                .map(|(name, value)| (name.to_string(), value.to_owned_value()))
231                .collect(),
232        )
233    }
234}
235
236impl<'r, V: Into<RootValue<'r>>, const N: usize> From<[(&'r str, V); N]> for Roots<'r> {
237    fn from(parts: [(&'r str, V); N]) -> Self {
238        parts.into_iter().collect()
239    }
240}
241
242impl<'r, V: Into<RootValue<'r>>> FromIterator<(&'r str, V)> for Roots<'r> {
243    fn from_iter<I: IntoIterator<Item = (&'r str, V)>>(iter: I) -> Self {
244        let mut roots = Roots::new();
245        for (name, value) in iter {
246            roots.insert(name, value);
247        }
248        roots
249    }
250}
251
252impl<'r, V: Into<RootValue<'r>>> Extend<(&'r str, V)> for Roots<'r> {
253    fn extend<I: IntoIterator<Item = (&'r str, V)>>(&mut self, iter: I) {
254        for (name, value) in iter {
255            self.insert(name, value);
256        }
257    }
258}
259
260// ── input impls ─────────────────────────────────────────────────────────
261
262impl sealed::Sealed for &Roots<'_> {}
263impl<'a, 'r: 'a> EvalInput<'a> for &'a Roots<'r> {
264    #[inline]
265    fn into_arena_value(self, arena: &'a Bump) -> Result<&'a DataValue<'a>> {
266        Ok(self.view_in(arena))
267    }
268
269    #[inline]
270    fn into_arena_for(
271        self,
272        logic: &crate::Logic,
273        engine: &crate::Engine,
274        arena: &'a Bump,
275    ) -> Result<&'a DataValue<'a>> {
276        Ok(self.arena_for(logic, engine, arena))
277    }
278}
279
280impl sealed::Sealed for Roots<'_> {}
281impl<'a, 'r: 'a> EvalInput<'a> for Roots<'r> {
282    #[inline]
283    fn into_arena_value(self, arena: &'a Bump) -> Result<&'a DataValue<'a>> {
284        Ok(self.view_in(arena))
285    }
286
287    #[inline]
288    fn into_arena_for(
289        self,
290        logic: &crate::Logic,
291        engine: &crate::Engine,
292        arena: &'a Bump,
293    ) -> Result<&'a DataValue<'a>> {
294        Ok(self.arena_for(logic, engine, arena))
295    }
296}
297
298impl sealed::LendArena for &Roots<'_> {
299    #[inline]
300    fn lend_arena<R>(
301        self,
302        f: impl for<'a> FnOnce(&'a DataValue<'a>, &'a Bump) -> Result<R>,
303    ) -> Result<R> {
304        let arena = sealed::one_shot_arena();
305        let data = self.view_in(&arena);
306        f(data, &arena)
307    }
308
309    #[inline]
310    fn lend_arena_for<R>(
311        self,
312        logic: &crate::Logic,
313        engine: &crate::Engine,
314        f: impl for<'a> FnOnce(&'a DataValue<'a>, &'a Bump) -> Result<R>,
315    ) -> Result<R> {
316        let arena = sealed::one_shot_arena();
317        let data = self.arena_for(logic, engine, &arena);
318        f(data, &arena)
319    }
320}
321impl OwnedInput for &Roots<'_> {
322    fn into_owned_input(self) -> Result<OwnedDataValue> {
323        Ok(self.to_owned_value())
324    }
325}
326
327impl sealed::LendArena for Roots<'_> {
328    #[inline]
329    fn lend_arena<R>(
330        self,
331        f: impl for<'a> FnOnce(&'a DataValue<'a>, &'a Bump) -> Result<R>,
332    ) -> Result<R> {
333        (&self).lend_arena(f)
334    }
335
336    #[inline]
337    fn lend_arena_for<R>(
338        self,
339        logic: &crate::Logic,
340        engine: &crate::Engine,
341        f: impl for<'a> FnOnce(&'a DataValue<'a>, &'a Bump) -> Result<R>,
342    ) -> Result<R> {
343        (&self).lend_arena_for(logic, engine, f)
344    }
345}
346impl OwnedInput for Roots<'_> {
347    fn into_owned_input(self) -> Result<OwnedDataValue> {
348        Ok(self.to_owned_value())
349    }
350}