use crate::{
type_fn::{self, CallFn, InvokeAlias, RevTypeFn, TypeFn, UncallFn},
MakeTypeWitness, TypeWitnessTypeArg,
};
use crate::const_marker::Usize;
use core::{
cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd},
default::Default,
hash::{Hash, Hasher},
fmt::{self, Debug},
};
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
crate::type_eq_ne_guts::declare_helpers!{
$
TypeEq
TypeFn
CallFn
}
crate::type_eq_ne_guts::declare_zip_helper!{
$ TypeEq
}
macro_rules! zip_project {
(
$left_type_eq:expr,
$right_type_eq:expr,
$F: ty,
($L0:ty, $R0:ty),
($L1:ty, $R1:ty),
) => ({
__ZipProjectVars::<$F, $L0, $R0, $L1, $R1> {
left_te: $left_type_eq,
right_te: $right_type_eq,
projected_te: {
// SAFETY:
// `TypeEq<$L0, $R0>` and `TypeEq<$L1, $R1>`
// implies `TypeEq<($L0, $L1), ($R0, $R1)>`,
unsafe {
TypeEq::new_unchecked()
}
}
}.projected_te
});
}
struct __ZipProjectVars<F, L0, R0, L1, R1>
where
F: TypeFn<(L0, L1)> + TypeFn<(R0, R1)>
{
#[allow(dead_code)]
left_te: TypeEq<L0, R0>,
#[allow(dead_code)]
right_te: TypeEq<L1, R1>,
projected_te: TypeEq<CallFn<F, (L0, L1)>, CallFn<F, (R0, R1)>>,
}
#[inline(always)]
pub const fn type_eq<T: ?Sized>() -> TypeEq<T, T> {
TypeEq::NEW
}
mod type_eq_ {
use core::{
any::{Any, TypeId},
marker::PhantomData,
};
pub struct TypeEq<L: ?Sized, R: ?Sized>(PhantomData<TypeEqHelper<L, R>>);
struct TypeEqHelper<L: ?Sized, R: ?Sized>(
#[allow(dead_code)]
fn(PhantomData<L>) -> PhantomData<L>,
#[allow(dead_code)]
fn(PhantomData<R>) -> PhantomData<R>,
);
impl<T: ?Sized> TypeEq<T, T> {
pub const NEW: Self = TypeEq(PhantomData);
}
impl TypeEq<(), ()> {
#[inline(always)]
pub const fn new<T: ?Sized>() -> TypeEq<T, T> {
TypeEq::<T, T>::NEW
}
}
impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
pub fn with_any() -> Option<Self>
where
L: Sized + Any,
R: Sized + Any,
{
if TypeId::of::<L>() == TypeId::of::<R>() {
unsafe { Some(TypeEq::new_unchecked()) }
} else {
None
}
}
#[inline(always)]
pub const unsafe fn new_unchecked() -> TypeEq<L, R> {
TypeEq(PhantomData)
}
}
}
pub use type_eq_::TypeEq;
impl<L: ?Sized, R: ?Sized> Copy for TypeEq<L, R> {}
impl<L: ?Sized, R: ?Sized> Clone for TypeEq<L, R> {
fn clone(&self) -> Self {
*self
}
}
impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
#[inline(always)]
pub const fn to_cmp(self) -> crate::TypeCmp<L, R> {
crate::TypeCmp::Eq(self)
}
#[inline(always)]
pub const fn flip(self: TypeEq<L, R>) -> TypeEq<R, L> {
unsafe { TypeEq::new_unchecked() }
}
#[inline(always)]
pub const fn join<O: ?Sized>(self: TypeEq<L, R>, _other: TypeEq<R, O>) -> TypeEq<L, O> {
unsafe { TypeEq::new_unchecked() }
}
}
impl<L0, R0> TypeEq<L0, R0> {
#[inline(always)]
pub const fn zip<L1: ?Sized, R1: ?Sized>(
self: TypeEq<L0, R0>,
other: TypeEq<L1, R1>,
) -> TypeEq<(L0, L1), (R0, R1)> {
zip_impl!{self[L0, R0], other[L1, R1]}
}
pub const fn zip3<L1, R1, L2: ?Sized, R2: ?Sized>(
self: TypeEq<L0, R0>,
other1: TypeEq<L1, R1>,
other2: TypeEq<L2, R2>,
) -> TypeEq<(L0, L1, L2), (R0, R1, R2)> {
zip_impl!{
self[L0, R0],
other1[L1, R1],
other2[L2, R2],
}
}
pub const fn zip4<L1, R1, L2, R2, L3: ?Sized, R3: ?Sized>(
self: TypeEq<L0, R0>,
other1: TypeEq<L1, R1>,
other2: TypeEq<L2, R2>,
other3: TypeEq<L3, R3>,
) -> TypeEq<(L0, L1, L2, L3), (R0, R1, R2, R3)> {
zip_impl!{
self[L0, R0],
other1[L1, R1],
other2[L2, R2],
other3[L3, R3],
}
}
}
impl<L, R> TypeEq<L, R> {
const ARE_SAME_TYPE: Amb = {
let approx_same_type = {
core::mem::size_of::<L>() == core::mem::size_of::<R>()
&& core::mem::align_of::<L>() == core::mem::align_of::<R>()
&& core::mem::size_of::<Option<L>>() == core::mem::size_of::<Option<R>>()
&& core::mem::align_of::<Option<L>>() == core::mem::align_of::<Option<R>>()
};
if approx_same_type {
Amb::Indefinite
} else {
Amb::No
}
};
#[inline(always)]
pub const fn reachability_hint<T>(self, val: T) -> T {
if let Amb::No = Self::ARE_SAME_TYPE {
unsafe { core::hint::unreachable_unchecked() }
}
val
}
#[inline(always)]
pub const fn to_right(self, from: L) -> R {
self.reachability_hint(());
unsafe { crate::__priv_transmute!(L, R, from) }
}
#[inline(always)]
pub const fn to_left(self, from: R) -> L {
self.reachability_hint(());
unsafe { crate::__priv_transmute!(R, L, from) }
}
}
impl<L: ?Sized, R: ?Sized> TypeWitnessTypeArg for TypeEq<L, R> {
type Arg = L;
}
impl<T: ?Sized> MakeTypeWitness for TypeEq<T, T> {
const MAKE: Self = Self::NEW;
}
impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
pub const fn map<F>(
self,
func: F,
) -> TypeEq<CallFn<InvokeAlias<F>, L>, CallFn<InvokeAlias<F>, R>>
where
InvokeAlias<F>: crate::TypeFn<L> + crate::TypeFn<R>
{
core::mem::forget(func);
projected_type_cmp!{self, L, R, F}
}
pub const fn project<F>(self) -> TypeEq<CallFn<InvokeAlias<F>, L>, CallFn<InvokeAlias<F>, R>>
where
InvokeAlias<F>: crate::TypeFn<L> + crate::TypeFn<R>
{
projected_type_cmp!{self, L, R, F}
}
}
impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
pub const fn unmap<F>(
self,
func: F,
) -> TypeEq<UncallFn<InvokeAlias<F>, L>, UncallFn<InvokeAlias<F>, R>>
where
InvokeAlias<F>: RevTypeFn<L> + RevTypeFn<R>
{
core::mem::forget(func);
unprojected_type_cmp!{self, L, R, F}
}
pub const fn unproject<F>(
self,
) -> TypeEq<UncallFn<InvokeAlias<F>, L>, UncallFn<InvokeAlias<F>, R>>
where
InvokeAlias<F>: crate::RevTypeFn<L> + crate::RevTypeFn<R>
{
unprojected_type_cmp!{self, L, R, F}
}
}
impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
pub const fn in_ref<'a>(self) -> TypeEq<&'a L, &'a R> {
projected_type_cmp!{self, L, R, type_fn::GRef<'a>}
}
crate::utils::conditionally_const!{
feature = "rust_1_83";
#[cfg_attr(not(feature = "rust_1_83"), doc = "```ignore")]
#[cfg_attr(feature = "rust_1_83", doc = "```rust")]
pub fn in_mut['a](self) -> TypeEq<&'a mut L, &'a mut R> {
projected_type_cmp!{self, L, R, type_fn::GRefMut<'a>}
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
pub const fn in_box(self) -> TypeEq<Box<L>, Box<R>> {
projected_type_cmp!{self, L, R, type_fn::GBox}
}
}
impl<L: Sized, R: Sized> TypeEq<L, R> {
#[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")]
#[cfg_attr(feature = "rust_1_61", doc = "```rust")]
#[inline(always)]
pub const fn in_array<const UL: usize, const UR: usize>(
self,
other: TypeEq<Usize<UL>, Usize<UR>>,
) -> TypeEq<[L; UL], [R; UR]> {
zip_project!{
self,
other,
crate::type_fn::PairToArrayFn,
(L, R),
(Usize<UL>, Usize<UR>),
}
}
}
enum Amb {
Indefinite,
No,
}
impl<T: ?Sized> Default for TypeEq<T, T> {
fn default() -> Self {
Self::NEW
}
}
impl<L: ?Sized, R: ?Sized> Debug for TypeEq<L, R> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("TypeEq")
}
}
impl<L: ?Sized, R: ?Sized> PartialEq for TypeEq<L, R> {
fn eq(&self, _: &Self) -> bool {
true
}
}
impl<L: ?Sized, R: ?Sized> PartialOrd for TypeEq<L, R> {
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
Some(Ordering::Equal)
}
}
impl<L: ?Sized, R: ?Sized> Ord for TypeEq<L, R> {
fn cmp(&self, _: &Self) -> Ordering {
Ordering::Equal
}
}
impl<L: ?Sized, R: ?Sized> Eq for TypeEq<L, R> {}
impl<L: ?Sized, R: ?Sized> Hash for TypeEq<L, R> {
fn hash<H>(&self, _state: &mut H)
where H: Hasher
{}
}