use std::iter::{FusedIterator, Peekable};
use crate::intervals::ops::SymmetricallyDifferentiable;
use crate::ops::SymmetricDifferenceResult;
#[derive(Debug, Clone, Hash)]
pub struct PeerSymmetricDifference<I> {
iter: I,
exhausted: bool,
}
impl<'a, I, T, U> PeerSymmetricDifference<I>
where
I: Iterator<Item = &'a T>,
T: 'a + SymmetricallyDifferentiable<Output = U> + Into<U> + Clone,
{
pub fn new(iter: I) -> PeerSymmetricDifference<Peekable<I>> {
PeerSymmetricDifference {
iter: iter.peekable(),
exhausted: false,
}
}
}
impl<'a, I, T, U> Iterator for PeerSymmetricDifference<Peekable<I>>
where
I: Iterator<Item = &'a T>,
T: 'a + SymmetricallyDifferentiable<Output = U> + Into<U> + Clone,
{
type Item = (U, Option<U>);
fn next(&mut self) -> Option<Self::Item> {
if self.exhausted {
return None;
}
let Some(current) = self.iter.next() else {
self.exhausted = true;
return None;
};
let Some(peeked) = self.iter.peek() else {
self.exhausted = true;
return None;
};
match current.sym_diff(peeked) {
SymmetricDifferenceResult::Single(shrunk) => Some((shrunk, None)),
SymmetricDifferenceResult::Split(split_first_part, split_second_part) => {
Some((split_first_part, Some(split_second_part)))
},
SymmetricDifferenceResult::Separate => Some((current.clone().into(), Some((*peeked).clone().into()))),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let inner_size_hint = self.iter.size_hint();
(
inner_size_hint.0.saturating_sub(1),
inner_size_hint.1.map(|x| x.saturating_sub(1)),
)
}
}
impl<'a, I, T, U> FusedIterator for PeerSymmetricDifference<Peekable<I>>
where
I: Iterator<Item = &'a T>,
T: 'a + SymmetricallyDifferentiable<Output = U> + Into<U> + Clone,
{
}
pub trait PeerSymmetricDifferenceIteratorDispatcher<'a, T, U>
where
Self: IntoIterator + Sized,
Self::IntoIter: Iterator<Item = &'a T>,
T: 'a + SymmetricallyDifferentiable<Output = U> + Into<U> + Clone,
{
fn peer_symmetric_difference(self) -> PeerSymmetricDifference<Peekable<Self::IntoIter>> {
PeerSymmetricDifference::new(self.into_iter())
}
}
impl<'a, I, T, U> PeerSymmetricDifferenceIteratorDispatcher<'a, T, U> for I
where
I: IntoIterator + Sized,
I::IntoIter: Iterator<Item = &'a T>,
T: 'a + SymmetricallyDifferentiable<Output = U> + Into<U> + Clone,
{
}
#[derive(Debug, Clone)]
pub struct PeerSymmetricDifferenceWith<I, F> {
iter: I,
f: F,
exhausted: bool,
}
impl<'a, I, T, U, F> PeerSymmetricDifferenceWith<I, F>
where
I: Iterator<Item = &'a T>,
T: 'a + Into<U> + Clone,
F: FnMut(&T, &T) -> SymmetricDifferenceResult<U>,
{
pub fn new(iter: I, f: F) -> PeerSymmetricDifferenceWith<Peekable<I>, F> {
PeerSymmetricDifferenceWith {
iter: iter.peekable(),
f,
exhausted: false,
}
}
}
impl<'a, I, T, U, F> Iterator for PeerSymmetricDifferenceWith<Peekable<I>, F>
where
I: Iterator<Item = &'a T>,
T: 'a + Into<U> + Clone,
F: FnMut(&T, &T) -> SymmetricDifferenceResult<U>,
{
type Item = (U, Option<U>);
fn next(&mut self) -> Option<Self::Item> {
if self.exhausted {
return None;
}
let Some(current) = self.iter.next() else {
self.exhausted = true;
return None;
};
let Some(peeked) = self.iter.peek() else {
self.exhausted = true;
return None;
};
match (self.f)(current, peeked) {
SymmetricDifferenceResult::Single(shrunk) => Some((shrunk, None)),
SymmetricDifferenceResult::Split(split_first_part, split_second_part) => {
Some((split_first_part, Some(split_second_part)))
},
SymmetricDifferenceResult::Separate => Some((current.clone().into(), Some((*peeked).clone().into()))),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let inner_size_hint = self.iter.size_hint();
(
inner_size_hint.0.saturating_sub(1),
inner_size_hint.1.map(|x| x.saturating_sub(1)),
)
}
}
impl<'a, I, T, U, F> FusedIterator for PeerSymmetricDifferenceWith<Peekable<I>, F>
where
I: Iterator<Item = &'a T>,
T: 'a + Into<U> + Clone,
F: FnMut(&T, &T) -> SymmetricDifferenceResult<U>,
{
}
pub trait PeerSymmetricDifferenceWithIteratorDispatcher<'a, T, U, F>
where
Self: IntoIterator + Sized,
Self::IntoIter: Iterator<Item = &'a T>,
T: 'a + Into<U> + Clone,
F: FnMut(&T, &T) -> SymmetricDifferenceResult<U>,
{
fn peer_symmetric_difference_with(self, f: F) -> PeerSymmetricDifferenceWith<Peekable<Self::IntoIter>, F> {
PeerSymmetricDifferenceWith::new(self.into_iter(), f)
}
}
impl<'a, I, T, U, F> PeerSymmetricDifferenceWithIteratorDispatcher<'a, T, U, F> for I
where
I: IntoIterator + Sized,
I::IntoIter: Iterator<Item = &'a T>,
T: 'a + Into<U> + Clone,
F: FnMut(&T, &T) -> SymmetricDifferenceResult<U>,
{
}