#![no_std]
use num_traits::{identities::{one, zero}, PrimInt};
#[derive(Debug)]
pub enum Either<T, U> {
Primary(T),
Secondary(U)
}
impl<T, U> Either<T, U> {
#[inline]
pub fn is_primary(&self) -> bool {
match self {
Either::Primary(_) => true,
_ => false
}
}
#[inline]
pub fn is_secondary(&self) -> bool {
match self {
Either::Secondary(_) => true,
_ => false
}
}
}
impl<T> core::ops::Deref for Either<T, T> {
type Target=T;
fn deref(&self) -> &Self::Target {
match self {
Either::Primary(v) | Either::Secondary(v) => v
}
}
}
#[derive(Debug)]
pub struct CorIter<F, I, J> where F: FnMut(Either<&I::Item, &J::Item>) -> bool, I: Iterator, J: Iterator {
formula: F,
primary: I,
secondary: J,
cur_i: Option<I::Item>,
cur_j: Option<J::Item>
}
impl<F, I, J> CorIter<F, I, J> where F: FnMut(Either<&I::Item, &J::Item>) -> bool, I: Iterator, J: Iterator {
#[inline]
pub fn new(formula: F, mut primary: I, secondary: J) -> CorIter<F, I, J> {
let cur_i = primary.next();
let cur_j = None;
CorIter {
formula,
primary,
secondary,
cur_i,
cur_j
}
}
}
impl<F, I, J> Iterator for CorIter<F, I, J> where F: FnMut(Either<&I::Item, &J::Item>) -> bool, I: Iterator, J: Iterator {
type Item=Either<I::Item, J::Item>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(i) = self.cur_i.take() {
if (self.formula)(Either::Primary(&i)) {
self.cur_i = self.primary.next();
} else {
self.cur_j = self.secondary.next();
}
Some(Either::Primary(i))
} else if let Some(j) = self.cur_j.take() {
if (self.formula)(Either::Secondary(&j)) {
self.cur_i = self.primary.next();
} else {
self.cur_j = self.secondary.next();
}
Some(Either::Secondary(j))
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (p_min, p_max) = self.primary.size_hint();
let (s_min, s_max) = self.secondary.size_hint();
(p_min + s_min, p_max.and_then(|p| s_max.map(|s| s + p)))
}
}
#[derive(Debug)]
pub struct LinearCorIter<I, J, T>
where I: Iterator, J: Iterator, T: PrimInt {
a: T,
b: T,
c: T,
primary: I,
secondary: J,
}
impl<I, J, T> LinearCorIter<I, J, T> where I: Iterator, J: Iterator, T: PrimInt {
pub fn new(primary: I, secondary: J, a: T, b: T) -> LinearCorIter<I, J, T> {
let c = if b == zero() {
a
} else {
b
};
LinearCorIter {
a,
b,
c,
primary,
secondary
}
}
}
impl<I, J, T> Iterator for LinearCorIter<I, J, T> where I: Iterator, J: Iterator, T: PrimInt {
type Item=Either<I::Item, J::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.c > zero() {
self.c = self.c - one();
self.primary.next().map(|i| Either::Primary(i))
} else if self.c < zero() {
self.c = self.c + one();
self.secondary.next().map(|j| Either::Secondary(j))
} else {
self.c = self.a;
if self.b == zero() {
if self.a > zero() {
self.secondary.next().map(|j| Either::Secondary(j))
} else if self.a < zero() {
self.primary.next().map(|i| Either::Primary(i))
} else {
None
}
} else {
self.b = zero();
self.next()
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (p_min, p_max) = self.primary.size_hint();
let (s_min, s_max) = self.secondary.size_hint();
(p_min + s_min, p_max.and_then(|p| s_max.map(|s| s + p)))
}
}
pub trait Correlate : IntoIterator + Sized {
fn linear_correlate<I, T>(self, other: I, a: T, b: T) -> LinearCorIter<Self::IntoIter, I::IntoIter, T> where I: IntoIterator, T: PrimInt {
LinearCorIter::new(self.into_iter(), other.into_iter(), a, b)
}
fn correlate_with<I, F>(self, other: I, function: F) -> CorIter<F, Self::IntoIter, I::IntoIter> where I: IntoIterator, F: FnMut(Either<&Self::Item, &I::Item>) -> bool {
CorIter::new(function, self.into_iter(), other.into_iter())
}
}
impl<T> Correlate for T where T: IntoIterator {}
#[cfg(test)]
mod tests;