use core::cmp::Ordering;
use core::iter::FusedIterator;
use core::slice::Iter;
#[derive(Debug)]
pub struct Compare<'a, T> {
left: Iter<'a, T>,
right: Iter<'a, T>,
left_next: Option<&'a T>,
right_next: Option<&'a T>,
}
impl<'a, T> Compare<'a, T> {
pub fn new(left: &'a [T], right: &'a [T]) -> Self {
let mut left = left.iter();
let mut right = right.iter();
let left_next = left.next();
let right_next = right.next();
Self {
left,
right,
left_next,
right_next,
}
}
pub fn left_len(&self) -> usize {
self.left.len() + if self.left_next.is_some() { 1 } else { 0 }
}
pub fn right_len(&self) -> usize {
self.right.len() + if self.right_next.is_some() { 1 } else { 0 }
}
}
#[derive(Debug, Clone, Copy)]
pub enum Item<'a, T> {
Left(&'a T),
Right(&'a T),
Both(&'a T),
}
impl<'a, T> Iterator for Compare<'a, T>
where
T: Ord,
{
type Item = Item<'a, T>;
fn next(&mut self) -> Option<Self::Item> {
let item = match (self.left_next, self.right_next) {
(None, None) => return None,
(None, Some(right)) => Item::Right(right),
(Some(left), None) => Item::Left(left),
(Some(left), Some(right)) => match left.cmp(right) {
Ordering::Less => Item::Left(left),
Ordering::Equal => Item::Both(left),
Ordering::Greater => Item::Right(right),
},
};
if matches!(item, Item::Left(_) | Item::Both(_)) {
self.left_next = self.left.next();
}
if matches!(item, Item::Right(_) | Item::Both(_)) {
self.right_next = self.right.next();
}
Some(item)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(
self.left_len().max(self.right_len()),
self.left_len().checked_add(self.right_len()),
)
}
}
impl<'a, T> FusedIterator for Compare<'a, T> where T: Ord {}
impl<'a, 'b, T, U> PartialEq<Item<'b, U>> for Item<'a, T>
where
T: PartialEq<U>,
{
fn eq(&self, other: &Item<'b, U>) -> bool {
use Item::*;
match (self, other) {
(Left(a), Left(b)) | (Right(a), Right(b)) | (Both(a), Both(b)) => (*a).eq(*b),
_ => false,
}
}
}
impl<'a, T> Eq for Item<'a, T> where T: Eq {}
impl<'a, 'b, T, U> PartialOrd<Item<'b, U>> for Item<'a, T>
where
T: PartialOrd<U>,
{
fn partial_cmp(&self, other: &Item<'b, U>) -> Option<Ordering> {
use Item::*;
match (self, other) {
(Left(a), Left(b)) | (Right(a), Right(b)) | (Both(a), Both(b)) => (*a).partial_cmp(*b),
(Left(_), Right(_) | Both(_)) | (Right(_), Both(_)) => Some(Ordering::Less),
(Right(_), Left(_)) | (Both(_), Left(_) | Right(_)) => Some(Ordering::Greater),
}
}
}
impl<'a, T> Ord for Item<'a, T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
use Item::*;
match (self, other) {
(Left(a), Left(b)) | (Right(a), Right(b)) | (Both(a), Both(b)) => (*a).cmp(*b),
(Left(_), Right(_) | Both(_)) | (Right(_), Both(_)) => Ordering::Less,
(Right(_), Left(_)) | (Both(_), Left(_) | Right(_)) => Ordering::Greater,
}
}
}