#![no_std]
#![deny(missing_debug_implementations, missing_copy_implementations)]
#![doc(html_root_url = "https://docs.rs/log/2.0.2")]
#[cfg(test)]
extern crate std;
mod put_back;
#[cfg(test)]
mod tests;
use core::cmp::{self, Ordering};
use core::fmt::{self, Debug};
use self::put_back::PutBack;
pub fn cmp<T, L, R>(a: L, b: R) -> Option<Ordering>
where
T: Ord,
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
{
classify(a, b).try_fold(Ordering::Equal, cmp_fold)
}
pub fn cmp_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> Option<Ordering>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
K: Ord,
F: FnMut(&T) -> K,
{
classify_by_key(a, b, key).try_fold(Ordering::Equal, cmp_fold)
}
pub fn cmp_by<T, L, R, F>(a: L, b: R, cmp: F) -> Option<Ordering>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
F: FnMut(&mut T, &mut T) -> Ordering,
{
classify_by(a, b, cmp).try_fold(Ordering::Equal, cmp_fold)
}
fn cmp_fold<T>(init: Ordering, next: Inclusion<T>) -> Option<Ordering> {
use Ordering::*;
match (init, next.ordering()) {
(Less, Greater) | (Greater, Less) => None,
(Equal, x) | (x, Equal) => Some(x),
(Greater, Greater) => Some(Greater),
(Less, Less) => Some(Less),
}
}
pub fn union<T, L, R>(a: L, b: R) -> impl Iterator<Item = T>
where
T: Ord,
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
{
classify(a, b).map(Inclusion::union)
}
pub fn union_by<T, L, R, F>(a: L, b: R, cmp: F) -> impl Iterator<Item = T>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
F: FnMut(&mut T, &mut T) -> Ordering,
{
classify_by(a, b, cmp).map(Inclusion::union)
}
pub fn union_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> impl Iterator<Item = T>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
K: Ord,
F: FnMut(&T) -> K,
{
classify_by_key(a, b, key).map(Inclusion::union)
}
pub fn intersection<T, L, R>(a: L, b: R) -> impl Iterator<Item = T>
where
T: Ord,
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
{
classify(a, b)
.with_size_hint(intersection_size_hint)
.filter_map(Inclusion::intersection)
}
pub fn intersection_by<T, L, R, F>(a: L, b: R, cmp: F) -> impl Iterator<Item = T>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
F: FnMut(&mut T, &mut T) -> Ordering,
{
classify_by(a, b, cmp)
.with_size_hint(|iter| intersection_size_hint(&iter.inner))
.filter_map(Inclusion::intersection)
}
pub fn intersection_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> impl Iterator<Item = T>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
K: Ord,
F: FnMut(&T) -> K,
{
classify_by_key(a, b, key)
.with_size_hint(|iter| intersection_size_hint(&iter.inner))
.filter_map(Inclusion::intersection)
}
pub fn difference<T, L, R>(a: L, b: R) -> impl Iterator<Item = T>
where
T: Ord,
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
{
classify(a, b)
.with_size_hint(difference_size_hint)
.filter_map(Inclusion::difference)
}
pub fn difference_by<T, L, R, F>(a: L, b: R, cmp: F) -> impl Iterator<Item = T>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
F: FnMut(&mut T, &mut T) -> Ordering,
{
classify_by(a, b, cmp)
.with_size_hint(|iter| difference_size_hint(&iter.inner))
.filter_map(Inclusion::difference)
}
pub fn difference_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> impl Iterator<Item = T>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
K: Ord,
F: FnMut(&T) -> K,
{
classify_by_key(a, b, key)
.with_size_hint(|iter| difference_size_hint(&iter.inner))
.filter_map(Inclusion::difference)
}
pub fn symmetric_difference<T, L, R>(a: L, b: R) -> impl Iterator<Item = T>
where
T: Ord,
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
{
classify(a, b).filter_map(Inclusion::symmetric_difference)
}
pub fn symmetric_difference_by<T, L, R, F>(a: L, b: R, cmp: F) -> impl Iterator<Item = T>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
F: FnMut(&mut T, &mut T) -> Ordering,
{
classify_by(a, b, cmp).filter_map(Inclusion::symmetric_difference)
}
pub fn symmetric_difference_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> impl Iterator<Item = T>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
K: Ord,
F: FnMut(&T) -> K,
{
classify_by_key(a, b, key).filter_map(Inclusion::symmetric_difference)
}
pub fn classify<T, L, R>(a: L, b: R) -> Classify<L::IntoIter, R::IntoIter>
where
T: Ord,
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
{
Classify::new(a, b)
}
pub fn classify_by<T, L, R, F>(a: L, b: R, cmp: F) -> ClassifyBy<L::IntoIter, R::IntoIter, F>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
F: FnMut(&mut T, &mut T) -> Ordering,
{
ClassifyBy {
inner: Classify::new(a, b),
cmp,
}
}
pub fn classify_by_key<T, L, R, K, F>(
a: L,
b: R,
key: F,
) -> ClassifyByKey<L::IntoIter, R::IntoIter, F>
where
L: IntoIterator<Item = T>,
R: IntoIterator<Item = T>,
K: Ord,
F: FnMut(&T) -> K,
{
ClassifyByKey {
inner: Classify::new(a, b),
key,
}
}
pub struct Classify<L, R>
where
L: Iterator,
R: Iterator,
{
lhs: PutBack<L>,
rhs: PutBack<R>,
}
impl<T, L, R> Classify<L, R>
where
L: Iterator<Item = T>,
R: Iterator<Item = T>,
{
fn new(
lhs: impl IntoIterator<IntoIter = L, Item = T>,
rhs: impl IntoIterator<IntoIter = R, Item = T>,
) -> Self {
Classify {
lhs: PutBack::new(lhs.into_iter()),
rhs: PutBack::new(rhs.into_iter()),
}
}
fn next_by<F>(&mut self, mut cmp: F) -> Option<Inclusion<T>>
where
F: FnMut(&mut T, &mut T) -> Ordering,
{
match (self.lhs.next(), self.rhs.next()) {
(Some(mut l), Some(mut r)) => match cmp(&mut l, &mut r) {
Ordering::Less => {
self.rhs.put_back(r);
Some(Inclusion::Left(l))
}
Ordering::Equal => Some(Inclusion::Both(l, r)),
Ordering::Greater => {
self.lhs.put_back(l);
Some(Inclusion::Right(r))
}
},
(Some(l), None) => Some(Inclusion::Left(l)),
(None, Some(r)) => Some(Inclusion::Right(r)),
(None, None) => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (lmin, lmax) = self.lhs.size_hint();
let (rmin, rmax) = self.rhs.size_hint();
let min = cmp::max(lmin, rmin);
let max = match (lmax, rmax) {
(Some(lmax), Some(rmax)) => lmax.checked_add(rmax),
_ => None,
};
(min, max)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Inclusion<T> {
Left(T),
Both(T, T),
Right(T),
}
impl<T> Inclusion<T> {
pub fn union(self) -> T {
match self {
Inclusion::Left(l) => l,
Inclusion::Both(l, _) => l,
Inclusion::Right(r) => r,
}
}
pub fn intersection(self) -> Option<T> {
match self {
Inclusion::Left(_) | Inclusion::Right(_) => None,
Inclusion::Both(l, _) => Some(l),
}
}
pub fn difference(self) -> Option<T> {
match self {
Inclusion::Left(l) => Some(l),
Inclusion::Both(_, _) | Inclusion::Right(_) => None,
}
}
pub fn symmetric_difference(self) -> Option<T> {
match self {
Inclusion::Left(l) => Some(l),
Inclusion::Both(_, _) => None,
Inclusion::Right(r) => Some(r),
}
}
pub fn ordering(&self) -> Ordering {
match self {
Inclusion::Left(_) => Ordering::Greater,
Inclusion::Both(_, _) => Ordering::Equal,
Inclusion::Right(_) => Ordering::Less,
}
}
}
impl<T, L, R> Iterator for Classify<L, R>
where
T: Ord,
L: Iterator<Item = T>,
R: Iterator<Item = T>,
{
type Item = Inclusion<T>;
fn next(&mut self) -> Option<Self::Item> {
self.next_by(|l, r| Ord::cmp(l, r))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.size_hint()
}
}
pub struct ClassifyBy<L, R, F>
where
L: Iterator,
R: Iterator,
{
inner: Classify<L, R>,
cmp: F,
}
impl<T, L, R, F> Iterator for ClassifyBy<L, R, F>
where
L: Iterator<Item = T>,
R: Iterator<Item = T>,
F: FnMut(&mut T, &mut T) -> Ordering,
{
type Item = Inclusion<T>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next_by(&mut self.cmp)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
pub struct ClassifyByKey<L, R, F>
where
L: Iterator,
R: Iterator,
{
inner: Classify<L, R>,
key: F,
}
impl<T, L, R, K, F> Iterator for ClassifyByKey<L, R, F>
where
L: Iterator<Item = T>,
R: Iterator<Item = T>,
K: Ord,
F: FnMut(&T) -> K,
{
type Item = Inclusion<T>;
fn next(&mut self) -> Option<Self::Item> {
let key = &mut self.key;
self.inner.next_by(|l, r| Ord::cmp(&key(l), &key(r)))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<L, R> Debug for Classify<L, R>
where
L: Debug + Iterator,
R: Debug + Iterator,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Classify")
.field("lhs", &self.lhs)
.field("rhs", &self.rhs)
.finish()
}
}
impl<L, R, F> Debug for ClassifyBy<L, R, F>
where
L: Debug + Iterator,
R: Debug + Iterator,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ClassifyBy")
.field("lhs", &self.inner.lhs)
.field("rhs", &self.inner.rhs)
.finish()
}
}
impl<L, R, F> Debug for ClassifyByKey<L, R, F>
where
L: Debug + Iterator,
R: Debug + Iterator,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ClassifyByKey")
.field("lhs", &self.inner.lhs)
.field("rhs", &self.inner.rhs)
.finish()
}
}
struct SizeHintIterator<I, F> {
iter: I,
f: F,
}
impl<I, F> Iterator for SizeHintIterator<I, F>
where
I: Iterator,
F: Fn(&I) -> (usize, Option<usize>),
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.f)(&self.iter)
}
}
trait WithSizeHint
where
Self: Sized + Iterator,
{
fn with_size_hint<F>(self, f: F) -> SizeHintIterator<Self, F>
where
F: Fn(&Self) -> (usize, Option<usize>),
{
SizeHintIterator { iter: self, f }
}
}
impl<I> WithSizeHint for I
where
Self: Sized,
I: Iterator,
{
}
fn intersection_size_hint<L, R>(classify: &Classify<L, R>) -> (usize, Option<usize>)
where
L: Iterator,
R: Iterator,
{
let (_, lmax) = classify.lhs.size_hint();
let (_, rmax) = classify.rhs.size_hint();
let max = match (lmax, rmax) {
(Some(l), Some(r)) => Some(l.min(r)),
(_, _) => None,
};
(0, max)
}
fn difference_size_hint<L, R>(classify: &Classify<L, R>) -> (usize, Option<usize>)
where
L: Iterator,
R: Iterator,
{
let (_, lmax) = classify.lhs.size_hint();
(0, lmax)
}