use super::iterators::ChunkIterator;
use super::{QueryBuilder, QueryData};
use crate::core::error::{RinqError, RinqResult};
use crate::core::state::Filtered;
use crate::core::state_diagnostics::HashEqBound;
#[cfg(feature = "parallel")]
use crate::parallel::ParallelQueryBuilder;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::marker::PhantomData;
impl<T: 'static, State> QueryBuilder<T, State> {
#[inline]
pub fn collect<B>(self) -> B
where
B: FromIterator<T>,
{
match self.data {
QueryData::Iterator(iter) => iter.collect(),
QueryData::SortedVec { items, .. } => items.into_iter().collect(),
}
}
#[inline]
pub(crate) fn into_vec(self) -> Vec<T> {
match self.data {
QueryData::Iterator(iter) => iter.collect(),
QueryData::SortedVec { items, .. } => items,
}
}
#[inline]
pub fn count(self) -> usize {
match self.data {
QueryData::Iterator(iter) => iter.count(),
QueryData::SortedVec { items, .. } => items.len(),
}
}
#[inline]
pub fn first(self) -> Option<T> {
match self.data {
QueryData::Iterator(mut iter) => iter.next(),
QueryData::SortedVec { mut items, .. } => {
if items.is_empty() {
None
} else {
Some(items.remove(0))
}
}
}
}
#[inline]
pub fn last(self) -> Option<T> {
match self.data {
QueryData::Iterator(iter) => iter.last(),
QueryData::SortedVec { mut items, .. } => items.pop(),
}
}
#[inline]
pub fn any<F>(self, mut predicate: F) -> bool
where
F: FnMut(&T) -> bool,
{
match self.data {
QueryData::Iterator(mut iter) => iter.any(|item| predicate(&item)),
QueryData::SortedVec { items, .. } => items.iter().any(predicate),
}
}
#[inline]
pub fn all<F>(self, mut predicate: F) -> bool
where
F: FnMut(&T) -> bool,
{
match self.data {
QueryData::Iterator(mut iter) => iter.all(|item| predicate(&item)),
QueryData::SortedVec { items, .. } => items.iter().all(predicate),
}
}
#[inline]
pub fn contains(self, value: &T) -> bool
where
T: PartialEq,
{
match self.data {
QueryData::Iterator(mut iter) => iter.any(|item| item == *value),
QueryData::SortedVec { items, .. } => items.contains(value),
}
}
#[inline]
pub fn first_or_default(self) -> T
where
T: Default,
{
match self.data {
QueryData::Iterator(mut iter) => iter.next().unwrap_or_default(),
QueryData::SortedVec { mut items, .. } => {
if items.is_empty() {
T::default()
} else {
items.remove(0)
}
}
}
}
#[inline]
pub fn last_or_default(self) -> T
where
T: Default,
{
match self.data {
QueryData::Iterator(iter) => iter.last().unwrap_or_default(),
QueryData::SortedVec { mut items, .. } => items.pop().unwrap_or_default(),
}
}
#[inline]
pub fn single(self) -> RinqResult<T> {
match self.data {
QueryData::Iterator(mut iter) => match iter.next() {
None => Err(RinqError::IteratorExhausted),
Some(first) => {
if iter.next().is_some() {
Err(RinqError::ExecutionError {
message: "single() called on a collection with more than one element"
.to_string(),
})
} else {
Ok(first)
}
}
},
QueryData::SortedVec { items, .. } => match items.len() {
0 => Err(RinqError::IteratorExhausted),
1 => Ok(items.into_iter().next().unwrap()),
_ => Err(RinqError::ExecutionError {
message: "single() called on a collection with more than one element"
.to_string(),
}),
},
}
}
#[inline]
pub fn single_or_default(self) -> RinqResult<T>
where
T: Default,
{
match self.data {
QueryData::Iterator(mut iter) => match iter.next() {
None => Ok(T::default()),
Some(first) => {
if iter.next().is_some() {
Err(RinqError::ExecutionError {
message:
"single_or_default() called on a collection with more than one element"
.to_string(),
})
} else {
Ok(first)
}
}
},
QueryData::SortedVec { items, .. } => match items.len() {
0 => Ok(T::default()),
1 => Ok(items.into_iter().next().unwrap()),
_ => Err(RinqError::ExecutionError {
message:
"single_or_default() called on a collection with more than one element"
.to_string(),
}),
},
}
}
#[inline]
pub fn element_at(self, index: usize) -> Option<T> {
match self.data {
QueryData::Iterator(mut iter) => iter.nth(index),
QueryData::SortedVec { items, .. } => items.into_iter().nth(index),
}
}
#[inline]
pub fn aggregate<Acc, F>(self, seed: Acc, f: F) -> Acc
where
F: Fn(Acc, T) -> Acc,
{
match self.data {
QueryData::Iterator(iter) => iter.fold(seed, f),
QueryData::SortedVec { items, .. } => items.into_iter().fold(seed, f),
}
}
#[inline]
pub fn aggregate_no_seed<F>(self, f: F) -> Option<T>
where
F: Fn(T, T) -> T,
{
let mut iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(iter) => iter,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
let first = iter.next()?;
Some(iter.fold(first, f))
}
#[inline]
pub fn concat(self, other: impl IntoIterator<Item = T> + 'static) -> QueryBuilder<T, Filtered> {
let chained: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(iter) => Box::new(iter.chain(other)),
QueryData::SortedVec { items, .. } => Box::new(items.into_iter().chain(other)),
};
QueryBuilder {
data: QueryData::Iterator(chained),
_state: PhantomData,
}
}
#[inline]
pub fn union(self, other: impl IntoIterator<Item = T> + 'static) -> QueryBuilder<T, Filtered>
where
T: HashEqBound + Clone,
{
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(iter) => iter,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
let mut seen = HashSet::new();
let combined = iter.chain(other).filter(move |item| {
if seen.contains(item) {
false
} else {
seen.insert(item.clone());
true
}
});
QueryBuilder {
data: QueryData::Iterator(Box::new(combined)),
_state: PhantomData,
}
}
#[inline]
pub fn intersect(
self,
other: impl IntoIterator<Item = T> + 'static,
) -> QueryBuilder<T, Filtered>
where
T: HashEqBound + Clone,
{
let other_set: HashSet<T> = other.into_iter().collect();
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(iter) => iter,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
let mut seen = HashSet::new();
let filtered =
iter.filter(move |item| other_set.contains(item) && seen.insert(item.clone()));
QueryBuilder {
data: QueryData::Iterator(Box::new(filtered)),
_state: PhantomData,
}
}
#[inline]
pub fn except(self, other: impl IntoIterator<Item = T> + 'static) -> QueryBuilder<T, Filtered>
where
T: HashEqBound + Clone,
{
let other_set: HashSet<T> = other.into_iter().collect();
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(iter) => iter,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
let mut seen = HashSet::new();
let filtered =
iter.filter(move |item| !other_set.contains(item) && seen.insert(item.clone()));
QueryBuilder {
data: QueryData::Iterator(Box::new(filtered)),
_state: PhantomData,
}
}
#[inline]
pub fn to_hashmap<K, F>(self, key_selector: F) -> RinqResult<HashMap<K, T>>
where
K: Hash + Eq,
F: Fn(&T) -> K,
{
let mut map = HashMap::new();
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(iter) => iter,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
for item in iter {
let key = key_selector(&item);
if map.contains_key(&key) {
return Err(RinqError::ExecutionError {
message: "to_hashmap() found a duplicate key".to_string(),
});
}
map.insert(key, item);
}
Ok(map)
}
#[inline]
pub fn to_lookup<K, F>(self, key_selector: F) -> HashMap<K, Vec<T>>
where
K: Hash + Eq,
F: Fn(&T) -> K,
{
let mut map: HashMap<K, Vec<T>> = HashMap::new();
let iter: Box<dyn Iterator<Item = T>> = match self.data {
QueryData::Iterator(iter) => iter,
QueryData::SortedVec { items, .. } => Box::new(items.into_iter()),
};
for item in iter {
let key = key_selector(&item);
map.entry(key).or_default().push(item);
}
map
}
}
impl<T: 'static, State> QueryBuilder<T, State> {
pub fn filter_map<U, F>(self, f: F) -> QueryBuilder<U, Filtered>
where
F: Fn(T) -> Option<U> + 'static,
U: '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(iter.filter_map(f))),
_state: PhantomData,
}
}
pub fn collect_vec(self) -> Vec<T> {
self.collect::<Vec<T>>()
}
pub fn step_by(self, step: usize) -> QueryBuilder<T, Filtered> {
assert!(step > 0, "step_by: step must be greater than 0");
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(iter.step_by(step))),
_state: PhantomData,
}
}
pub fn cycle(self) -> QueryBuilder<T, Filtered>
where
T: Clone,
{
let items: Vec<T> = match self.data {
QueryData::Iterator(it) => it.collect(),
QueryData::SortedVec { items, .. } => items,
};
QueryBuilder {
data: QueryData::Iterator(Box::new(CycleIter::new(items))),
_state: PhantomData,
}
}
}
struct CycleIter<T> {
items: Vec<T>,
index: usize,
}
impl<T> CycleIter<T> {
fn new(items: Vec<T>) -> Self {
Self { items, index: 0 }
}
}
impl<T: Clone> Iterator for CycleIter<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.items.is_empty() {
return None;
}
let item = self.items[self.index].clone();
self.index = (self.index + 1) % self.items.len();
Some(item)
}
}
impl<T: 'static> QueryBuilder<T, crate::core::state::Filtered> {
#[inline]
pub fn map<U, F>(self, projection: F) -> QueryBuilder<U, crate::core::state::Projected<U>>
where
F: Fn(T) -> U + 'static,
U: 'static,
{
self.select(projection)
}
}
pub trait IntoQuery: Sized {
type Item: 'static;
fn into_query(self) -> QueryBuilder<Self::Item, crate::core::state::Initial>;
}
impl<T: 'static> IntoQuery for Vec<T> {
type Item = T;
fn into_query(self) -> QueryBuilder<T, crate::core::state::Initial> {
QueryBuilder::from(self)
}
}
impl<T: Clone + 'static> QueryBuilder<T, crate::core::state::Initial> {
pub fn from_arc_cloned(arc: &std::sync::Arc<Vec<T>>) -> Self {
let cloned: Vec<T> = arc.as_ref().clone();
Self {
data: QueryData::Iterator(Box::new(cloned.into_iter())),
_state: PhantomData,
}
}
pub fn from_arc_slice_cloned(arc: &std::sync::Arc<[T]>) -> Self {
let cloned: Vec<T> = arc.iter().cloned().collect();
Self {
data: QueryData::Iterator(Box::new(cloned.into_iter())),
_state: PhantomData,
}
}
}
impl<T: 'static, State> QueryBuilder<T, State> {
pub fn tap_each<F>(self, f: F) -> QueryBuilder<T, Filtered>
where
F: Fn(&T) + '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(iter.inspect(f))),
_state: PhantomData,
}
}
pub fn tap_collect<F>(self, f: F) -> QueryBuilder<T, Filtered>
where
F: FnOnce(&[T]),
{
let items: Vec<T> = match self.data {
QueryData::Iterator(it) => it.collect(),
QueryData::SortedVec { items, .. } => items,
};
f(&items);
QueryBuilder {
data: QueryData::Iterator(Box::new(items.into_iter())),
_state: PhantomData,
}
}
pub fn pipe<T2, S2, F>(self, f: F) -> QueryBuilder<T2, S2>
where
F: FnOnce(Self) -> QueryBuilder<T2, S2>,
T2: 'static,
{
f(self)
}
}
impl<T: 'static, State> QueryBuilder<T, State> {
pub fn for_each<F>(self, f: F)
where
F: FnMut(T),
{
match self.data {
QueryData::Iterator(iter) => iter.for_each(f),
QueryData::SortedVec { items, .. } => items.into_iter().for_each(f),
}
}
pub fn to_sorted_vec<K, F>(self, key_selector: F) -> Vec<T>
where
F: Fn(&T) -> K,
K: Ord,
{
let mut items = self.into_vec();
items.sort_by_key(key_selector);
items
}
pub fn to_sorted_vec_desc<K, F>(self, key_selector: F) -> Vec<T>
where
F: Fn(&T) -> K,
K: Ord,
{
let mut items = self.into_vec();
items.sort_by_key(|x| std::cmp::Reverse(key_selector(x)));
items
}
pub fn take_last(self, n: usize) -> Vec<T> {
let mut items = self.into_vec();
if n >= items.len() {
items
} else {
items.split_off(items.len() - n)
}
}
pub fn skip_last(self, n: usize) -> Vec<T> {
let mut items = self.into_vec();
if n >= items.len() {
items.clear();
} else {
items.truncate(items.len() - n);
}
items
}
pub fn count_by<F>(self, predicate: F) -> usize
where
F: Fn(&T) -> bool,
{
match self.data {
QueryData::Iterator(iter) => iter.filter(|x| predicate(x)).count(),
QueryData::SortedVec { items, .. } => items.iter().filter(|x| predicate(x)).count(),
}
}
pub fn sum_by<N, F>(self, key: F) -> N
where
F: Fn(T) -> N,
N: Default + std::ops::Add<Output = N>,
{
match self.data {
QueryData::Iterator(iter) => iter.map(key).fold(N::default(), |a, b| a + b),
QueryData::SortedVec { items, .. } => {
items.into_iter().map(key).fold(N::default(), |a, b| a + b)
}
}
}
pub fn average_by<F>(self, key: F) -> Option<f64>
where
F: Fn(&T) -> f64,
{
let mut sum = 0.0_f64;
let mut count = 0usize;
match self.data {
QueryData::Iterator(iter) => {
for item in iter {
sum += key(&item);
count += 1;
}
}
QueryData::SortedVec { items, .. } => {
for item in &items {
sum += key(item);
count += 1;
}
}
}
if count == 0 {
None
} else {
Some(sum / count as f64)
}
}
pub fn reduce<F>(self, f: F) -> Option<T>
where
F: Fn(T, T) -> T,
{
self.aggregate_no_seed(f)
}
pub fn all_unique(self) -> bool
where
T: Hash + Eq,
{
let mut seen = HashSet::new();
match self.data {
QueryData::Iterator(iter) => {
for item in iter {
if !seen.insert(item) {
return false;
}
}
}
QueryData::SortedVec { items, .. } => {
for item in items {
if !seen.insert(item) {
return false;
}
}
}
}
true
}
pub fn none<F>(self, predicate: F) -> bool
where
F: Fn(&T) -> bool,
{
!match self.data {
QueryData::Iterator(mut iter) => iter.any(|item| predicate(&item)),
QueryData::SortedVec { items, .. } => items.iter().any(|item| predicate(item as &T)),
}
}
}
impl<T: 'static, State> QueryBuilder<T, State> {
pub fn frequencies(self) -> HashMap<T, usize>
where
T: Hash + Eq,
{
let mut map: HashMap<T, usize> = HashMap::new();
match self.data {
QueryData::Iterator(iter) => {
for item in iter {
*map.entry(item).or_insert(0) += 1;
}
}
QueryData::SortedVec { items, .. } => {
for item in items {
*map.entry(item).or_insert(0) += 1;
}
}
}
map
}
pub fn flatten<U>(self) -> QueryBuilder<U, Filtered>
where
T: IntoIterator<Item = U>,
U: '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(iter.flatten())),
_state: PhantomData,
}
}
pub fn position<F>(self, mut predicate: F) -> Option<usize>
where
F: FnMut(&T) -> bool,
{
match self.data {
QueryData::Iterator(iter) => iter
.enumerate()
.find_map(|(i, item)| if predicate(&item) { Some(i) } else { None }),
QueryData::SortedVec { items, .. } => {
items.iter().position(|item| predicate(item as &T))
}
}
}
pub fn find<F>(self, mut predicate: F) -> Option<T>
where
F: FnMut(&T) -> bool,
{
match self.data {
QueryData::Iterator(mut iter) => iter.find(|item| predicate(item)),
QueryData::SortedVec { items, .. } => items.into_iter().find(|item| predicate(item)),
}
}
pub fn index_of(self, value: &T) -> Option<usize>
where
T: PartialEq,
{
match self.data {
QueryData::Iterator(iter) => iter
.enumerate()
.find_map(|(i, item)| if item == *value { Some(i) } else { None }),
QueryData::SortedVec { items, .. } => items.iter().position(|item| item == value),
}
}
pub fn nth(self, index: usize) -> Option<T> {
self.element_at(index)
}
pub fn batch(self, size: usize) -> QueryBuilder<Vec<T>, Filtered> {
assert!(size > 0, "batch size must be greater than 0");
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(ChunkIterator {
inner: iter,
chunk_size: size,
})),
_state: PhantomData,
}
}
pub fn exactly_one(self) -> RinqResult<T> {
self.single()
}
pub fn tee(self) -> (Vec<T>, Vec<T>)
where
T: Clone,
{
let items = self.into_vec();
let clone = items.clone();
(items, clone)
}
}
#[cfg(feature = "parallel")]
impl<T: Send + 'static, State> QueryBuilder<T, State> {
pub fn into_parallel(self) -> ParallelQueryBuilder<T, State> {
ParallelQueryBuilder {
items: self.into_vec(),
_state: PhantomData,
}
}
}