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