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