jaq_interpret/
path.rs

1use crate::box_iter::{box_once, flat_map_with, map_with, BoxIter};
2use crate::results::then;
3use crate::val::{ValR2, ValT};
4use alloc::{boxed::Box, vec::Vec};
5pub use jaq_syn::path::Opt;
6
7#[derive(Clone, Debug)]
8pub struct Path<F>(pub Vec<(Part<F>, Opt)>);
9
10#[derive(Clone, Debug)]
11pub enum Part<I> {
12    Index(I),
13    /// if both are `None`, return iterator over whole array/object
14    Range(Option<I>, Option<I>),
15}
16
17impl<'a, U: Clone + 'a, E: Clone + 'a, T: Clone + IntoIterator<Item = Result<U, E>> + 'a> Path<T> {
18    pub fn explode(self) -> impl Iterator<Item = Result<Path<U>, E>> + 'a {
19        Path(Vec::new())
20            .combinations(self.0.into_iter())
21            .map(|path| path.transpose())
22    }
23}
24
25impl<'a, U: Clone + 'a> Path<U> {
26    fn combinations<I, F>(self, mut iter: I) -> BoxIter<'a, Self>
27    where
28        I: Iterator<Item = (Part<F>, Opt)> + Clone + 'a,
29        F: IntoIterator<Item = U> + Clone + 'a,
30    {
31        if let Some((part, opt)) = iter.next() {
32            let parts = part.into_iter();
33            flat_map_with(parts, (self, iter), move |part, (mut prev, iter)| {
34                prev.0.push((part, opt));
35                prev.combinations(iter)
36            })
37        } else {
38            box_once(self)
39        }
40    }
41}
42
43impl<'a, V: ValT + 'a> Path<V> {
44    pub fn run(self, v: V) -> Box<dyn Iterator<Item = ValR2<V>> + 'a> {
45        run(self.0.into_iter(), v)
46    }
47
48    pub fn update<F>(mut self, v: V, f: F) -> ValR2<V>
49    where
50        F: Fn(V) -> Box<dyn Iterator<Item = ValR2<V>> + 'a>,
51    {
52        if let Some(last) = self.0.pop() {
53            update(self.0.into_iter(), last, v, &f)
54        } else {
55            // should be unreachable
56            Ok(v)
57        }
58    }
59}
60
61fn run<'a, V: ValT + 'a, I>(mut iter: I, val: V) -> Box<dyn Iterator<Item = ValR2<V>> + 'a>
62where
63    I: Iterator<Item = (Part<V>, Opt)> + Clone + 'a,
64{
65    if let Some((part, opt)) = iter.next() {
66        let essential = matches!(opt, Opt::Essential);
67        let ys = part.run(val).filter(move |v| essential || v.is_ok());
68        flat_map_with(ys, iter, move |v, iter| then(v, |v| run(iter, v)))
69    } else {
70        box_once(Ok(val))
71    }
72}
73
74fn update<'a, V: ValT, P, F>(mut iter: P, last: (Part<V>, Opt), v: V, f: &F) -> ValR2<V>
75where
76    P: Iterator<Item = (Part<V>, Opt)> + Clone,
77    F: Fn(V) -> Box<dyn Iterator<Item = ValR2<V>> + 'a>,
78{
79    if let Some((part, opt)) = iter.next() {
80        use core::iter::once;
81        part.update(v, opt, |v| once(update(iter.clone(), last.clone(), v, f)))
82    } else {
83        last.0.update(v, last.1, f)
84    }
85}
86
87impl<'a, V: ValT + 'a> Part<V> {
88    fn run(&self, v: V) -> impl Iterator<Item = ValR2<V>> + 'a {
89        match self {
90            Self::Index(idx) => box_once(v.index(idx)),
91            Self::Range(None, None) => Box::new(v.values()),
92            Self::Range(from, upto) => box_once(v.range(from.as_ref()..upto.as_ref())),
93        }
94    }
95
96    fn update<F, I>(&self, v: V, opt: Opt, f: F) -> ValR2<V>
97    where
98        F: Fn(V) -> I,
99        I: Iterator<Item = ValR2<V>>,
100    {
101        match self {
102            Self::Index(idx) => v.map_index(idx, opt, f),
103            Self::Range(None, None) => v.map_values(opt, f),
104            Self::Range(from, upto) => v.map_range(from.as_ref()..upto.as_ref(), opt, f),
105        }
106    }
107}
108
109impl<'a, U: Clone + 'a, F: IntoIterator<Item = U> + Clone + 'a> Part<F> {
110    fn into_iter(self) -> BoxIter<'a, Part<U>> {
111        use Part::{Index, Range};
112        match self {
113            Index(i) => Box::new(i.into_iter().map(Index)),
114            Range(None, None) => box_once(Range(None, None)),
115            Range(Some(from), None) => {
116                Box::new(from.into_iter().map(|from| Range(Some(from), None)))
117            }
118            Range(None, Some(upto)) => {
119                Box::new(upto.into_iter().map(|upto| Range(None, Some(upto))))
120            }
121            Range(Some(from), Some(upto)) => {
122                Box::new(flat_map_with(from.into_iter(), upto, move |from, upto| {
123                    map_with(upto.into_iter(), from, move |upto, from| {
124                        Range(Some(from), Some(upto))
125                    })
126                }))
127            }
128        }
129    }
130}
131
132impl<T> Path<T> {
133    pub fn map_ref<'a, U>(&'a self, mut f: impl FnMut(&'a T) -> U) -> Path<U> {
134        let path = self.0.iter();
135        let path = path.map(move |(part, opt)| (part.as_ref().map(&mut f), *opt));
136        Path(path.collect())
137    }
138}
139
140impl<T> Part<T> {
141    fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Part<U> {
142        use Part::{Index, Range};
143        match self {
144            Index(i) => Index(f(i)),
145            Range(from, upto) => Range(from.map(&mut f), upto.map(&mut f)),
146        }
147    }
148}
149
150impl<T, E> Path<Result<T, E>> {
151    fn transpose(self) -> Result<Path<T>, E> {
152        self.0
153            .into_iter()
154            .map(|(part, opt)| Ok((part.transpose()?, opt)))
155            .collect::<Result<_, _>>()
156            .map(Path)
157    }
158}
159
160impl<T, E> Part<Result<T, E>> {
161    fn transpose(self) -> Result<Part<T>, E> {
162        match self {
163            Self::Index(i) => Ok(Part::Index(i?)),
164            Self::Range(from, upto) => Ok(Part::Range(from.transpose()?, upto.transpose()?)),
165        }
166    }
167}
168
169impl<F> Part<F> {
170    fn as_ref(&self) -> Part<&F> {
171        match self {
172            Self::Index(i) => Part::Index(i),
173            Self::Range(from, upto) => Part::Range(from.as_ref(), upto.as_ref()),
174        }
175    }
176}
177
178impl<F> From<Part<F>> for Path<F> {
179    fn from(p: Part<F>) -> Self {
180        Self(Vec::from([(p, Opt::Essential)]))
181    }
182}