use crate::{TypeEq, TypeNe};
#[cfg(feature = "rust_1_61")]
use crate::{BaseTypeWitness, MetaBaseTypeWit, SomeTypeArgIsNe};
use core::{
any::Any,
cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd},
hash::{Hash, Hasher},
fmt::{self, Debug},
};
#[cfg_attr(not(feature = "rust_1_65"), doc = "```ignore")]
#[cfg_attr(feature = "rust_1_65", doc = "```rust")]
pub enum TypeCmp<L: ?Sized, R: ?Sized>{
Eq(TypeEq<L, R>),
Ne(TypeNe<L, R>),
}
impl<L: ?Sized, R: ?Sized> TypeCmp<L, R> {
#[deprecated = concat!(
"fallout of `https://github.com/rust-lang/rust/issues/97156`,",
"`TypeId::of::<L>() != TypeId::of::<R>()` does not imply `L != R`"
)]
pub fn with_any() -> Self
where
L: Sized + Any,
R: Sized + Any,
{
#[allow(deprecated)]
if let Some(equal) = TypeEq::with_any() {
TypeCmp::Eq(equal)
} else if let Some(unequal) = TypeNe::with_any() {
TypeCmp::Ne(unequal)
} else {
unreachable!()
}
}
pub const fn flip(self) -> TypeCmp<R, L> {
match self {
TypeCmp::Eq(te) => TypeCmp::Eq(te.flip()),
TypeCmp::Ne(te) => TypeCmp::Ne(te.flip()),
}
}
pub const fn join_left<Q: ?Sized>(self, left: TypeEq<Q, L>) -> TypeCmp<Q, R> {
match self {
TypeCmp::Eq(te) => TypeCmp::Eq(left.join(te)),
TypeCmp::Ne(te) => TypeCmp::Ne(te.join_left(left)),
}
}
pub const fn join_right<Q: ?Sized>(self, right: TypeEq<R, Q>) -> TypeCmp<L, Q> {
match self {
TypeCmp::Eq(te) => TypeCmp::Eq(te.join(right)),
TypeCmp::Ne(te) => TypeCmp::Ne(te.join_right(right)),
}
}
pub const fn eq(self) -> Option<TypeEq<L, R>> {
match self {
TypeCmp::Eq(te) => Some(te),
TypeCmp::Ne(_) => None,
}
}
pub const fn ne(self) -> Option<TypeNe<L, R>> {
match self {
TypeCmp::Eq(_) => None,
TypeCmp::Ne(te) => Some(te),
}
}
pub const fn is_eq(self) -> bool {
matches!(self, TypeCmp::Eq(_))
}
pub const fn is_ne(self) -> bool {
matches!(self, TypeCmp::Ne(_))
}
#[track_caller]
pub const fn unwrap_eq(self) -> TypeEq<L, R> {
match self {
TypeCmp::Eq(te) => te,
TypeCmp::Ne(_) => panic!("called `TypeCmp::unwrap_eq` on a `TypeNe` value"),
}
}
#[track_caller]
pub const fn unwrap_ne(self) -> TypeNe<L, R> {
match self {
TypeCmp::Eq(_) => panic!("called `TypeCmp::unwrap_ne` on a `TypeEq` value"),
TypeCmp::Ne(te) => te,
}
}
}
#[cfg(feature = "rust_1_61")]
macro_rules! alternative_docs {
($func:expr) => {concat!(
"# Alternative\n",
"\n",
"[`methods::", $func,"`](crate::methods::", $func, ") \n",
"is an alternative to this function. \n",
"\n",
"This method always returns `TypeCmp`, \n",
"while [that function](crate::methods::", $func, ")\n",
"returns [`TypeNe`] when any argument is a `TypeNe`.\n",
"\n",
"# Returned variant\n",
"\n",
"This returns either [`TypeCmp::Eq`] or [`TypeCmp::Ne`]",
" depending on the arguments:\n",
"- if all arguments (including `self`)",
" are [`TypeEq`] or [`TypeCmp::Eq`], this returns [`TypeCmp::Eq`] \n",
"- if any argument (including `self`) ",
"is a [`TypeNe`] or [`TypeCmp::Ne`], this returns [`TypeCmp::Ne`] \n",
)};
}
#[cfg(feature = "rust_1_61")]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))]
impl<L, R> TypeCmp<L, R> {
#[doc = alternative_docs!("zip2")]
pub const fn zip<A>(self, other: A) -> TypeCmp<(L, A::L), (R, A::R)>
where
A: BaseTypeWitness,
{
let other = MetaBaseTypeWit::to_cmp(A::WITNESS, other);
match (self, other) {
(TypeCmp::Eq(tel), TypeCmp::Eq(ter)) => {
TypeCmp::Eq(tel.zip(ter))
}
(TypeCmp::Ne(ne), _) => {
TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip2(ne, other))
}
(_, TypeCmp::Ne(ne)) => {
TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip2(self, ne))
}
}
}
#[doc = alternative_docs!("zip3")]
pub const fn zip3<A, B>(self, arg0: A, arg1: B) -> TypeCmp<(L, A::L, B::L), (R, A::R, B::R)>
where
A: BaseTypeWitness,
A::L: Sized,
A::R: Sized,
B: BaseTypeWitness,
{
let arg0 = MetaBaseTypeWit::to_cmp(A::WITNESS, arg0);
let arg1 = MetaBaseTypeWit::to_cmp(B::WITNESS, arg1);
match (self, arg0, arg1) {
(TypeCmp::Eq(te0), TypeCmp::Eq(te1), TypeCmp::Eq(te2)) => {
TypeCmp::Eq(te0.zip3(te1, te2))
}
(TypeCmp::Ne(ne), _, _) => {
TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip3(ne, arg0, arg1))
}
(_, TypeCmp::Ne(ne), _) => {
TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip3(self, ne, arg1))
}
(_, _, TypeCmp::Ne(ne)) => {
TypeCmp::Ne(SomeTypeArgIsNe::C(TypeEq::NEW).zip3(self, arg0, ne))
}
}
}
#[doc = alternative_docs!("zip4")]
pub const fn zip4<A, B, C>(
self,
arg0: A,
arg1: B,
arg2: C,
) -> TypeCmp<(L, A::L, B::L, C::L), (R, A::R, B::R, C::R)>
where
A: BaseTypeWitness,
A::L: Sized,
A::R: Sized,
B: BaseTypeWitness,
B::L: Sized,
B::R: Sized,
C: BaseTypeWitness,
{
let arg0 = MetaBaseTypeWit::to_cmp(A::WITNESS, arg0);
let arg1 = MetaBaseTypeWit::to_cmp(B::WITNESS, arg1);
let arg2 = MetaBaseTypeWit::to_cmp(C::WITNESS, arg2);
match (self, arg0, arg1, arg2) {
(TypeCmp::Eq(te0), TypeCmp::Eq(te1), TypeCmp::Eq(te2), TypeCmp::Eq(te3)) => {
TypeCmp::Eq(te0.zip4(te1, te2, te3))
}
(TypeCmp::Ne(ne), _, _, _) => {
TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip4(ne, arg0, arg1, arg2))
}
(_, TypeCmp::Ne(ne), _, _) => {
TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip4(self, ne, arg1, arg2))
}
(_, _, TypeCmp::Ne(ne), _) => {
TypeCmp::Ne(SomeTypeArgIsNe::C(TypeEq::NEW).zip4(self, arg0, ne, arg2))
}
(_, _, _, TypeCmp::Ne(ne)) => {
TypeCmp::Ne(SomeTypeArgIsNe::D(TypeEq::NEW).zip4(self, arg0, arg1, ne))
}
}
}
}
include!{"./type_cmp/extra_type_cmp_methods.rs"}
impl<L: ?Sized, R: ?Sized> Copy for TypeCmp<L, R> {}
impl<L: ?Sized, R: ?Sized> Clone for TypeCmp<L, R> {
fn clone(&self) -> Self {
*self
}
}
impl<L: ?Sized, R: ?Sized> Debug for TypeCmp<L, R> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TypeCmp::Eq(x) => Debug::fmt(x, f),
TypeCmp::Ne(x) => Debug::fmt(x, f),
}
}
}
impl<L: ?Sized, R: ?Sized> PartialEq for TypeCmp<L, R> {
fn eq(&self, other: &Self) -> bool {
self.is_eq() == other.is_eq()
}
}
impl<L: ?Sized, R: ?Sized> PartialOrd for TypeCmp<L, R> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.is_eq().partial_cmp(&other.is_eq())
}
}
impl<L: ?Sized, R: ?Sized> Ord for TypeCmp<L, R> {
fn cmp(&self, other: &Self) -> Ordering {
self.is_eq().cmp(&other.is_eq())
}
}
impl<L: ?Sized, R: ?Sized> Eq for TypeCmp<L, R> {}
impl<L: ?Sized, R: ?Sized> Hash for TypeCmp<L, R> {
fn hash<H>(&self, state: &mut H)
where H: Hasher
{
match self {
TypeCmp::Eq(x) => Hash::hash(x, state),
TypeCmp::Ne(x) => Hash::hash(x, state),
}
}
}