Skip to content

Commit

Permalink
Use IntoIterator to signal delayed iteration.
Browse files Browse the repository at this point in the history
  • Loading branch information
01mf02 committed Jan 16, 2024
1 parent 28af565 commit d028aee
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 49 deletions.
124 changes: 85 additions & 39 deletions jaq-interpret/src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,60 @@ impl<'a> FilterT<'a> for &'a Owned {
}
}

#[derive(Clone)]
struct Delay<F>(F);

impl<I: Iterator, F: FnOnce() -> I> IntoIterator for Delay<F> {
type Item = I::Item;
type IntoIter = I;
fn into_iter(self) -> Self::IntoIter {
self.0()
}
}

#[derive(Clone)]
enum Either<L, R> {
L(L),
R(R),
}

struct EitherIter<L, R>(Either<L, R>);

impl<L: Iterator, R: Iterator<Item = L::Item>> Iterator for EitherIter<L, R> {
type Item = L::Item;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
Either::L(l) => l.next(),
Either::R(r) => r.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.0 {
Either::L(l) => l.size_hint(),
Either::R(r) => r.size_hint(),
}
}
}

impl<L: IntoIterator, R: IntoIterator<Item = L::Item>> IntoIterator for Either<L, R> {
type Item = L::Item;
type IntoIter = EitherIter<L::IntoIter, R::IntoIter>;
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: Iterator, F: FnOnce() -> I + Clone>(f: F) -> Either<Vec<I::Item>, Delay<F>> {
let iter = f.clone()();
match iter.size_hint().1 {
Some(_) => Either::L(iter.collect::<Vec<_>>()),
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};
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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),
Expand Down
26 changes: 16 additions & 10 deletions jaq-interpret/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl<'a, U: Clone + 'a> Path<U> {
pub fn combinations<I, F>(self, mut iter: I) -> BoxIter<'a, Self>
where
I: Iterator<Item = (Part<F>, Opt)> + Clone + 'a,
F: Fn() -> BoxIter<'a, U> + 'a,
F: IntoIterator<Item = U> + Clone + 'a,
{
if let Some((part, opt)) = iter.next() {
let parts = part.into_iter();
Expand Down Expand Up @@ -179,19 +179,25 @@ impl Part<Val> {
}
}

impl<'a, U: Clone + 'a, F: Fn() -> BoxIter<'a, U> + 'a> Part<F> {
impl<'a, U: Clone + 'a, F: IntoIterator<Item = U> + Clone + 'a> Part<F> {
fn into_iter(self) -> BoxIter<'a, Part<U>> {
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))
})
}))
}
}
}
}
Expand Down

0 comments on commit d028aee

Please sign in to comment.