use super::iterators::{ChunkByIterator, UnfoldBoundedIter, UnfoldIter};
use super::{QueryBuilder, QueryData};
use crate::core::state::{Filtered, Initial};
use std::marker::PhantomData;
struct ScanIter<T, B, F> {
inner: Box<dyn Iterator<Item = T>>,
state: Option<B>,
f: F,
}
impl<T, B: Clone, F: FnMut(B, T) -> B> Iterator for ScanIter<T, B, F> {
type Item = B;
fn next(&mut self) -> Option<B> {
let x = self.inner.next()?;
let acc = self.state.take()?;
let next_acc = (self.f)(acc, x);
self.state = Some(next_acc.clone());
Some(next_acc)
}
}
impl<T: 'static, State> QueryBuilder<T, State> {
pub fn scan<B, F>(self, seed: B, f: F) -> QueryBuilder<B, Filtered>
where
B: Clone + 'static,
F: FnMut(B, T) -> B + 'static,
{
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(it) => it,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
QueryBuilder {
data: QueryData::Iterator(Box::new(ScanIter {
inner: iter,
state: Some(seed),
f,
})),
_state: PhantomData,
}
}
pub fn chunk_by<K, F>(self, key_fn: F) -> QueryBuilder<Vec<T>, Filtered>
where
K: PartialEq + 'static,
F: FnMut(&T) -> K + 'static,
{
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(it) => it,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
QueryBuilder {
data: QueryData::Iterator(Box::new(ChunkByIterator {
inner: iter,
key_fn,
buffered: None,
done: false,
})),
_state: PhantomData,
}
}
pub fn dedup(self) -> QueryBuilder<T, Filtered>
where
T: PartialEq + Clone,
{
self.dedup_by(|x| x.clone())
}
pub fn dedup_by<K, F>(self, mut key_fn: F) -> QueryBuilder<T, Filtered>
where
K: PartialEq + 'static,
F: FnMut(&T) -> K + 'static,
T: 'static,
{
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(it) => it,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
let mut last_key: Option<K> = None;
let filtered = iter.filter(move |item| {
let key = key_fn(item);
if last_key.as_ref() == Some(&key) {
false
} else {
last_key = Some(key);
true
}
});
QueryBuilder {
data: QueryData::Iterator(Box::new(filtered)),
_state: PhantomData,
}
}
pub fn zip_with<U, R, I, F>(self, other: I, f: F) -> QueryBuilder<R, Filtered>
where
U: 'static,
R: 'static,
I: IntoIterator<Item = U> + 'static,
I::IntoIter: 'static,
F: Fn(T, U) -> R + 'static,
{
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(it) => it,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
let zipped = iter.zip(other).map(move |(a, b)| f(a, b));
QueryBuilder {
data: QueryData::Iterator(Box::new(zipped)),
_state: PhantomData,
}
}
pub fn pairwise(self) -> QueryBuilder<(T, T), Filtered>
where
T: Clone,
{
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(it) => it,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
QueryBuilder {
data: QueryData::Iterator(Box::new(PairwiseIter {
inner: iter,
prev: None,
})),
_state: PhantomData,
}
}
pub fn intersperse(self, separator: T) -> QueryBuilder<T, Filtered>
where
T: Clone,
{
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(it) => it,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
QueryBuilder {
data: QueryData::Iterator(Box::new(IntersperseIter {
inner: iter,
separator,
pending: None,
first: true,
})),
_state: PhantomData,
}
}
pub fn min_max(self) -> Option<(T, T)>
where
T: Ord + Clone,
{
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(it) => it,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
let mut iter = iter;
let first = iter.next()?;
let mut min = first.clone();
let mut max = first;
for item in iter {
if item < min {
min = item.clone();
}
if item > max {
max = item;
}
}
Some((min, max))
}
}
impl<T: 'static> QueryBuilder<T, Initial> {
pub fn unfold<S, F>(seed: S, f: F) -> QueryBuilder<T, Initial>
where
S: 'static,
F: FnMut(S) -> Option<(T, S)> + 'static,
{
QueryBuilder {
data: QueryData::Iterator(Box::new(UnfoldIter {
state: Some(seed),
f,
})),
_state: PhantomData,
}
}
pub fn unfold_bounded<S, F>(seed: S, f: F, max: usize) -> QueryBuilder<T, Initial>
where
S: 'static,
F: FnMut(S) -> Option<(T, S)> + 'static,
{
QueryBuilder {
data: QueryData::Iterator(Box::new(UnfoldBoundedIter {
inner: UnfoldIter {
state: Some(seed),
f,
},
remaining: max,
})),
_state: PhantomData,
}
}
}
struct PairwiseIter<T> {
inner: Box<dyn Iterator<Item = T>>,
prev: Option<T>,
}
impl<T: Clone> Iterator for PairwiseIter<T> {
type Item = (T, T);
fn next(&mut self) -> Option<(T, T)> {
if self.prev.is_none() {
self.prev = Some(self.inner.next()?);
}
let next = self.inner.next()?;
let pair = (self.prev.as_ref().unwrap().clone(), next.clone());
self.prev = Some(next);
Some(pair)
}
}
struct IntersperseIter<T> {
inner: Box<dyn Iterator<Item = T>>,
separator: T,
pending: Option<T>,
first: bool,
}
impl<T: Clone> Iterator for IntersperseIter<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if let Some(sep) = self.pending.take() {
return Some(sep);
}
let item = self.inner.next()?;
if self.first {
self.first = false;
Some(item)
} else {
self.pending = Some(item);
Some(self.separator.clone())
}
}
}