typewit/
type_cmp.rs

1use crate::{TypeEq, TypeNe};
2
3#[cfg(feature = "rust_1_61")]
4use crate::{BaseTypeWitness, MetaBaseTypeWit, SomeTypeArgIsNe};
5
6
7use core::{
8    any::Any,
9    cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd},
10    hash::{Hash, Hasher},
11    fmt::{self, Debug},
12};
13
14/// The result of comparing two types for equality.
15/// 
16/// # Example
17/// 
18/// ### Custom array creation
19/// 
20/// (this example requires Rust 1.63.0, because of [`core::array::from_fn`]).
21/// 
22#[cfg_attr(not(feature = "rust_1_65"), doc = "```ignore")]
23#[cfg_attr(feature = "rust_1_65", doc = "```rust")]
24/// use typewit::{const_marker::Usize, TypeCmp, TypeEq, TypeNe};
25/// 
26/// let empty: [String; 0] = [];
27/// assert_eq!(ArrayMaker::<String, 0>::empty().make(), empty);
28/// 
29/// assert_eq!(ArrayMaker::<u8, 2>::defaulted().make(), [0u8, 0u8]);
30/// 
31/// assert_eq!(ArrayMaker::with(|i| i.pow(2)).make(), [0usize, 1, 4, 9]);
32/// 
33/// 
34/// enum ArrayMaker<T, const LEN: usize> {
35///     NonEmpty(fn(usize) -> T, TypeNe<[T; LEN], [T; 0]>),
36///     Empty(TypeEq<[T; LEN], [T; 0]>),
37/// }
38/// 
39/// impl<T, const LEN: usize> ArrayMaker<T, LEN> {
40///     pub fn make(self) -> [T; LEN] {
41///         match self {
42///             ArrayMaker::NonEmpty(func, _) => std::array::from_fn(func),
43///             ArrayMaker::Empty(te) => te.to_left([]),
44///         }
45///     }
46/// 
47///     pub const fn defaulted() -> Self 
48///     where
49///         T: Default
50///     {
51///         Self::with(|_| Default::default())
52///     }
53/// 
54///     pub const fn with(func: fn(usize) -> T) -> Self {
55///         match  Usize::<LEN>.equals(Usize::<0>) // : TypeCmp<Usize<LEN>, Usize<0>>
56///             .project::<ArrayFn<T>>() // : TypeCmp<[T; LEN], [T; 0]>
57///         {
58///             TypeCmp::Ne(ne) => ArrayMaker::NonEmpty(func, ne),
59///             TypeCmp::Eq(eq) => ArrayMaker::Empty(eq),
60///         }
61///     }
62/// }
63/// 
64/// impl<T> ArrayMaker<T, 0> {
65///     pub const fn empty() -> Self {
66///         Self::Empty(TypeEq::NEW)
67///     }
68/// }
69/// 
70/// impl<T, const LEN: usize> Copy for ArrayMaker<T, LEN> {}
71/// 
72/// impl<T, const LEN: usize> Clone for ArrayMaker<T, LEN> {
73///     fn clone(&self) -> Self { *self }
74/// }
75/// 
76/// typewit::inj_type_fn! {
77///     // Declares `struct ArrayFn`, which implements `InjTypeFn<Usize<LEN>>`:
78///     // an injective type-level function from `Usize<LEN>` to `[T; LEN]`
79///     struct ArrayFn<T>;
80///     impl<const LEN: usize> Usize<LEN> => [T; LEN]
81/// }
82/// ```
83pub enum TypeCmp<L: ?Sized, R: ?Sized>{
84    /// proof of `L == R`
85    Eq(TypeEq<L, R>),
86    /// proof of `L != R`
87    Ne(TypeNe<L, R>),
88}
89
90impl<L: ?Sized, R: ?Sized> TypeCmp<L, R> {
91    /// Constructs a `TypeCmp<L, R>` by comparing the `L` and `R` types for equality.
92    /// 
93    /// # Example
94    /// 
95    /// ```rust
96    /// use typewit::TypeCmp;
97    /// 
98    /// let eq: TypeCmp<u8, u8> = TypeCmp::with_any();
99    /// assert!(matches!(eq, TypeCmp::Eq(_)));
100    /// 
101    /// let ne = TypeCmp::<u8, i8>::with_any();
102    /// assert!(matches!(ne, TypeCmp::Ne(_)));
103    /// ```
104    #[deprecated = concat!(
105        "fallout of `https://github.com/rust-lang/rust/issues/97156`,",
106        "`TypeId::of::<L>() != TypeId::of::<R>()` does not imply `L != R`"
107    )]
108    pub fn with_any() -> Self
109    where
110        L: Sized + Any,
111        R: Sized + Any,
112    {
113        #[allow(deprecated)]
114        if let Some(equal) = TypeEq::with_any() {
115            TypeCmp::Eq(equal)
116        } else if let Some(unequal) = TypeNe::with_any() {
117            TypeCmp::Ne(unequal)
118        } else {
119            unreachable!()
120        }
121    }
122
123    /// Swaps the type arguments of this `TypeCmp`
124    /// 
125    /// # Example
126    /// 
127    /// ```rust
128    /// use typewit::{TypeCmp, type_ne};
129    /// 
130    /// const TC: TypeCmp<u8, i8> = TypeCmp::Ne(type_ne!(u8, i8));
131    /// 
132    /// const TK: TypeCmp<i8, u8> = TC.flip();
133    /// 
134    /// ```
135    pub const fn flip(self) -> TypeCmp<R, L> {
136        match self {
137            TypeCmp::Eq(te) => TypeCmp::Eq(te.flip()),
138            TypeCmp::Ne(te) => TypeCmp::Ne(te.flip()),
139        }
140    }
141
142    /// Joins this `TypeCmp<L, R>` with a `TypeEq<Q, L>`, producing a `TypeCmp<Q, R>`.
143    /// 
144    /// # Example
145    /// 
146    /// ```rust
147    /// use typewit::{TypeCmp, TypeEq, type_ne};
148    /// 
149    /// const TC: TypeCmp<str, [u8]> = type_ne!(str, [u8]).to_cmp();
150    /// 
151    /// const fn foo<A: ?Sized>(eq: TypeEq<A, str>) {
152    ///     let _tc: TypeCmp<A, [u8]> = TC.join_left(eq);
153    /// }
154    /// ```
155    pub const fn join_left<Q: ?Sized>(self, left: TypeEq<Q, L>) -> TypeCmp<Q, R> {
156        match self {
157            TypeCmp::Eq(te) => TypeCmp::Eq(left.join(te)),
158            TypeCmp::Ne(te) => TypeCmp::Ne(te.join_left(left)),
159        }
160    }
161
162    /// Joins this `TypeCmp<L, R>` with a `TypeEq<R, Q>`, producing a `TypeCmp<L, Q>`.
163    /// 
164    /// # Example
165    /// 
166    /// ```rust
167    /// use typewit::{TypeCmp, TypeEq, type_ne};
168    /// 
169    /// const NE: TypeCmp<String, Vec<u8>> = type_ne!(String, Vec<u8>).to_cmp();
170    /// 
171    /// const fn foo<A>(eq: TypeEq<Vec<u8>, A>) {
172    ///     let _ne: TypeCmp<String, A> = NE.join_right(eq);
173    /// }
174    /// ```
175    pub const fn join_right<Q: ?Sized>(self, right: TypeEq<R, Q>) -> TypeCmp<L, Q> {
176        match self {
177            TypeCmp::Eq(te) => TypeCmp::Eq(te.join(right)),
178            TypeCmp::Ne(te) => TypeCmp::Ne(te.join_right(right)),
179        }
180    }
181
182    /// Converts this `TypeCmp<L, R>` into an `Option<TypeEq<L, R>>`.
183    /// 
184    /// # Example
185    /// 
186    /// ```rust
187    /// use typewit::{TypeCmp, TypeEq, type_ne};
188    /// 
189    /// let eq: TypeCmp<u8, u8> = TypeCmp::Eq(TypeEq::NEW);
190    /// assert!(matches!(eq.eq(), Some(TypeEq::<u8, u8>{..})));
191    /// 
192    /// let ne = TypeCmp::Ne(type_ne!(u8, i8));
193    /// assert!(matches!(ne.eq(), None::<TypeEq<u8, i8>>));
194    /// ```
195    pub const fn eq(self) -> Option<TypeEq<L, R>> {
196        match self {
197            TypeCmp::Eq(te) => Some(te),
198            TypeCmp::Ne(_) => None,
199        }
200    }
201
202    /// Converts this `TypeCmp<L, R>` into an `Option<TypeNe<L, R>>`.
203    /// 
204    /// # Example
205    /// 
206    /// ```rust
207    /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne};
208    /// 
209    /// let eq: TypeCmp<u8, u8> = TypeCmp::Eq(TypeEq::NEW);
210    /// assert!(matches!(eq.ne(), None::<TypeNe<u8, u8>>));
211    /// 
212    /// let ne = TypeCmp::Ne(type_ne!(u8, i8));
213    /// assert!(matches!(ne.ne(), Some(TypeNe::<u8, i8>{..})));
214    /// ```
215    pub const fn ne(self) -> Option<TypeNe<L, R>> {
216        match self {
217            TypeCmp::Eq(_) => None,
218            TypeCmp::Ne(te) => Some(te),
219        }
220    }
221
222    /// Returns whether this `TypeCmp` is a `TypeCmp::Eq`.
223    /// 
224    /// # Example
225    /// 
226    /// ```rust
227    /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne};
228    /// 
229    /// const EQ: TypeCmp<u8, u8> = TypeEq::NEW.to_cmp();
230    /// assert_eq!(EQ.is_eq(), true);
231    /// 
232    /// const NE: TypeCmp<i8, u8> = type_ne!(i8, u8).to_cmp();
233    /// assert_eq!(NE.is_eq(), false);
234    /// ```
235    pub const fn is_eq(self) -> bool {
236        matches!(self, TypeCmp::Eq(_))
237    }
238
239    /// Returns whether this `TypeCmp` is a `TypeCmp::Ne`.
240    /// 
241    /// # Example
242    /// 
243    /// ```rust
244    /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne};
245    /// 
246    /// const EQ: TypeCmp<u8, u8> = TypeEq::NEW.to_cmp();
247    /// assert_eq!(EQ.is_ne(), false);
248    /// 
249    /// const NE: TypeCmp<i8, u8> = type_ne!(i8, u8).to_cmp();
250    /// assert_eq!(NE.is_ne(), true);
251    /// ```
252    pub const fn is_ne(self) -> bool {
253        matches!(self, TypeCmp::Ne(_))
254    }
255
256    /// Returns the contained `TypeEq`
257    /// 
258    /// # Panic
259    /// 
260    /// Panics if the contained value is a `TypeNe`.
261    /// 
262    /// # Example
263    /// 
264    /// ```rust
265    /// use typewit::{TypeCmp, TypeEq};
266    /// 
267    /// let eq: TypeCmp<u8, u8> = TypeCmp::Eq(TypeEq::NEW);
268    /// assert!(matches!(eq.unwrap_eq(), TypeEq::<u8, u8>{..}));
269    /// ```
270    #[track_caller]
271    pub const fn unwrap_eq(self) -> TypeEq<L, R> {
272        match self {
273            TypeCmp::Eq(te) => te,
274            TypeCmp::Ne(_) => panic!("called `TypeCmp::unwrap_eq` on a `TypeNe` value"),
275        }
276    }
277
278    /// Returns the contained `TypeNe`
279    /// 
280    /// # Panic
281    /// 
282    /// Panics if the contained value is a `TypeEq`.
283    /// 
284    /// # Example
285    /// 
286    /// ```rust
287    /// use typewit::{TypeCmp, TypeNe, type_ne};
288    /// 
289    /// let ne = TypeCmp::Ne(type_ne!(u8, i8));
290    /// assert!(matches!(ne.unwrap_ne(), TypeNe::<u8, i8>{..}));
291    /// ```
292    #[track_caller]
293    pub const fn unwrap_ne(self) -> TypeNe<L, R> {
294        match self {
295            TypeCmp::Eq(_) => panic!("called `TypeCmp::unwrap_ne` on a `TypeEq` value"),
296            TypeCmp::Ne(te) => te,
297        }
298    }
299}
300
301#[cfg(feature = "rust_1_61")]
302macro_rules! alternative_docs {
303    ($func:expr) => {concat!(
304        "# Alternative\n",
305        "\n",
306        "[`methods::", $func,"`](crate::methods::", $func, ") \n",
307        "is an alternative to this function. \n",
308        "\n",
309        "This method always returns `TypeCmp`, \n",
310        "while [that function](crate::methods::", $func, ")\n",
311        "returns [`TypeNe`] when any argument is a `TypeNe`.\n",
312        "\n",
313        "# Returned variant\n",
314        "\n",
315        "This returns either [`TypeCmp::Eq`] or [`TypeCmp::Ne`]",
316        " depending on the arguments:\n",
317        "- if all arguments (including `self`)",
318        " are [`TypeEq`] or [`TypeCmp::Eq`], this returns [`TypeCmp::Eq`] \n",
319        "- if any argument (including `self`) ",
320        "is a [`TypeNe`] or [`TypeCmp::Ne`], this returns [`TypeCmp::Ne`] \n",
321    )};
322}
323
324#[cfg(feature = "rust_1_61")]
325#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))]
326impl<L, R> TypeCmp<L, R> {
327    /// Combines this `TypeCmp<L, R>` with a [`BaseTypeWitness`] type to produce a
328    /// `TypeCmp<(L, A::L), (R, A::R)>`.
329    /// 
330    #[doc = alternative_docs!("zip2")]
331    /// 
332    /// # Example
333    /// 
334    /// ```rust
335    /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne};
336    /// 
337    /// 
338    /// const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
339    /// const EQ: TypeEq<u16, u16> = TypeEq::NEW;
340    /// const TC_NE: TypeCmp<u32, u64> = TypeCmp::Ne(type_ne!(u32, u64));
341    /// const TC_EQ: TypeCmp<i64, i64> = TypeCmp::Eq(TypeEq::NEW);
342    /// 
343    /// assert!(matches!(
344    ///     TC_EQ.zip(NE),
345    ///     TypeCmp::<(i64, u8), (i64, i8)>::Ne(_),
346    /// ));
347    /// 
348    /// assert!(matches!(
349    ///     TC_EQ.zip(EQ),
350    ///     TypeCmp::<(i64, u16), (i64, u16)>::Eq(_),
351    /// ));
352    /// 
353    /// assert!(matches!(
354    ///     TC_EQ.zip(TC_EQ),
355    ///     TypeCmp::<(i64, i64), (i64, i64)>::Eq(_),
356    /// ));
357    /// 
358    /// assert!(matches!(
359    ///     TC_EQ.zip(TC_NE),
360    ///     TypeCmp::<(i64, u32), (i64, u64)>::Ne(_),
361    /// ));
362    /// ```
363    pub const fn zip<A>(self, other: A) -> TypeCmp<(L, A::L), (R, A::R)> 
364    where
365        A: BaseTypeWitness,
366    {
367        let other = MetaBaseTypeWit::to_cmp(A::WITNESS, other);
368
369        match (self, other) {
370            (TypeCmp::Eq(tel), TypeCmp::Eq(ter)) => {
371                TypeCmp::Eq(tel.zip(ter))
372            }
373            (TypeCmp::Ne(ne), _) => {
374                TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip2(ne, other))
375            }
376            (_, TypeCmp::Ne(ne)) => {
377                TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip2(self, ne))
378            }
379        }
380    }
381
382    /// Combines this `TypeCmp<L, R>` with two [`BaseTypeWitness`] types to produce a
383    /// `TypeCmp<(L, A::L, B::L), (R, A::R, B::R)>`.
384    /// 
385    #[doc = alternative_docs!("zip3")]
386    /// 
387    /// # Example
388    /// 
389    /// ```rust
390    /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne};
391    /// 
392    /// 
393    /// const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
394    /// const EQ: TypeEq<u16, u16> = TypeEq::NEW;
395    /// const TC_NE: TypeCmp<u32, u64> = TypeCmp::Ne(type_ne!(u32, u64));
396    /// const TC_EQ: TypeCmp<i64, i64> = TypeCmp::Eq(TypeEq::NEW);
397    /// 
398    /// assert!(matches!(
399    ///     TC_EQ.zip3(EQ, NE),
400    ///     TypeCmp::<(i64, u16, u8), (i64, u16, i8)>::Ne(_),
401    /// ));
402    /// 
403    /// assert!(matches!(
404    ///     TC_EQ.zip3(EQ, TC_EQ),
405    ///     TypeCmp::<(i64, u16, i64), (i64, u16, i64)>::Eq(_),
406    /// ));
407    /// 
408    /// assert!(matches!(
409    ///     TC_EQ.zip3(NE, TC_NE),
410    ///     TypeCmp::<(i64, u8, u32), (i64, i8, u64)>::Ne(_),
411    /// ));
412    /// ```
413    pub const fn zip3<A, B>(self, arg0: A, arg1: B) -> TypeCmp<(L, A::L, B::L), (R, A::R, B::R)> 
414    where
415        A: BaseTypeWitness,
416        A::L: Sized,
417        A::R: Sized,
418        B: BaseTypeWitness,
419    {
420        let arg0 = MetaBaseTypeWit::to_cmp(A::WITNESS, arg0);
421        let arg1 = MetaBaseTypeWit::to_cmp(B::WITNESS, arg1);
422
423        match (self, arg0, arg1) {
424            (TypeCmp::Eq(te0), TypeCmp::Eq(te1), TypeCmp::Eq(te2)) => {
425                TypeCmp::Eq(te0.zip3(te1, te2))
426            }
427            (TypeCmp::Ne(ne), _, _) => {
428                TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip3(ne, arg0, arg1))
429            }
430            (_, TypeCmp::Ne(ne), _) => {
431                TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip3(self, ne, arg1))
432            }
433            (_, _, TypeCmp::Ne(ne)) => {
434                TypeCmp::Ne(SomeTypeArgIsNe::C(TypeEq::NEW).zip3(self, arg0, ne))
435            }
436        }
437    }
438
439    /// Combines this `TypeCmp<L, R>` with three [`BaseTypeWitness`] types to produce a
440    /// `TypeCmp<(L, A::L, B::L, C::L), (R, A::R, B::R, C::R)>`.
441    ///
442    #[doc = alternative_docs!("zip4")]
443    ///
444    /// 
445    /// # Example
446    /// 
447    /// ```rust
448    /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne};
449    /// 
450    /// 
451    /// const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
452    /// const EQ: TypeEq<u16, u16> = TypeEq::NEW;
453    /// const TC_NE: TypeCmp<u32, u64> = TypeCmp::Ne(type_ne!(u32, u64));
454    /// const TC_EQ: TypeCmp<i64, i64> = TypeCmp::Eq(TypeEq::NEW);
455    /// 
456    /// assert!(matches!(
457    ///     TC_EQ.zip4(EQ, NE, TC_NE),
458    ///     TypeCmp::<(i64, u16, u8, u32), (i64, u16, i8, u64)>::Ne(_),
459    /// ));
460    /// 
461    /// assert!(matches!(
462    ///     TC_EQ.zip4(EQ, TC_EQ, EQ),
463    ///     TypeCmp::<(i64, u16, i64, u16), (i64, u16, i64, u16)>::Eq(_),
464    /// ));
465    /// ```
466    pub const fn zip4<A, B, C>(
467        self, 
468        arg0: A, 
469        arg1: B, 
470        arg2: C,
471    ) -> TypeCmp<(L, A::L, B::L, C::L), (R, A::R, B::R, C::R)> 
472    where
473        A: BaseTypeWitness,
474        A::L: Sized,
475        A::R: Sized,
476        B: BaseTypeWitness,
477        B::L: Sized,
478        B::R: Sized,
479        C: BaseTypeWitness,
480    {
481        let arg0 = MetaBaseTypeWit::to_cmp(A::WITNESS, arg0);
482        let arg1 = MetaBaseTypeWit::to_cmp(B::WITNESS, arg1);
483        let arg2 = MetaBaseTypeWit::to_cmp(C::WITNESS, arg2);
484
485        match (self, arg0, arg1, arg2) {
486            (TypeCmp::Eq(te0), TypeCmp::Eq(te1), TypeCmp::Eq(te2), TypeCmp::Eq(te3)) => {
487                TypeCmp::Eq(te0.zip4(te1, te2, te3))
488            }
489            (TypeCmp::Ne(ne), _, _, _) => {
490                TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip4(ne, arg0, arg1, arg2))
491            }
492            (_, TypeCmp::Ne(ne), _, _) => {
493                TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip4(self, ne, arg1, arg2))
494            }
495            (_, _, TypeCmp::Ne(ne), _) => {
496                TypeCmp::Ne(SomeTypeArgIsNe::C(TypeEq::NEW).zip4(self, arg0, ne, arg2))
497            }
498            (_, _, _, TypeCmp::Ne(ne)) => {
499                TypeCmp::Ne(SomeTypeArgIsNe::D(TypeEq::NEW).zip4(self, arg0, arg1, ne))
500            }
501        }
502    }
503}
504
505
506// using this instead of `mod extra_type_cmp_methods;`
507// to document the impls in the submodule below the constructors.
508include!{"./type_cmp/extra_type_cmp_methods.rs"}
509
510
511impl<L: ?Sized, R: ?Sized> Copy for TypeCmp<L, R> {}
512
513impl<L: ?Sized, R: ?Sized> Clone for TypeCmp<L, R> {
514    fn clone(&self) -> Self {
515        *self
516    }
517}
518
519impl<L: ?Sized, R: ?Sized> Debug for TypeCmp<L, R> {
520    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
521        match self {
522            TypeCmp::Eq(x) => Debug::fmt(x, f),
523            TypeCmp::Ne(x) => Debug::fmt(x, f),
524        }
525    }
526}
527
528impl<L: ?Sized, R: ?Sized> PartialEq for TypeCmp<L, R> {
529    fn eq(&self, other: &Self) -> bool {
530        self.is_eq() == other.is_eq()
531    }
532}
533
534impl<L: ?Sized, R: ?Sized> PartialOrd for TypeCmp<L, R> {
535    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
536        self.is_eq().partial_cmp(&other.is_eq())
537    }
538}
539
540impl<L: ?Sized, R: ?Sized> Ord for TypeCmp<L, R> {
541    fn cmp(&self, other: &Self) -> Ordering {
542        self.is_eq().cmp(&other.is_eq())
543    }
544}
545
546impl<L: ?Sized, R: ?Sized> Eq for TypeCmp<L, R> {}
547
548impl<L: ?Sized, R: ?Sized> Hash for TypeCmp<L, R> {
549    fn hash<H>(&self, state: &mut H)
550    where H: Hasher
551    {
552        match self {
553            TypeCmp::Eq(x) => Hash::hash(x, state),
554            TypeCmp::Ne(x) => Hash::hash(x, state),
555        }
556    }
557}
558
559
560
561
562
563
564
565