use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;
use super::{PhantomInvariantData, TyEq, Val};
macro_rules! impl_all {
( $name:ident ) => {
#[cfg_attr(feature = "cargo-clippy", allow(expl_impl_clone_on_copy))]
impl<X: ?Sized, Y: ?Sized> Clone for $name<X, Y> {
fn clone(&self) -> Self { *self }
}
impl<X: ?Sized, Y: ?Sized> Copy for $name<X, Y> { }
impl<X: ?Sized, Y: ?Sized> fmt::Debug for $name<X, Y> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(stringify!($name))
}
}
}
}
pub struct Equal<X: ?Sized, Y: ?Sized>(
PhantomInvariantData<X>,
PhantomInvariantData<Y>,
);
impl_all!(Equal);
impl<'x, 'y, T> Equal<Val<'x, T>, Val<'y, T>> {
pub fn into_ty_eq(self) -> TyEq<Val<'x, T>, Val<'y, T>> {
use std::mem::transmute;
unsafe { transmute(TyEq::<Val<'x, T>, Val<'x, T>>::refl()) }
}
}
pub struct NotEqual<X: ?Sized, Y: ?Sized>(
PhantomInvariantData<X>,
PhantomInvariantData<Y>,
);
impl_all!(NotEqual);
pub struct Less<X: ?Sized, Y: ?Sized>(
PhantomInvariantData<X>,
PhantomInvariantData<Y>,
);
impl_all!(Less);
pub struct Greater<X: ?Sized, Y: ?Sized>(
PhantomInvariantData<X>,
PhantomInvariantData<Y>,
);
impl_all!(Greater);
pub type LessEqual<X, Y> = Result<Less<X, Y>, Equal<X, Y>>;
pub type GreaterEqual<X, Y> = Result<Greater<X, Y>, Equal<X, Y>>;
pub fn partial_equal<X, Y, T>(x: &X, y: &Y) -> Option<Equal<X, Y>>
where X: Deref<Target=T>, Y: Deref<Target=T>, T: PartialEq + ?Sized {
if &**x == &**y {
Some(Equal(PhantomData, PhantomData))
} else {
None
}
}
pub fn equal<X, Y, T>(x: &X, y: &Y) -> Result<Equal<X, Y>, NotEqual<X, Y>>
where X: Deref<Target=T>, Y: Deref<Target=T>, T: Eq + ?Sized {
if &**x == &**y {
Ok(Equal(PhantomData, PhantomData))
} else {
Err(NotEqual(PhantomData, PhantomData))
}
}
pub fn partial_compare<X, Y, T>(x: &X, y: &Y)
-> Option<Result<Less<X, Y>,
GreaterEqual<X, Y>>>
where X: Deref<Target=T>, Y: Deref<Target=T>, T: Ord + ?Sized {
use std::cmp::Ordering;
match PartialOrd::partial_cmp(&**x, &**y) {
None => None,
Some(ordering) => Some(match ordering {
Ordering::Less => Ok(Less(PhantomData, PhantomData)),
Ordering::Equal => Err(Err(Equal(PhantomData, PhantomData))),
Ordering::Greater => Err(Ok(Greater(PhantomData, PhantomData))),
}),
}
}
pub fn compare<X, Y, T>(x: &X, y: &Y) -> Result<Less<X, Y>, GreaterEqual<X, Y>>
where X: Deref<Target=T>, Y: Deref<Target=T>, T: Ord + ?Sized {
use std::cmp::Ordering;
match Ord::cmp(&**x, &**y) {
Ordering::Less => Ok(Less(PhantomData, PhantomData)),
Ordering::Equal => Err(Err(Equal(PhantomData, PhantomData))),
Ordering::Greater => Err(Ok(Greater(PhantomData, PhantomData))),
}
}
#[cfg(test)]
mod tests {
use super::super::*;
use super::*;
#[test]
fn it_works() {
imprint(1, |one| { imprint(2, |two| { imprint(1, |one_| {
assert!(partial_compare(&one, &two).is_some());
assert!(compare(&one, &two).is_ok());
assert!(compare(&two, &one).unwrap_err().is_ok());
assert!(equal(&two, &one).is_err());
assert!(partial_equal(&two, &one).is_none());
assert!(compare(&one, &one_).unwrap_err().is_err());
assert!(equal(&one, &one_).is_ok());
assert!(partial_equal(&one, &one_).is_some());
}) }) });
}
}