use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
pub trait Comparator<T: ?Sized> {
fn cmp(&self, left: &T, right: &T) -> Ordering;
fn reversed(self) -> ReversedOrder<T, Self>
where
Self: Sized,
{
ReversedOrder(self, PhantomData)
}
fn then<N>(self, next: N) -> CompareThen<T, Self, N>
where
Self: Sized,
N: Comparator<T>,
{
CompareThen(self, next, PhantomData)
}
fn max<'a>(&self, left: &'a T, right: &'a T) -> &'a T {
match self.cmp(left, right) {
Ordering::Less => right,
_ => left,
}
}
fn min<'a>(&self, left: &'a T, right: &'a T) -> &'a T {
match self.cmp(left, right) {
Ordering::Greater => right,
_ => left,
}
}
}
pub fn natural_order<T>() -> NaturalOrder<T>
where
T: ?Sized + Ord,
{
NaturalOrder(PhantomData)
}
pub fn reverse_order<T>() -> ReversedNaturalOrder<T>
where
T: ?Sized + Ord,
{
ReversedNaturalOrder(PhantomData)
}
pub fn comparing<S, T, F>(map: F) -> Comparing<S, T, F>
where
S: ?Sized,
T: ?Sized + Ord,
F: Fn(&S) -> T,
{
Comparing(map, PhantomData, PhantomData)
}
pub fn comparing_ref<S, T, F>(map: F) -> ComparingRef<S, T, F>
where
S: ?Sized,
T: ?Sized + Ord,
F: Fn(&S) -> &T,
{
ComparingRef(map, PhantomData, PhantomData)
}
pub fn comparing_with<S, T, F, C>(map: F, cmp: C) -> ComparingWith<S, T, F, C>
where
S: ?Sized,
T: ?Sized + Ord,
F: Fn(&S) -> T,
C: Comparator<T>,
{
ComparingWith(map, cmp, PhantomData, PhantomData)
}
pub fn comparing_ref_with<S, T, F, C>(map: F, cmp: C) -> ComparingRefWith<S, T, F, C>
where
S: ?Sized,
T: ?Sized + Ord,
F: Fn(&S) -> &T,
C: Comparator<T>,
{
ComparingRefWith(map, cmp, PhantomData, PhantomData)
}
pub fn partial_order_or<T, C>(cmp: C) -> PartialOrderOr<T, C>
where
T: ?Sized + PartialOrd<T>,
C: Comparator<T>,
{
PartialOrderOr(cmp, PhantomData)
}
pub fn at_least<T, F>(is_at_least: F) -> AtLeast<T, F>
where
T: ?Sized,
F: Fn(&T) -> bool,
{
AtLeast(is_at_least, PhantomData)
}
pub fn at_greatest<T, F>(is_at_greatest: F) -> AtGreatest<T, F>
where
T: ?Sized,
F: Fn(&T) -> bool,
{
AtGreatest(is_at_greatest, PhantomData)
}
pub fn move_to_cmp_fn<T>(comparator: impl Comparator<T>) -> impl Fn(&T, &T) -> Ordering
where
T: ?Sized,
{
move |left, right| comparator.cmp(left, right)
}
impl<T, F> Comparator<T> for F
where
T: ?Sized,
F: Fn(&T, &T) -> Ordering,
{
fn cmp(&self, left: &T, right: &T) -> Ordering {
self(left, right)
}
}
#[derive(Copy, Clone, Debug)]
pub struct NaturalOrder<T: ?Sized + Ord>(PhantomData<*const T>);
impl<T> Comparator<T> for NaturalOrder<T>
where
T: ?Sized + Ord,
{
fn cmp(&self, left: &T, right: &T) -> Ordering {
left.cmp(right)
}
}
#[derive(Copy, Clone, Debug)]
pub struct ReversedNaturalOrder<T: ?Sized + Ord>(PhantomData<*const T>);
impl<T> Comparator<T> for ReversedNaturalOrder<T>
where
T: ?Sized + Ord,
{
fn cmp(&self, left: &T, right: &T) -> Ordering {
right.cmp(left)
}
}
#[derive(Copy, Clone, Debug)]
pub struct ReversedOrder<T: ?Sized, C: Comparator<T>>(C, PhantomData<*const T>);
impl<T, C> Comparator<T> for ReversedOrder<T, C>
where
T: ?Sized,
C: Comparator<T>,
{
fn cmp(&self, left: &T, right: &T) -> Ordering {
self.0.cmp(right, left)
}
}
#[derive(Copy, Clone, Debug)]
pub struct Comparing<S: ?Sized, T: ?Sized + Ord, F: Fn(&S) -> T>(
F,
PhantomData<*const S>,
PhantomData<*const T>,
);
impl<S, T, F> Comparator<S> for Comparing<S, T, F>
where
S: ?Sized,
T: Ord,
F: Fn(&S) -> T,
{
fn cmp(&self, left: &S, right: &S) -> Ordering {
Ord::cmp(&self.0(left), &self.0(right))
}
}
#[derive(Copy, Clone, Debug)]
pub struct ComparingRef<S: ?Sized, T: ?Sized + Ord, F: Fn(&S) -> &T>(
F,
PhantomData<*const S>,
PhantomData<*const T>,
);
impl<S, T, F> Comparator<S> for ComparingRef<S, T, F>
where
S: ?Sized,
T: ?Sized + Ord,
F: Fn(&S) -> &T,
{
fn cmp(&self, left: &S, right: &S) -> Ordering {
Ord::cmp(self.0(left), self.0(right))
}
}
#[derive(Copy, Clone, Debug)]
pub struct ComparingWith<S: ?Sized, T: ?Sized + Ord, F: Fn(&S) -> T, C: Comparator<T>>(
F,
C,
PhantomData<*const S>,
PhantomData<*const T>,
);
impl<S, T, F, C> Comparator<S> for ComparingWith<S, T, F, C>
where
S: ?Sized,
T: Ord,
F: Fn(&S) -> T,
C: Comparator<T>,
{
fn cmp(&self, left: &S, right: &S) -> Ordering {
self.1.cmp(&self.0(left), &self.0(right))
}
}
#[derive(Copy, Clone, Debug)]
pub struct ComparingRefWith<S: ?Sized, T: ?Sized + Ord, F: Fn(&S) -> &T, C: Comparator<T>>(
F,
C,
PhantomData<*const S>,
PhantomData<*const T>,
);
impl<S, T, F, C> Comparator<S> for ComparingRefWith<S, T, F, C>
where
S: ?Sized,
T: ?Sized + Ord,
F: Fn(&S) -> &T,
C: Comparator<T>,
{
fn cmp(&self, left: &S, right: &S) -> Ordering {
self.1.cmp(self.0(left), self.0(right))
}
}
#[derive(Copy, Clone, Debug)]
pub struct PartialOrderOr<T: ?Sized + PartialOrd<T>, C: Comparator<T>>(C, PhantomData<*const T>);
impl<T, C> Comparator<T> for PartialOrderOr<T, C>
where
T: ?Sized + PartialOrd<T>,
C: Comparator<T>,
{
fn cmp(&self, left: &T, right: &T) -> Ordering {
match left.partial_cmp(right) {
Some(ord) => ord,
None => self.0.cmp(left, right),
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct AtLeast<T: ?Sized, F: Fn(&T) -> bool>(F, PhantomData<*const T>);
impl<T, F> Comparator<T> for AtLeast<T, F>
where
T: ?Sized,
F: Fn(&T) -> bool,
{
fn cmp(&self, left: &T, right: &T) -> Ordering {
match (self.0(left), self.0(right)) {
(a, b) if a == b => Ordering::Equal,
(true, _) => Ordering::Less,
_ => Ordering::Greater,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct AtGreatest<T: ?Sized, F: Fn(&T) -> bool>(F, PhantomData<*const T>);
impl<T, F> Comparator<T> for AtGreatest<T, F>
where
T: ?Sized,
F: Fn(&T) -> bool,
{
fn cmp(&self, left: &T, right: &T) -> Ordering {
match (self.0(left), self.0(right)) {
(a, b) if a == b => Ordering::Equal,
(true, _) => Ordering::Greater,
_ => Ordering::Less,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct CompareThen<T: ?Sized, C: Comparator<T>, N: Comparator<T>>(C, N, PhantomData<*const T>);
impl<T, C, N> Comparator<T> for CompareThen<T, C, N>
where
T: ?Sized,
C: Comparator<T>,
N: Comparator<T>,
{
fn cmp(&self, left: &T, right: &T) -> Ordering {
match self.0.cmp(left, right) {
Ordering::Equal => self.1.cmp(left, right),
ordering => ordering,
}
}
}
pub trait EqClass<T: ?Sized> {
fn eq(&self, left: &T, right: &T) -> bool;
fn and<N>(self, next: N) -> BothEq<T, Self, N>
where
Self: Sized,
N: EqClass<T>,
{
BothEq(self, next, PhantomData)
}
}
pub fn natural_eq<T>() -> NaturalEq<T>
where
T: ?Sized + PartialEq<T>,
{
NaturalEq(PhantomData)
}
pub fn partial_eq<T>() -> PartialEqClass<T>
where
T: ?Sized + PartialEq<T>,
{
PartialEqClass(PhantomData)
}
pub fn eq_by<S, T, F>(map: F) -> EqBy<S, T, F>
where
S: ?Sized,
T: ?Sized + PartialEq<T>,
F: Fn(&S) -> T,
{
EqBy(map, PhantomData, PhantomData)
}
pub fn eq_by_ref<S, T, F>(map: F) -> EqByRef<S, T, F>
where
S: ?Sized,
T: ?Sized + PartialEq<T>,
F: Fn(&S) -> &T,
{
EqByRef(map, PhantomData, PhantomData)
}
pub fn eq_by_with<S, T, F, C>(map: F, eq: C) -> EqByWith<S, T, F, C>
where
S: ?Sized,
T: ?Sized + PartialEq<T>,
F: Fn(&S) -> T,
C: EqClass<T>,
{
EqByWith(map, eq, PhantomData, PhantomData)
}
pub fn eq_by_ref_with<S, T, F, C>(map: F, eq: C) -> EqByRefWith<S, T, F, C>
where
S: ?Sized,
T: ?Sized + PartialEq<T>,
F: Fn(&S) -> &T,
C: EqClass<T>,
{
EqByRefWith(map, eq, PhantomData, PhantomData)
}
pub fn eq_by_hash<T>() -> EqByHash<T>
where
T: ?Sized + Hash,
{
EqByHash(PhantomData)
}
pub fn eq_by_cmp<T, C>(cmp: C) -> EqByCmp<T, C>
where
T: ?Sized,
C: Comparator<T>,
{
EqByCmp(cmp, PhantomData)
}
pub fn move_to_eq_fn<T>(eq_class: impl EqClass<T>) -> impl Fn(&T, &T) -> bool
where
T: ?Sized,
{
move |left, right| eq_class.eq(left, right)
}
impl<T, F> EqClass<T> for F
where
T: ?Sized,
F: Fn(&T, &T) -> bool,
{
fn eq(&self, left: &T, right: &T) -> bool {
self(left, right)
}
}
#[derive(Copy, Clone, Debug)]
pub struct NaturalEq<T: ?Sized + PartialEq<T>>(PhantomData<*const T>);
impl<T> EqClass<T> for NaturalEq<T>
where
T: ?Sized + PartialEq<T>,
{
fn eq(&self, left: &T, right: &T) -> bool {
left.eq(right)
}
}
#[derive(Copy, Clone, Debug)]
pub struct PartialEqClass<T: ?Sized + PartialEq<T>>(PhantomData<*const T>);
impl<T> EqClass<T> for PartialEqClass<T>
where
T: ?Sized + PartialEq<T>,
{
fn eq(&self, left: &T, right: &T) -> bool {
match (left.eq(left), right.eq(right)) {
(false, false) => true,
(true, true) => left.eq(right),
_ => false,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct EqBy<S: ?Sized, T: ?Sized + PartialEq<T>, F: Fn(&S) -> T>(
F,
PhantomData<*const S>,
PhantomData<*const T>,
);
impl<S, T, F> EqClass<S> for EqBy<S, T, F>
where
S: ?Sized,
T: PartialEq<T>,
F: Fn(&S) -> T,
{
fn eq(&self, left: &S, right: &S) -> bool {
self.0(left).eq(&self.0(right))
}
}
#[derive(Copy, Clone, Debug)]
pub struct EqByRef<S: ?Sized, T: ?Sized + PartialEq<T>, F: Fn(&S) -> &T>(
F,
PhantomData<*const S>,
PhantomData<*const T>,
);
impl<S, T, F> EqClass<S> for EqByRef<S, T, F>
where
S: ?Sized,
T: ?Sized + PartialEq<T>,
F: Fn(&S) -> &T,
{
fn eq(&self, left: &S, right: &S) -> bool {
self.0(left).eq(self.0(right))
}
}
#[derive(Copy, Clone, Debug)]
pub struct EqByWith<S: ?Sized, T: ?Sized + PartialEq<T>, F: Fn(&S) -> T, C: EqClass<T>>(
F,
C,
PhantomData<*const S>,
PhantomData<*const T>,
);
impl<S, T, F, C> EqClass<S> for EqByWith<S, T, F, C>
where
S: ?Sized,
T: PartialEq<T>,
F: Fn(&S) -> T,
C: EqClass<T>,
{
fn eq(&self, left: &S, right: &S) -> bool {
self.1.eq(&self.0(left), &self.0(right))
}
}
#[derive(Copy, Clone, Debug)]
pub struct EqByRefWith<S: ?Sized, T: ?Sized + PartialEq<T>, F: Fn(&S) -> &T, C: EqClass<T>>(
F,
C,
PhantomData<*const S>,
PhantomData<*const T>,
);
impl<S, T, F, C> EqClass<S> for EqByRefWith<S, T, F, C>
where
S: ?Sized,
T: ?Sized + PartialEq<T>,
F: Fn(&S) -> &T,
C: EqClass<T>,
{
fn eq(&self, left: &S, right: &S) -> bool {
self.1.eq(self.0(left), self.0(right))
}
}
#[derive(Copy, Clone, Debug)]
pub struct EqByHash<T: ?Sized + Hash>(PhantomData<*const T>);
impl<T> EqClass<T> for EqByHash<T>
where
T: ?Sized + Hash,
{
fn eq(&self, left: &T, right: &T) -> bool {
#[inline]
fn hash<T: ?Sized + Hash>(to_hash: &T) -> u64 {
let mut hasher = DefaultHasher::new();
to_hash.hash(&mut hasher);
hasher.finish()
}
hash(left) == hash(right)
}
}
#[derive(Copy, Clone, Debug)]
pub struct EqByCmp<T: ?Sized, C: Comparator<T>>(C, PhantomData<*const T>);
impl<T, C> EqClass<T> for EqByCmp<T, C>
where
T: ?Sized,
C: Comparator<T>,
{
fn eq(&self, left: &T, right: &T) -> bool {
Ordering::Equal == self.0.cmp(left, right)
}
}
#[derive(Copy, Clone, Debug)]
pub struct BothEq<T: ?Sized, C: EqClass<T>, N: EqClass<T>>(C, N, PhantomData<*const T>);
impl<T, C, N> EqClass<T> for BothEq<T, C, N>
where
T: ?Sized,
C: EqClass<T>,
N: EqClass<T>,
{
fn eq(&self, left: &T, right: &T) -> bool {
self.0.eq(left, right) && self.1.eq(left, right)
}
}
mod tests;