use crate::cmp::{CmpWrapper, IsNotStdKind, IsStdKind};
use core::marker::PhantomData;
use typewit::TypeEq;
pub trait ConstCmp {
type Kind: ConstCmpKind;
type This: ?Sized + ConstCmp<Kind = Self::Kind, This = Self::This>;
}
impl<T, const N: usize> ConstCmp for [T; N] {
type Kind = IsStdKind;
type This = Self;
}
impl<T> ConstCmp for [T] {
type Kind = IsStdKind;
type This = Self;
}
impl ConstCmp for str {
type Kind = IsStdKind;
type This = Self;
}
impl<T> ConstCmp for &T
where
T: ?Sized + ConstCmp,
{
type Kind = T::Kind;
type This = T::This;
}
impl<T> ConstCmp for &mut T
where
T: ?Sized + ConstCmp,
{
type Kind = T::Kind;
type This = T::This;
}
#[allow(clippy::type_complexity)]
pub struct IsAConstCmp<K, T: ?Sized, R: ?Sized>(
PhantomData<(
PhantomData<fn() -> PhantomData<K>>,
PhantomData<fn() -> PhantomData<T>>,
PhantomData<fn() -> PhantomData<R>>,
)>,
);
impl<K, T: ?Sized, R: ?Sized> Copy for IsAConstCmp<K, T, R> {}
impl<K, T: ?Sized, R: ?Sized> Clone for IsAConstCmp<K, T, R> {
fn clone(&self) -> Self {
*self
}
}
impl<R> IsAConstCmp<R::Kind, R::This, R>
where
R: ?Sized + ConstCmp,
{
pub const NEW: Self = Self(PhantomData);
}
impl<K, T: ?Sized, R: ?Sized> IsAConstCmp<K, T, R> {
#[inline(always)]
pub const fn infer_type(self, _: &R) -> Self {
self
}
#[inline]
pub const fn coerce<'a>(self, reff: &'a T) -> CoerceTo<'a, T, K>
where
K: ConstCmpKind,
{
match const { <K as ConstCmpKind>::__KIND_WITNESS.to_coercion_witness::<'a, T>() } {
__CoercionWitness::IsStdKind(te) => te.to_left(CmpWrapper::from_ref(reff)),
__CoercionWitness::IsNotStdKind(te) => te.to_left(reff),
}
}
#[inline(always)]
pub const fn unreference(self, r: &T) -> &T {
r
}
}
pub trait ConstCmpKind: Sized {
type CoerceTo<T: ?Sized>: ?Sized;
#[doc(hidden)]
const __KIND_WITNESS: __ConstCmpKindWitness<Self>;
}
impl ConstCmpKind for IsStdKind {
type CoerceTo<T: ?Sized> = CmpWrapper<T>;
#[doc(hidden)]
const __KIND_WITNESS: __ConstCmpKindWitness<Self> =
__ConstCmpKindWitness::IsStdKind(TypeEq::NEW);
}
impl ConstCmpKind for IsNotStdKind {
type CoerceTo<T: ?Sized> = T;
#[doc(hidden)]
const __KIND_WITNESS: __ConstCmpKindWitness<Self> =
__ConstCmpKindWitness::IsNotStdKind(TypeEq::NEW);
}
pub type CoerceTo<'a, T, K = <T as ConstCmp>::Kind> = &'a <K as ConstCmpKind>::CoerceTo<T>;
#[doc(hidden)]
pub enum __ConstCmpKindWitness<Kind> {
IsStdKind(TypeEq<Kind, IsStdKind>),
IsNotStdKind(TypeEq<Kind, IsNotStdKind>),
}
impl<Kind> Copy for __ConstCmpKindWitness<Kind> {}
impl<Kind> Clone for __ConstCmpKindWitness<Kind> {
fn clone(&self) -> Self {
*self
}
}
impl<Kind> __ConstCmpKindWitness<Kind> {
const fn to_coercion_witness<'a, T>(self) -> __CoercionWitness<'a, T, Kind>
where
T: ?Sized,
Kind: ConstCmpKind,
{
typewit::type_fn! {
struct CoerceToFn<T: ?Sized>;
impl<K: ConstCmpKind> K => <K as ConstCmpKind>::CoerceTo<T>
}
match self {
Self::IsStdKind(te) => {
__CoercionWitness::IsStdKind(te.project::<CoerceToFn<T>>().in_ref())
}
Self::IsNotStdKind(te) => {
__CoercionWitness::IsNotStdKind(te.project::<CoerceToFn<T>>().in_ref())
}
}
}
}
#[doc(hidden)]
enum __CoercionWitness<'a, T: ?Sized, K: ConstCmpKind> {
IsStdKind(TypeEq<CoerceTo<'a, T, K>, &'a CmpWrapper<T>>),
IsNotStdKind(TypeEq<CoerceTo<'a, T, K>, &'a T>),
}
#[doc(hidden)]
pub struct __AssertConstCmp<'a, T: ConstCmp> {
pub reff: &'a T,
}
#[doc(hidden)]
#[macro_export]
macro_rules! __assert_const_cmp {
($reff:expr) => {
$crate::cmp::__AssertConstCmp { reff: $reff }
};
}