diff --git a/jaq-interpret/src/filter.rs b/jaq-interpret/src/filter.rs index 69c56664b..394d5d279 100644 --- a/jaq-interpret/src/filter.rs +++ b/jaq-interpret/src/filter.rs @@ -225,6 +225,60 @@ impl<'a> FilterT<'a> for &'a Owned { } } +#[derive(Clone)] +struct Delay(F); + +impl I> IntoIterator for Delay { + type Item = I::Item; + type IntoIter = I; + fn into_iter(self) -> Self::IntoIter { + self.0() + } +} + +#[derive(Clone)] +enum Either { + L(L), + R(R), +} + +struct EitherIter(Either); + +impl> Iterator for EitherIter { + type Item = L::Item; + fn next(&mut self) -> Option { + match &mut self.0 { + Either::L(l) => l.next(), + Either::R(r) => r.next(), + } + } + fn size_hint(&self) -> (usize, Option) { + match &self.0 { + Either::L(l) => l.size_hint(), + Either::R(r) => r.size_hint(), + } + } +} + +impl> IntoIterator for Either { + type Item = L::Item; + type IntoIter = EitherIter; + fn into_iter(self) -> Self::IntoIter { + EitherIter(match self { + Self::L(l) => Either::L(l.into_iter()), + Self::R(r) => Either::R(r.into_iter()), + }) + } +} + +fn bla I + Clone>(f: F) -> Either, Delay> { + let iter = f.clone()(); + match iter.size_hint().1 { + Some(_) => Either::L(iter.collect::>()), + None => Either::R(Delay(f)), + } +} + impl<'a> FilterT<'a> for Ref<'a> { fn run(self, cv: Cv<'a>) -> ValRs<'a> { use core::iter::{once, once_with}; @@ -279,18 +333,15 @@ impl<'a> FilterT<'a> for Ref<'a> { }), Ast::Path(f, path) => { use crate::path::{self, Path}; - let cvc = cv.clone(); - let path = path.0.iter().map(move |(part, opt)| { - ( - part.as_ref().map(|i| { - let cvc = cvc.clone(); - move || w(i).run(cvc.clone()) - }), - *opt, - ) - }); + let run = |i| { + let cv = cv.clone(); + bla(move || w(i).run(cv)) + }; + let path = path.0.iter(); + let path = path.map(move |(part, opt)| (part.as_ref().map(run), *opt)); + let path: Vec<_> = path.collect(); flat_map_with(w(f).run(cv), path, |y, path| { - let paths = Path(Vec::new()).combinations(path); + let paths = Path(Vec::new()).combinations(path.into_iter()); let paths = paths.map(|path| path.transpose()); then(y, |y| { @@ -387,36 +438,31 @@ impl<'a> FilterT<'a> for Ref<'a> { Ast::Path(l, path) => { use crate::path::{self, Path}; - let cvc = cv.clone(); - - let path = path.0.iter().map(move |(part, opt)| { - ( - part.as_ref().map(|i| { - let cvc = cvc.clone(); - move || w(i).run(cvc.clone()) - }), - *opt, - ) - }); + let run = |i| { + let cv = cv.clone(); + bla(move || w(i).run(cv)) + }; + let path = path.0.iter(); + let path = path.map(move |(part, opt)| (part.as_ref().map(run), *opt)); let path: Vec<_> = path.collect(); - w(l).update( - cv, - Box::new(move |v| { - let paths = Path(Vec::new()).combinations(path.clone().into_iter()); - let mut paths = paths.map(|path| path.transpose()); - - box_once(paths.try_fold(v, |acc, path| { - let mut path = path?; - if let Some(last) = path.0.pop() { - path::update(path.0.into_iter(), last, acc, &f) - } else { - // should be unreachable - Ok(acc) - } - })) - }), - ) + let f = move |v| { + let path = path.clone(); + let paths = Path(Vec::new()).combinations(path.into_iter()); + let mut paths = paths.map(|path| path.transpose()); + + box_once(paths.try_fold(v, |acc, path| { + let mut path = path?; + if let Some(last) = path.0.pop() { + path::update(path.0.into_iter(), last, acc, &f) + } else { + // should be unreachable + Ok(acc) + } + })) + }; + + w(l).update(cv, Box::new(f)) } Ast::Pipe(l, false, r) => w(l).update( (cv.0.clone(), cv.1), diff --git a/jaq-interpret/src/path.rs b/jaq-interpret/src/path.rs index 9b4bab215..d04304ba0 100644 --- a/jaq-interpret/src/path.rs +++ b/jaq-interpret/src/path.rs @@ -19,7 +19,7 @@ impl<'a, U: Clone + 'a> Path { pub fn combinations(self, mut iter: I) -> BoxIter<'a, Self> where I: Iterator, Opt)> + Clone + 'a, - F: Fn() -> BoxIter<'a, U> + 'a, + F: IntoIterator + Clone + 'a, { if let Some((part, opt)) = iter.next() { let parts = part.into_iter(); @@ -179,19 +179,25 @@ impl Part { } } -impl<'a, U: Clone + 'a, F: Fn() -> BoxIter<'a, U> + 'a> Part { +impl<'a, U: Clone + 'a, F: IntoIterator + Clone + 'a> Part { fn into_iter(self) -> BoxIter<'a, Part> { use Part::{Index, Range}; match self { - Index(i) => Box::new(i().map(Index)), + Index(i) => Box::new(i.into_iter().map(Index)), Range(None, None) => box_once(Range(None, None)), - Range(Some(from), None) => Box::new(from().map(|from| Range(Some(from), None))), - Range(None, Some(upto)) => Box::new(upto().map(|upto| Range(None, Some(upto)))), - Range(Some(from), Some(upto)) => Box::new(from().flat_map(move |from| { - map_with(upto(), from, move |upto, from| { - Range(Some(from), Some(upto)) - }) - })), + Range(Some(from), None) => { + Box::new(from.into_iter().map(|from| Range(Some(from), None))) + } + Range(None, Some(upto)) => { + Box::new(upto.into_iter().map(|upto| Range(None, Some(upto)))) + } + Range(Some(from), Some(upto)) => { + Box::new(flat_map_with(from.into_iter(), upto, move |from, upto| { + map_with(upto.into_iter(), from, move |upto, from| { + Range(Some(from), Some(upto)) + }) + })) + } } } }