jaq_core/
path.rs

1//! Paths and their parts.
2
3use crate::box_iter::{box_once, flat_map_with, map_with, then, BoxIter};
4use crate::val::{ValRs, ValT, ValX, ValXs};
5use crate::RcList;
6use alloc::{boxed::Box, vec::Vec};
7
8/// Path such as `.[].a?[1:]`.
9#[derive(Clone, Debug)]
10pub struct Path<F>(pub Vec<(Part<F>, Opt)>);
11
12/// Part of a path, such as `[]`, `a`, and `[1:]` in `.[].a?[1:]`.
13#[derive(Clone, Debug)]
14pub enum Part<I> {
15    /// Access arrays with integer and objects with string indices
16    Index(I),
17    /// Iterate over arrays with optional range bounds and over objects without bounds
18    /// If both are `None`, return iterator over whole array/object
19    Range(Option<I>, Option<I>),
20}
21
22/// Optionality of a path part, i.e. whether `?` is present.
23///
24/// For example, `[] | .a` fails with an error, while `[] | .a?` returns nothing.
25/// By default, path parts are *essential*, meaning that they fail.
26/// Annotating them with `?` makes them *optional*.
27#[derive(Copy, Clone, Debug)]
28pub enum Opt {
29    /// Return nothing if the input cannot be accessed with the path
30    Optional,
31    /// Fail if the input cannot be accessed with the path
32    Essential,
33}
34
35impl<I> Default for Part<I> {
36    fn default() -> Self {
37        Self::Range(None, None)
38    }
39}
40
41impl Opt {
42    /// If `self` is optional, return `x`, else fail with `f(x)`.
43    pub fn fail<T, E>(self, x: T, f: impl FnOnce(T) -> E) -> Result<T, E> {
44        match self {
45            Self::Optional => Ok(x),
46            Self::Essential => Err(f(x)),
47        }
48    }
49}
50
51impl<'a, U: Clone + 'a, E: Clone + 'a, T: Clone + IntoIterator<Item = Result<U, E>> + 'a> Path<T> {
52    pub(crate) fn explode(self) -> impl Iterator<Item = Result<Path<U>, E>> + 'a {
53        Path(Vec::new())
54            .combinations(self.0.into_iter())
55            .map(Path::transpose)
56    }
57}
58
59impl<'a, U: Clone + 'a> Path<U> {
60    fn combinations<I, F>(self, mut iter: I) -> BoxIter<'a, Self>
61    where
62        I: Iterator<Item = (Part<F>, Opt)> + Clone + 'a,
63        F: IntoIterator<Item = U> + Clone + 'a,
64    {
65        if let Some((part, opt)) = iter.next() {
66            let parts = part.into_iter();
67            flat_map_with(parts, (self, iter), move |part, (mut prev, iter)| {
68                prev.0.push((part, opt));
69                prev.combinations(iter)
70            })
71        } else {
72            box_once(self)
73        }
74    }
75}
76
77impl<'a, V: ValT + 'a> Path<V> {
78    pub(crate) fn run(self, v: V) -> ValRs<'a, V> {
79        run(self.0.into_iter(), v, |part, v| part.run(v))
80    }
81
82    pub(crate) fn paths(self, vp: (V, RcList<V>)) -> ValRs<'a, (V, RcList<V>), V> {
83        run(self.0.into_iter(), vp, |part, vp| part.paths(vp))
84    }
85
86    pub(crate) fn update<F>(mut self, v: V, f: F) -> ValX<V>
87    where
88        F: Fn(V) -> ValXs<'a, V>,
89    {
90        if let Some(last) = self.0.pop() {
91            update(self.0.into_iter(), last, v, &f)
92        } else {
93            // should be unreachable
94            Ok(v)
95        }
96    }
97}
98
99fn run<'a, V: 'a, T: 'a>(
100    mut iter: impl Iterator<Item = (Part<V>, Opt)> + Clone + 'a,
101    val: T,
102    f: fn(Part<V>, T) -> ValRs<'a, T, V>,
103) -> ValRs<'a, T, V> {
104    if let Some((part, opt)) = iter.next() {
105        let essential = matches!(opt, Opt::Essential);
106        let ys = f(part, val).filter(move |v| essential || v.is_ok());
107        flat_map_with(ys, iter, move |v, iter| then(v, |v| run(iter, v, f)))
108    } else {
109        box_once(Ok(val))
110    }
111}
112
113fn update<'a, V: ValT, P, F>(mut iter: P, last: (Part<V>, Opt), v: V, f: &F) -> ValX<V>
114where
115    P: Iterator<Item = (Part<V>, Opt)> + Clone,
116    F: Fn(V) -> ValXs<'a, V>,
117{
118    if let Some((part, opt)) = iter.next() {
119        use core::iter::once;
120        part.update(v, opt, |v| once(update(iter.clone(), last.clone(), v, f)))
121    } else {
122        last.0.update(v, last.1, f)
123    }
124}
125
126impl<'a, V: ValT + 'a> Part<V> {
127    fn run(&self, v: V) -> ValRs<'a, V> {
128        match self {
129            Self::Index(idx) => box_once(v.index(idx)),
130            Self::Range(None, None) => Box::new(v.values()),
131            Self::Range(from, upto) => box_once(v.range(from.as_ref()..upto.as_ref())),
132        }
133    }
134
135    fn paths(&self, (v, p): (V, RcList<V>)) -> ValRs<'a, (V, RcList<V>), V> {
136        match self {
137            Self::Index(idx) => box_once(v.index(idx).map(|v| (v, p.cons(idx.clone())))),
138            Self::Range(None, None) => Box::new(
139                v.key_values()
140                    .map(move |kv| kv.map(|(k, v)| (v, p.clone().cons(k)))),
141            ),
142            Self::Range(from, upto) => box_once(
143                v.range(from.as_ref()..upto.as_ref())
144                    .map(|v| (v, p.cons(V::from(from.clone()..upto.clone())))),
145            ),
146        }
147    }
148
149    fn update<F, I>(&self, v: V, opt: Opt, f: F) -> ValX<V>
150    where
151        F: Fn(V) -> I,
152        I: Iterator<Item = ValX<V>>,
153    {
154        match self {
155            Self::Index(idx) => v.map_index(idx, opt, f),
156            Self::Range(None, None) => v.map_values(opt, f),
157            Self::Range(from, upto) => v.map_range(from.as_ref()..upto.as_ref(), opt, f),
158        }
159    }
160}
161
162impl<'a, U: Clone + 'a, F: IntoIterator<Item = U> + Clone + 'a> Part<F> {
163    fn into_iter(self) -> BoxIter<'a, Part<U>> {
164        use Part::{Index, Range};
165        match self {
166            Index(i) => Box::new(i.into_iter().map(Index)),
167            Range(None, None) => box_once(Range(None, None)),
168            Range(Some(from), None) => {
169                Box::new(from.into_iter().map(|from| Range(Some(from), None)))
170            }
171            Range(None, Some(upto)) => {
172                Box::new(upto.into_iter().map(|upto| Range(None, Some(upto))))
173            }
174            Range(Some(from), Some(upto)) => {
175                Box::new(flat_map_with(from.into_iter(), upto, move |from, upto| {
176                    map_with(upto.into_iter(), from, move |upto, from| {
177                        Range(Some(from), Some(upto))
178                    })
179                }))
180            }
181        }
182    }
183}
184
185impl<T> Path<T> {
186    pub(crate) fn map_ref<'a, U>(&'a self, mut f: impl FnMut(&'a T) -> U) -> Path<U> {
187        let path = self.0.iter();
188        let path = path.map(move |(part, opt)| (part.as_ref().map(&mut f), *opt));
189        Path(path.collect())
190    }
191}
192
193impl<T> Part<T> {
194    /// Apply a function to the contained indices.
195    pub(crate) fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Part<U> {
196        use Part::{Index, Range};
197        match self {
198            Index(i) => Index(f(i)),
199            Range(from, upto) => Range(from.map(&mut f), upto.map(&mut f)),
200        }
201    }
202}
203
204impl<T, E> Path<Result<T, E>> {
205    fn transpose(self) -> Result<Path<T>, E> {
206        self.0
207            .into_iter()
208            .map(|(part, opt)| Ok((part.transpose()?, opt)))
209            .collect::<Result<_, _>>()
210            .map(Path)
211    }
212}
213
214impl<T, E> Part<Result<T, E>> {
215    fn transpose(self) -> Result<Part<T>, E> {
216        match self {
217            Self::Index(i) => Ok(Part::Index(i?)),
218            Self::Range(from, upto) => Ok(Part::Range(from.transpose()?, upto.transpose()?)),
219        }
220    }
221}
222
223impl<F> Part<F> {
224    fn as_ref(&self) -> Part<&F> {
225        match self {
226            Self::Index(i) => Part::Index(i),
227            Self::Range(from, upto) => Part::Range(from.as_ref(), upto.as_ref()),
228        }
229    }
230}
231
232impl<F> From<Part<F>> for Path<F> {
233    fn from(p: Part<F>) -> Self {
234        Self(Vec::from([(p, Opt::Essential)]))
235    }
236}