1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
use core::marker::PhantomData;

#[cfg(feature = "__for_konst")]
pub(crate) mod make_project_fn;

// documented in konst::polymorphism::type_eq;
pub trait HasTypeWitness<W: TypeWitnessTypeArg<Arg = Self>> {
    /// A constant of the type witness
    const WITNESS: W;

    #[doc(hidden)]
    const __PRIV_KO9Y329U2U: __Priv<Self, W>;
}

impl<T, W> HasTypeWitness<W> for T
where
    T: ?Sized,
    W: MakeTypeWitness<Arg = T>,
{
    const WITNESS: W = W::MAKE;

    #[doc(hidden)]
    const __PRIV_KO9Y329U2U: __Priv<Self, W> = __Priv(PhantomData, PhantomData);
}

#[doc(hidden)]
pub struct __Priv<T: ?Sized, W>(
    PhantomData<fn() -> PhantomData<W>>,
    PhantomData<fn() -> PhantomData<T>>,
);

pub trait TypeWitnessTypeArg {
    /// The type parameter used for type witnesses-
    ///
    /// Usually, enums that implement this trait have
    /// variants with `Type<Self::Arg, SomeType>` fields.
    type Arg: ?Sized;
}

pub trait MakeTypeWitness: TypeWitnessTypeArg {
    /// A constant with the type witness
    const MAKE: Self;
}

mod type_eq_ {
    use core::marker::PhantomData;

    pub struct TypeEq<L: ?Sized, R: ?Sized>(PhantomData<TypeEqHelper<L, R>>);

    // Declared to work around this error in old Rust versions:
    // > error[E0658]: function pointers cannot appear in constant functions
    struct TypeEqHelper<L: ?Sized, R: ?Sized>(
        fn(PhantomData<L>) -> PhantomData<L>,
        fn(PhantomData<R>) -> PhantomData<R>,
    );

    impl<L: ?Sized> TypeEq<L, L> {
        /// Constructs a `TypeEq<L, L>`.
        pub const NEW: Self = TypeEq(PhantomData);
    }

    impl TypeEq<(), ()> {
        /// Constructs a `TypeEq<T, T>`.
        #[inline(always)]
        pub const fn new<T: ?Sized>() -> TypeEq<T, T> {
            TypeEq::<T, T>::NEW
        }
    }

    impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
        /// Swaps the type parameters of this `TypeEq`
        #[inline(always)]
        pub const fn flip(self) -> TypeEq<R, L> {
            TypeEq(PhantomData)
        }

        /// Constructs a `TypeEq<L, R>`.
        ///
        /// # Safety
        ///
        /// You must ensure that `L` is the same type as `R`,
        /// layout equivalence is **not** enough.
        ///
        #[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, R> TypeEq<L, R> {
    /// Whether `L` is the same type as `R`.
    const ARE_SAME_TYPE: Amb = {
        // hacky way to emulate a lifetime-unaware
        // `TypeId::of<L>() == TypeId::of<R>()`
        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
        }
    };

    /// Hints to the compiler that a `TypeEq<L, R>`
    /// can only be constructed if `L == R`.
    ///
    /// This function takes and returns `val` unmodified.
    /// This allows returning some value from an expression
    /// while hinting that `L == R`.
    ///
    #[inline(always)]
    pub const fn reachability_hint<T>(self, val: T) -> T {
        if let Amb::No = Self::ARE_SAME_TYPE {
            // safety: it's impossible to have a `TypeEq<L, R>` value
            // where `L` and `R` are not the same type
            unsafe { core::hint::unreachable_unchecked() }
        }

        val
    }

    /// A no-op cast from `L` to `R`
    ///
    /// Having a `TypeEq<L, R>` value proves that `L` and `R` are the same type.
    #[inline(always)]
    pub const fn to_right(self, from: L) -> R {
        self.reachability_hint(());

        unsafe { crate::__priv_transmute!(L, R, from) }
    }
    /// A no-op cast from `R` to `L`
    ///
    /// Having a `TypeEq<L, R>` value proves that `L` and `R` are the same type.
    #[inline(always)]
    pub const fn to_left(self, from: R) -> L {
        self.reachability_hint(());

        unsafe { crate::__priv_transmute!(R, L, from) }
    }
}

#[cfg(feature = "__for_konst")]
impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
    crate::type_eq_projection_fn! {
        /// Converts a `TypeEq<L, R>` to `TypeEq<&L, &R>`
        pub const fn in_ref(T, self: TypeEq<L, R>) -> Ref<'a, T>
    }

    #[cfg(feature = "mut_refs")]
    crate::type_eq_projection_fn! {
        /// Converts a `TypeEq<L, R>` to `TypeEq<&mut L, &mut R>`
        #[cfg_attr(feature = "docsrs", doc(cfg(feature = "mut_refs")))]
        pub const fn in_mut(T, self: TypeEq<L, R>) -> RefMut<'a, T>
    }

    #[cfg(feature = "alloc")]
    crate::type_eq_projection_fn! {
        /// Converts a `TypeEq<L, R>` to `TypeEq<Box<L>, Box<R>>`
        #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
        pub const fn in_box(T, self: TypeEq<L, R>) -> ::alloc::boxed::Box<T>
    }
}
#[cfg(feature = "__for_konst")]
type Ref<'a, T> = &'a T;

#[cfg(feature = "mut_refs")]
type RefMut<'a, T> = &'a mut T;

enum Amb {
    // indefinitely false/true
    Indefinite,
    // definitely false
    No,
}