typewit/type_eq.rs
1use crate::{
2 type_fn::{self, CallFn, InvokeAlias, RevTypeFn, TypeFn, UncallFn},
3 MakeTypeWitness, TypeWitnessTypeArg,
4};
5
6use crate::const_marker::Usize;
7
8
9
10use core::{
11 cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd},
12 default::Default,
13 hash::{Hash, Hasher},
14 fmt::{self, Debug},
15};
16
17#[cfg(feature = "alloc")]
18use alloc::boxed::Box;
19
20crate::type_eq_ne_guts::declare_helpers!{
21 $
22 TypeEq
23 TypeFn
24 CallFn
25}
26
27crate::type_eq_ne_guts::declare_zip_helper!{
28 $ TypeEq
29}
30
31// Equivalent to `type_eq.zip(other_type_eq).project::<Func>()`,
32// defined to ensure that methods which do zip+project have 0 overhead in debug builds.
33macro_rules! zip_project {
34 // Since `$L0`, `$L1`,`$R0`, and `$R1` are all used only once,
35 // it's safe to declare them as `:ty` (safe against malicious type macros).
36 (
37 $left_type_eq:expr,
38 $right_type_eq:expr,
39 $F: ty,
40 ($L0:ty, $R0:ty),
41 ($L1:ty, $R1:ty),
42 ) => ({
43 __ZipProjectVars::<$F, $L0, $R0, $L1, $R1> {
44 left_te: $left_type_eq,
45 right_te: $right_type_eq,
46 projected_te: {
47 // SAFETY:
48 // `TypeEq<$L0, $R0>` and `TypeEq<$L1, $R1>`
49 // implies `TypeEq<($L0, $L1), ($R0, $R1)>`,
50 //
51 // Using `$F` only once, as a type argument,
52 // to protect against type-position macros that expand to
53 // different types on each use.
54 unsafe {
55 TypeEq::new_unchecked()
56 }
57 }
58 }.projected_te
59 });
60}
61
62struct __ZipProjectVars<F, L0, R0, L1, R1>
63where
64 F: TypeFn<(L0, L1)> + TypeFn<(R0, R1)>
65{
66 #[allow(dead_code)]
67 left_te: TypeEq<L0, R0>,
68
69 #[allow(dead_code)]
70 right_te: TypeEq<L1, R1>,
71
72 // (TypeEq<L0, R0>, TypeEq<L1, R1>)
73 // implies TypeEq<(L0, L1), (R0, R1)>
74 // implies TypeEq<CallFn<F, (L0, L1)>, CallFn<F, (R0, R1)>>
75 projected_te: TypeEq<CallFn<F, (L0, L1)>, CallFn<F, (R0, R1)>>,
76}
77
78
79/// Constructs a [`TypeEq<T, T>`](TypeEq)
80///
81/// # Example
82///
83/// ```rust
84/// use typewit::{MakeTypeWitness, TypeWitnessTypeArg, TypeEq, type_eq};
85///
86/// assert_eq!(ascii_to_upper(b'a'), b'A');
87/// assert_eq!(ascii_to_upper(b'f'), b'F');
88/// assert_eq!(ascii_to_upper(b'B'), b'B');
89/// assert_eq!(ascii_to_upper(b'0'), b'0');
90///
91/// assert_eq!(ascii_to_upper('c'), 'C');
92/// assert_eq!(ascii_to_upper('e'), 'E');
93/// assert_eq!(ascii_to_upper('H'), 'H');
94/// assert_eq!(ascii_to_upper('@'), '@');
95///
96/// const fn ascii_to_upper<T>(c: T) -> T
97/// where
98/// Wit<T>: MakeTypeWitness,
99/// {
100/// match MakeTypeWitness::MAKE {
101/// Wit::U8(te) => {
102/// // `te` is a `TypeEq<T, u8>`, which allows casting between `T` and `u8`.
103/// // `te.to_right(...)` goes from `T` to `u8`
104/// // `te.to_left(...)` goes from `u8` to `T`
105/// te.to_left(te.to_right(c).to_ascii_uppercase())
106/// }
107/// Wit::Char(te) => {
108/// // `te` is a `TypeEq<T, char>`, which allows casting between `T` and `char`.
109/// // `te.to_right(...)` goes from `T` to `char`
110/// // `te.to_left(...)` goes from `char` to `T`
111/// te.to_left(te.to_right(c).to_ascii_uppercase())
112/// }
113/// }
114/// }
115///
116/// // This is a type witness
117/// enum Wit<T> {
118/// // this variant requires `T == u8`
119/// U8(TypeEq<T, u8>),
120///
121/// // this variant requires `T == char`
122/// Char(TypeEq<T, char>),
123/// }
124/// impl<T> TypeWitnessTypeArg for Wit<T> {
125/// type Arg = T;
126/// }
127/// impl MakeTypeWitness for Wit<u8> {
128/// const MAKE: Self = Self::U8(type_eq());
129/// }
130/// impl MakeTypeWitness for Wit<char> {
131/// const MAKE: Self = Self::Char(type_eq());
132/// }
133/// ```
134/// The code above can be written more concisly using
135/// the [`polymatch`](crate::polymatch) and [`simple_type_witness`] macros:
136/// ```rust
137/// # use typewit::{MakeTypeWitness, TypeWitnessTypeArg, TypeEq, type_eq};
138/// #
139/// # assert_eq!(ascii_to_upper(b'a'), b'A');
140/// # assert_eq!(ascii_to_upper(b'f'), b'F');
141/// # assert_eq!(ascii_to_upper(b'B'), b'B');
142/// # assert_eq!(ascii_to_upper(b'0'), b'0');
143/// #
144/// # assert_eq!(ascii_to_upper('c'), 'C');
145/// # assert_eq!(ascii_to_upper('e'), 'E');
146/// # assert_eq!(ascii_to_upper('H'), 'H');
147/// # assert_eq!(ascii_to_upper('@'), '@');
148/// #
149/// const fn ascii_to_upper<T>(c: T) -> T
150/// where
151/// Wit<T>: MakeTypeWitness,
152/// {
153/// // deduplicating identical match arms using the `polymatch` macro.
154/// typewit::polymatch!{MakeTypeWitness::MAKE;
155/// Wit::U8(te) | Wit::Char(te) => te.to_left(te.to_right(c).to_ascii_uppercase())
156/// }
157/// }
158///
159/// // This macro declares a type witness
160/// typewit::simple_type_witness! {
161/// // Declares `enum Wit<__Wit>`
162/// // The `__Wit` type parameter is implicit and always the last generic parameter.
163/// enum Wit {
164/// // this variant requires `__Wit == u8`
165/// U8 = u8,
166/// // this variant requires `__Wit == char`
167/// Char = char,
168/// }
169/// }
170/// ```
171/// note that [`simple_type_witness`] can't replace enums whose
172/// witnessed type parameter is not the last,
173/// or have variants with anything but one `TypeEq` field each.
174///
175/// [`simple_type_witness`]: crate::simple_type_witness
176#[inline(always)]
177pub const fn type_eq<T: ?Sized>() -> TypeEq<T, T> {
178 TypeEq::NEW
179}
180
181
182// Declaring `TypeEq` in a submodule to prevent "safely" constructing `TypeEq` with
183// two different type arguments in the `crate::type_eq` module.
184mod type_eq_ {
185 use core::{
186 any::{Any, TypeId},
187 marker::PhantomData,
188 };
189
190 /// Value-level proof that `L` is the same type as `R`
191 ///
192 /// This type can be used to prove that `L` and `R` are the same type,
193 /// because it can only be safely constructed with
194 /// [`TypeEq::<L, L>::NEW`](#associatedconstant.NEW)(or [`new`](#method.new)),
195 /// where both type arguments are the same type.
196 ///
197 /// This type is not too useful by itself, it becomes useful
198 /// [when put inside of an enum](#polymorphic-branching).
199 ///
200 ///
201 /// `TypeEq<L, R>` uses the `L` type parameter as the more generic type by convention
202 /// (e.g: `TypeEq<T, char>`).
203 /// This only matters if you're using the type witness traits
204 /// ([`HasTypeWitness`](crate::HasTypeWitness),
205 /// [`MakeTypeWitness`](crate::MakeTypeWitness),
206 /// [`TypeWitnessTypeArg`](crate::TypeWitnessTypeArg)) with `TypeEq`.
207 ///
208 /// # Soundness
209 ///
210 /// `TypeEq<L, R>` requires both type arguments to be the same type so that
211 /// [projecting](Self::project) the type arguments results in the same type for
212 /// both arguments.
213 ///
214 /// Unsafely creating a `TypeEq<L, R>` where `L != R` allows
215 /// [transmuting between any two types](#arbitrary-transmute)
216 /// (that is bad).
217 ///
218 /// # Examples
219 ///
220 /// ### Polymorphic branching
221 ///
222 /// This example demonstrates how type witnesses can be used to
223 /// choose between expressions of different types with a constant.
224 ///
225 /// ```rust
226 /// use typewit::TypeEq;
227 ///
228 /// const fn main() {
229 /// assert!(matches!(choose!(0; b"a string", 2, panic!()), b"a string"));
230 ///
231 /// const UNO: u64 = 1;
232 /// assert!(matches!(choose!(UNO; loop{}, [3, 5], true), [3, 5]));
233 ///
234 /// assert!(matches!(choose!(2 + 3; (), unreachable!(), ['5', '3']), ['5', '3']));
235 /// }
236 ///
237 /// /// Evaluates the argument at position `$chosen % 3`, other arguments aren't evaluated.
238 /// ///
239 /// /// The arguments can all be different types.
240 /// ///
241 /// /// `$chosen` must be a `u64` constant.
242 /// #[macro_export]
243 /// macro_rules! choose {
244 /// ($chosen:expr; $arg_0: expr, $arg_1: expr, $arg_2: expr) => {
245 /// match Choice::<{$chosen % 3}>::VAL {
246 /// // `te` (a `TypeEq<T, X>`) allows us to safely go between
247 /// // the type that the match returns (its `T` type argument)
248 /// // and the type of `$arg_0` (its `X` type argument).
249 /// Branch3::A(te) => {
250 /// // `to_left` goes from `X` to `T`
251 /// te.to_left($arg_0)
252 /// }
253 /// // same as the `A` branch, with a different type for the argument
254 /// Branch3::B(te) => te.to_left($arg_1),
255 /// // same as the `A` branch, with a different type for the argument
256 /// Branch3::C(te) => te.to_left($arg_2),
257 /// }
258 /// }
259 /// }
260 ///
261 /// // This is a type witness
262 /// pub enum Branch3<T, X, Y, Z> {
263 /// // This variant requires `T == X`
264 /// A(TypeEq<T, X>),
265 ///
266 /// // This variant requires `T == Y`
267 /// B(TypeEq<T, Y>),
268 ///
269 /// // This variant requires `T == Z`
270 /// C(TypeEq<T, Z>),
271 /// }
272 ///
273 /// // Used to get different values of `Branch3` depending on `N`
274 /// pub trait Choice<const N: u64> {
275 /// const VAL: Self;
276 /// }
277 ///
278 /// impl<X, Y, Z> Choice<0> for Branch3<X, X, Y, Z> {
279 /// // Because the first two type arguments of `Branch3` are `X`
280 /// // (as required by the `TypeEq<T, X>` field in Branch3's type definition),
281 /// // we can use `TypeEq::NEW` here.
282 /// const VAL: Self = Self::A(TypeEq::NEW);
283 /// }
284 ///
285 /// impl<X, Y, Z> Choice<1> for Branch3<Y, X, Y, Z> {
286 /// const VAL: Self = Self::B(TypeEq::NEW);
287 /// }
288 ///
289 /// impl<X, Y, Z> Choice<2> for Branch3<Z, X, Y, Z> {
290 /// const VAL: Self = Self::C(TypeEq::NEW);
291 /// }
292 ///
293 /// ```
294 ///
295 pub struct TypeEq<L: ?Sized, R: ?Sized>(PhantomData<TypeEqHelper<L, R>>);
296
297 // Declared to work around this error in old Rust versions:
298 // > error[E0658]: function pointers cannot appear in constant functions
299 struct TypeEqHelper<L: ?Sized, R: ?Sized>(
300 #[allow(dead_code)]
301 fn(PhantomData<L>) -> PhantomData<L>,
302 #[allow(dead_code)]
303 fn(PhantomData<R>) -> PhantomData<R>,
304 );
305
306
307 impl<T: ?Sized> TypeEq<T, T> {
308 /// Constructs a `TypeEq<T, T>`.
309 ///
310 /// # Example
311 ///
312 /// ```rust
313 /// use typewit::TypeEq;
314 ///
315 /// assert_eq!(mutate(5, Wit::U32(TypeEq::NEW)), 25);
316 ///
317 /// assert_eq!(mutate(5, Wit::Other(TypeEq::NEW)), 5);
318 /// assert_eq!(mutate("hello", Wit::Other(TypeEq::NEW)), "hello");
319 ///
320 /// const fn mutate<W>(val: W, wit: Wit<W>) -> W {
321 /// match wit {
322 /// Wit::U32(te) => te.to_left(te.to_right(val) + 20),
323 /// Wit::Other(_) => val,
324 /// }
325 /// }
326 ///
327 /// // This can't be written using the `simple_type_witness` macro because the
328 /// // type in the `Other` variant overlaps with the other ones.
329 /// enum Wit<W> {
330 /// U32(TypeEq<W, u32>),
331 /// Other(TypeEq<W, W>),
332 /// }
333 /// ```
334 ///
335 pub const NEW: Self = TypeEq(PhantomData);
336 }
337
338 impl TypeEq<(), ()> {
339 /// Constructs a `TypeEq<T, T>`.
340 #[inline(always)]
341 pub const fn new<T: ?Sized>() -> TypeEq<T, T> {
342 TypeEq::<T, T>::NEW
343 }
344 }
345
346 impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
347 /// Constructs `TypeEq<L, R>` if `L == R`, otherwise returns None.
348 ///
349 /// # Example
350 ///
351 /// ```rust
352 /// use typewit::TypeEq;
353 ///
354 /// use std::any::Any;
355 ///
356 /// assert_eq!(sum_u32s(&[3u32, 5, 8]), Some(16));
357 /// assert_eq!(sum_u32s(&[3i32, 5, 8]), None);
358 ///
359 ///
360 /// fn sum_u32s<T: Clone + Any>(foo: &[T]) -> Option<u32> {
361 /// typecast_slice::<T, u32>(foo)
362 /// .map(|foo: &[u32]| foo.iter().copied().sum())
363 /// }
364 ///
365 /// fn typecast_slice<T: Any, U: Any>(foo: &[T]) -> Option<&[U]> {
366 /// struct SliceFn;
367 /// impl<T> typewit::TypeFn<T> for SliceFn {
368 /// type Output = [T];
369 /// }
370 ///
371 /// TypeEq::<T, U>::with_any().map(|te: TypeEq<T, U>|{
372 /// te.map(SliceFn) // TypeEq<[T], [U]>
373 /// .in_ref() // TypeEq<&[T]>, &[U]>
374 /// .to_right(foo) // identity cast from `&[T]` to `&[U]`
375 /// })
376 /// }
377 /// ```
378 pub fn with_any() -> Option<Self>
379 where
380 L: Sized + Any,
381 R: Sized + Any,
382 {
383 if TypeId::of::<L>() == TypeId::of::<R>() {
384 // SAFETY: the two TypeIds compare equal, so L == R
385 unsafe { Some(TypeEq::new_unchecked()) }
386 } else {
387 None
388 }
389 }
390
391 /// Constructs a `TypeEq<L, R>`.
392 ///
393 /// # Safety
394 ///
395 /// You must ensure that `L` is the same type as `R`.
396 ///
397 /// # Examples
398 ///
399 /// ### Unsound usage
400 /// <span id="arbitrary-transmute"></span>
401 ///
402 /// This example demonstrates why `L == R` is a strict requirement.
403 ///
404 /// ```rust
405 /// use typewit::{TypeEq, TypeFn};
406 ///
407 /// // SAFETY: WRONG! UNSOUND!
408 /// let te: TypeEq<u8, i8> = unsafe{ TypeEq::new_unchecked() };
409 ///
410 /// // Because `TypeEq<u8, i8>` is incorrect,
411 /// // we get this absurd `TypeEq` from the `project` method.
412 /// let absurd: TypeEq<(), Vec<usize>> = te.project::<Func>();
413 ///
414 /// // This casts from `()` to `Vec<usize>` (which is UB).
415 /// // Last time I tried uncommenting this, it killed the test runner.
416 /// // absurd.to_right(());
417 ///
418 /// struct Func;
419 /// impl TypeFn<u8> for Func { type Output = (); }
420 /// impl TypeFn<i8> for Func { type Output = Vec<usize>; }
421 ///
422 ///
423 /// ```
424 ///
425 #[inline(always)]
426 pub const unsafe fn new_unchecked() -> TypeEq<L, R> {
427 TypeEq(PhantomData)
428 }
429 }
430}
431pub use type_eq_::TypeEq;
432
433impl<L: ?Sized, R: ?Sized> Copy for TypeEq<L, R> {}
434
435impl<L: ?Sized, R: ?Sized> Clone for TypeEq<L, R> {
436 fn clone(&self) -> Self {
437 *self
438 }
439}
440
441impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
442 /// Converts this `TypeEq` into a [`TypeCmp`](crate::TypeCmp)
443 ///
444 /// # Example
445 ///
446 /// ```rust
447 /// use typewit::{TypeCmp, TypeEq};
448 ///
449 /// const TC: TypeCmp<bool, bool> = TypeEq::NEW.to_cmp();
450 ///
451 /// assert!(matches!(TC, TypeCmp::Eq(_)));
452 /// ```
453 #[inline(always)]
454 pub const fn to_cmp(self) -> crate::TypeCmp<L, R> {
455 crate::TypeCmp::Eq(self)
456 }
457
458 /// Swaps the type parameters of this `TypeEq`
459 ///
460 /// # Example
461 ///
462 /// ```rust
463 /// use typewit::TypeEq;
464 ///
465 /// assert_eq!(flip_bytes([3, 5], TypeEq::NEW), [5, 3]);
466 ///
467 /// const fn flip_bytes<T>(val: T, te: TypeEq<T, [u8; 2]>) -> T {
468 /// bar(val, te.flip())
469 /// }
470 /// const fn bar<T>(val: T, te: TypeEq<[u8; 2], T>) -> T {
471 /// let [l, r] = te.to_left(val);
472 /// te.to_right([r, l])
473 /// }
474 /// ```
475 ///
476 #[inline(always)]
477 pub const fn flip(self: TypeEq<L, R>) -> TypeEq<R, L> {
478 // SAFETY: L == R implies R == L
479 unsafe { TypeEq::new_unchecked() }
480 }
481
482 /// Joins this `TypeEq<L, R>` with a `TypeEq<R, O>`, producing a `TypeEq<L, O>`.
483 ///
484 /// The returned `TypeEq` can then be used to coerce between `L` and `O`.
485 ///
486 /// # Example
487 ///
488 /// ```rust
489 /// use typewit::TypeEq;
490 ///
491 /// assert_eq!(foo(TypeEq::NEW, TypeEq::NEW, Some(3)), Some(3));
492 /// assert_eq!(foo(TypeEq::NEW, TypeEq::NEW, None), None);
493 ///
494 ///
495 /// fn foo<L, X>(
496 /// this: TypeEq<L, Option<X>>,
497 /// that: TypeEq<Option<X>, Option<u32>>,
498 /// value: Option<u32>,
499 /// ) -> L {
500 /// let te: TypeEq<L, Option<u32>> = this.join(that);
501 /// te.to_left(value)
502 /// }
503 ///
504 /// ```
505 ///
506 #[inline(always)]
507 pub const fn join<O: ?Sized>(self: TypeEq<L, R>, _other: TypeEq<R, O>) -> TypeEq<L, O> {
508 // SAFETY: (L == R, R == O) implies L == O
509 unsafe { TypeEq::new_unchecked() }
510 }
511}
512
513impl<L0, R0> TypeEq<L0, R0> {
514 /// Combines this `TypeEq<L0, R0>` with a `TypeEq<L1, R1>`,
515 /// producing a `TypeEq<(L0, L1), (R0, R1)>`.
516 ///
517 /// # Alternative
518 ///
519 /// For an alternative which allows zipping `TypeEq` with any
520 /// [`BaseTypeWitness`](crate::BaseTypeWitness),
521 /// you can use [`methods::zip2`](crate::methods::zip2)
522 /// (requires the `"rust_1_65"` feature)
523 ///
524 /// # Example
525 ///
526 /// This example demonstrates how one can combine two `TypeEq`s to use
527 /// with a multi-parameter type.
528 ///
529 /// ```rust
530 /// use typewit::{const_marker::Usize, TypeEq, TypeFn};
531 ///
532 /// assert_eq!(make_foo(TypeEq::NEW, TypeEq::NEW), Foo("hello", [3, 5, 8]));
533 ///
534 /// const fn make_foo<T, const N: usize>(
535 /// te_ty: TypeEq<T, &'static str>,
536 /// te_len: TypeEq<Usize<N>, Usize<3>>,
537 /// ) -> Foo<T, N> {
538 /// // the type annotations are just for the reader, they can be inferred.
539 /// let te_pair: TypeEq<(T, Usize<N>), (&str, Usize<3>)> = te_ty.zip(te_len);
540 ///
541 /// let te: TypeEq<Foo<T, N>, Foo<&str, 3>> = te_pair.project::<GFoo>();
542 ///
543 /// // `te.to_left(...)` here goes from `Foo<&str, 3>` to `Foo<T, N>`
544 /// te.to_left(Foo("hello", [3, 5, 8]))
545 /// }
546 ///
547 /// #[derive(Debug, PartialEq)]
548 /// struct Foo<T, const N: usize>(T, [u8; N]);
549 ///
550 /// typewit::type_fn!{
551 /// // Type-level function from `(T, Usize<N>)` to `Foo<T, N>`
552 /// struct GFoo;
553 ///
554 /// impl<T, const N: usize> (T, Usize<N>) => Foo<T, N>
555 /// }
556 /// ```
557 ///
558 #[inline(always)]
559 pub const fn zip<L1: ?Sized, R1: ?Sized>(
560 self: TypeEq<L0, R0>,
561 other: TypeEq<L1, R1>,
562 ) -> TypeEq<(L0, L1), (R0, R1)> {
563 zip_impl!{self[L0, R0], other[L1, R1]}
564 }
565
566 /// Combines three `TypeEq<L*, R*>` to produce a
567 /// `TypeEq<(L0, L1, L2), (R0, R1, R2)>`.
568 ///
569 /// # Alternative
570 ///
571 /// For an alternative which allows zipping `TypeEq` with two of any
572 /// [`BaseTypeWitness`](crate::BaseTypeWitness),
573 /// you can use [`methods::zip3`](crate::methods::zip3)
574 /// (requires the `"rust_1_65"` feature)
575 ///
576 /// # Example
577 ///
578 /// ```rust
579 /// use typewit::{TypeEq, type_eq};
580 ///
581 /// use std::cmp::Ordering::{self, Less};
582 ///
583 /// assert_eq!(make_tuple(type_eq(), type_eq(), type_eq()), (3, "foo", Less));
584 ///
585 /// fn make_tuple<A, B, C>(
586 /// te0: TypeEq<A, u8>,
587 /// te1: TypeEq<B, &str>,
588 /// te2: TypeEq<C, Ordering>,
589 /// ) -> (A, B, C) {
590 /// te0.zip3(te1, te2) // returns `TypeEq<(A, B, C), (u8, &str, Ordering)>`
591 /// .to_left((3, "foo", Less))
592 /// }
593 ///
594 /// ```
595 pub const fn zip3<L1, R1, L2: ?Sized, R2: ?Sized>(
596 self: TypeEq<L0, R0>,
597 other1: TypeEq<L1, R1>,
598 other2: TypeEq<L2, R2>,
599 ) -> TypeEq<(L0, L1, L2), (R0, R1, R2)> {
600 zip_impl!{
601 self[L0, R0],
602 other1[L1, R1],
603 other2[L2, R2],
604 }
605 }
606
607 /// Combines four `TypeEq<L*, R*>` to produce a
608 /// `TypeEq<(L0, L1, L2, L3), (R0, R1, R2, L3)>`.
609 ///
610 /// # Alternative
611 ///
612 /// For an alternative which allows zipping `TypeEq` with three of any
613 /// [`BaseTypeWitness`](crate::BaseTypeWitness),
614 /// you can use [`methods::zip4`](crate::methods::zip4)
615 /// (requires the `"rust_1_65"` feature)
616 ///
617 /// # Example
618 ///
619 /// ```rust
620 /// use typewit::{TypeEq, type_eq};
621 ///
622 /// use std::cmp::Ordering::{self, Less};
623 ///
624 /// assert_eq!(
625 /// make_tuple(type_eq(), type_eq(), type_eq(), type_eq()),
626 /// (3, "foo", Less, true),
627 /// );
628 ///
629 /// fn make_tuple<A, B, C, D>(
630 /// te0: TypeEq<A, u8>,
631 /// te1: TypeEq<B, &str>,
632 /// te2: TypeEq<C, Ordering>,
633 /// te3: TypeEq<D, bool>,
634 /// ) -> (A, B, C, D) {
635 /// let te: TypeEq<(A, B, C, D), (u8, &str, Ordering, bool)> = te0.zip4(te1, te2, te3);
636 /// te.to_left((3, "foo", Less, true))
637 /// }
638 ///
639 /// ```
640 pub const fn zip4<L1, R1, L2, R2, L3: ?Sized, R3: ?Sized>(
641 self: TypeEq<L0, R0>,
642 other1: TypeEq<L1, R1>,
643 other2: TypeEq<L2, R2>,
644 other3: TypeEq<L3, R3>,
645 ) -> TypeEq<(L0, L1, L2, L3), (R0, R1, R2, R3)> {
646 zip_impl!{
647 self[L0, R0],
648 other1[L1, R1],
649 other2[L2, R2],
650 other3[L3, R3],
651 }
652 }
653
654}
655
656impl<L, R> TypeEq<L, R> {
657 /// Whether `L` is the same type as `R`.
658 ///
659 /// False positive equality is fine for this associated constant,
660 /// since it's used to optimize out definitely unequal types.
661 const ARE_SAME_TYPE: Amb = {
662 // hacky way to emulate a lifetime-unaware
663 // `TypeId::of<L>() == TypeId::of<R>()`
664 let approx_same_type = {
665 core::mem::size_of::<L>() == core::mem::size_of::<R>()
666 && core::mem::align_of::<L>() == core::mem::align_of::<R>()
667 && core::mem::size_of::<Option<L>>() == core::mem::size_of::<Option<R>>()
668 && core::mem::align_of::<Option<L>>() == core::mem::align_of::<Option<R>>()
669 };
670
671 if approx_same_type {
672 Amb::Indefinite
673 } else {
674 Amb::No
675 }
676 };
677
678
679 /// Hints to the compiler that a `TypeEq<L, R>`
680 /// can only be constructed if `L == R`.
681 ///
682 /// This function takes and returns `val` unmodified.
683 /// This allows returning some value from an expression
684 /// while hinting that `L == R`.
685 ///
686 #[inline(always)]
687 pub const fn reachability_hint<T>(self, val: T) -> T {
688 if let Amb::No = Self::ARE_SAME_TYPE {
689 // safety: `TypeEq<L, R>` requires `L == R` to be constructed
690 unsafe { core::hint::unreachable_unchecked() }
691 }
692
693 val
694 }
695
696 /// A no-op cast from `L` to `R`.
697 ///
698 /// This cast is a no-op because having a `TypeEq<L, R>` value
699 /// proves that `L` and `R` are the same type.
700 ///
701 /// # Example
702 ///
703 /// ```rust
704 /// use typewit::{TypeEq, type_eq};
705 ///
706 /// use std::cmp::Ordering::{self, *};
707 ///
708 /// assert_eq!(mutated(Less, Wit::Ord(type_eq())), Greater);
709 /// assert_eq!(mutated(Equal, Wit::Ord(type_eq())), Equal);
710 /// assert_eq!(mutated(Greater, Wit::Ord(type_eq())), Less);
711 ///
712 /// assert_eq!(mutated(false, Wit::Bool(type_eq())), true);
713 /// assert_eq!(mutated(true, Wit::Bool(type_eq())), false);
714 ///
715 /// const fn mutated<R>(arg: R, w: Wit<R>) -> R {
716 /// match w {
717 /// Wit::Ord(te) => te.to_left(te.to_right(arg).reverse()),
718 /// Wit::Bool(te) => te.to_left(!te.to_right(arg)),
719 /// }
720 /// }
721 ///
722 /// enum Wit<R> {
723 /// Ord(TypeEq<R, Ordering>),
724 /// Bool(TypeEq<R, bool>),
725 /// }
726 /// ```
727 ///
728 #[inline(always)]
729 pub const fn to_right(self, from: L) -> R {
730 self.reachability_hint(());
731
732 // safety: `TypeEq<L, R>` requires `L == R` to be constructed
733 unsafe { crate::__priv_transmute!(L, R, from) }
734 }
735 /// A no-op cast from `R` to `L`.
736 ///
737 /// This cast is a no-op because having a `TypeEq<L, R>` value
738 /// proves that `L` and `R` are the same type.
739 ///
740 /// # Example
741 ///
742 /// ```rust
743 /// use typewit::{TypeEq, type_eq};
744 ///
745 /// assert_eq!(stuff(Wit::OptSlice(type_eq())), Some(&[3, 5, 8][..]));
746 /// assert_eq!(stuff(Wit::Bool(type_eq())), true);
747 ///
748 /// const fn stuff<R>(te: Wit<R>) -> R {
749 /// match te {
750 /// Wit::OptSlice(te) => te.to_left(Some(&[3, 5, 8])),
751 /// Wit::Bool(te) => te.to_left(true),
752 /// }
753 /// }
754 ///
755 /// enum Wit<R> {
756 /// OptSlice(TypeEq<R, Option<&'static [u16]>>),
757 /// Bool(TypeEq<R, bool>),
758 /// }
759 /// ```
760 ///
761 #[inline(always)]
762 pub const fn to_left(self, from: R) -> L {
763 self.reachability_hint(());
764
765 // safety: `TypeEq<L, R>` requires `L == R` to be constructed
766 unsafe { crate::__priv_transmute!(R, L, from) }
767 }
768}
769
770
771impl<L: ?Sized, R: ?Sized> TypeWitnessTypeArg for TypeEq<L, R> {
772 type Arg = L;
773}
774
775impl<T: ?Sized> MakeTypeWitness for TypeEq<T, T> {
776 const MAKE: Self = Self::NEW;
777}
778
779
780impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
781 /// Maps the type arguments of this `TypeEq`
782 /// by using the `F` [type-level function](crate::type_fn::TypeFn).
783 ///
784 /// Use this function over [`project`](Self::project)
785 /// if you want the type of the passed in function to be inferred.
786 ///
787 /// # Example
788 ///
789 /// ```rust
790 /// use typewit::{TypeEq, TypeFn};
791 ///
792 /// assert_eq!(foo(TypeEq::NEW), (false, 5));
793 ///
794 /// const fn foo<'a, T>(te: TypeEq<u32, T>) -> (bool, T) {
795 /// // `GPair<bool>` maps `u32` to `(bool, u32)`
796 /// // and maps `T` to `(bool, T)`
797 /// let map_te: TypeEq<(bool, u32), (bool, T)> = te.map(GPair::<bool>::NEW);
798 ///
799 /// // same as the above, but inferring `GPair`'s generic arguments.
800 /// let _: TypeEq<(bool, u32), (bool, T)> = te.map(GPair::NEW);
801 ///
802 /// map_te.to_right((false, 5u32))
803 /// }
804 ///
805 /// // Declares `struct GPair<A>`, a type-level function from `B` to `(A, B)`
806 /// typewit::type_fn! {
807 /// struct GPair<A>;
808 ///
809 /// impl<B> B => (A, B)
810 /// }
811 /// ```
812 ///
813 // #[cfg(feature = "project")]
814 // #[cfg_attr(feature = "docsrs", doc(cfg(feature = "project")))]
815 pub const fn map<F>(
816 self,
817 func: F,
818 ) -> TypeEq<CallFn<InvokeAlias<F>, L>, CallFn<InvokeAlias<F>, R>>
819 where
820 InvokeAlias<F>: crate::TypeFn<L> + crate::TypeFn<R>
821 {
822 core::mem::forget(func);
823 projected_type_cmp!{self, L, R, F}
824 }
825
826 /// Maps the type arguments of this `TypeEq`
827 /// by using the `F` [type-level function](crate::type_fn::TypeFn).
828 ///
829 /// Use this function over [`map`](Self::map)
830 /// if you want to specify the type of the passed in function explicitly.
831 ///
832 /// # Example
833 ///
834 /// ```rust
835 /// use typewit::{TypeEq, TypeFn};
836 ///
837 /// assert_eq!(foo(TypeEq::NEW), vec![3u32, 5, 8]);
838 ///
839 /// fn foo<T>(te: TypeEq<u32, T>) -> Vec<T> {
840 /// let vec_te: TypeEq<Vec<u32>, Vec<T>> = te.project::<GVec>();
841 /// vec_te.to_right(vec![3, 5, 8])
842 /// }
843 ///
844 /// // Declares `GVec`, a type-level function from `T` to `Vec<T>`
845 /// typewit::type_fn!{
846 /// struct GVec;
847 ///
848 /// impl<T> T => Vec<T>
849 /// }
850 ///
851 /// ```
852 ///
853 pub const fn project<F>(self) -> TypeEq<CallFn<InvokeAlias<F>, L>, CallFn<InvokeAlias<F>, R>>
854 where
855 InvokeAlias<F>: crate::TypeFn<L> + crate::TypeFn<R>
856 {
857 projected_type_cmp!{self, L, R, F}
858 }
859}
860
861impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
862 /// Maps the type arguments of this `TypeEq`
863 /// by using the [reversed](crate::RevTypeFn)
864 /// version of the `F` type-level function.
865 ///
866 /// Use this function over [`unproject`](Self::unproject)
867 /// if you want the type of the passed in function to be inferred.
868 ///
869 /// # Example
870 ///
871 /// ```rust
872 /// use typewit::{TypeEq, UncallFn};
873 ///
874 /// assert_eq!(first_int(&[3, 5, 8, 13], TypeEq::NEW), 3);
875 ///
876 /// const fn first_int<T, const N: usize>(
877 /// array: &[T; N],
878 /// te_slice: TypeEq<[T], [u8]>,
879 /// ) -> u8 {
880 /// let te: TypeEq<T, u8> = te_slice.unmap(SliceFn);
881 ///
882 /// let te_ref: TypeEq<&T, &u8> = te.in_ref();
883 ///
884 /// *te_ref.to_right(&array[0])
885 /// }
886 ///
887 /// typewit::inj_type_fn! {
888 /// struct SliceFn;
889 ///
890 /// impl<T> T => [T]
891 /// }
892 /// ```
893 pub const fn unmap<F>(
894 self,
895 func: F,
896 ) -> TypeEq<UncallFn<InvokeAlias<F>, L>, UncallFn<InvokeAlias<F>, R>>
897 where
898 InvokeAlias<F>: RevTypeFn<L> + RevTypeFn<R>
899 {
900 core::mem::forget(func);
901
902 unprojected_type_cmp!{self, L, R, F}
903 }
904
905 /// Maps the type arguments of this `TypeEq`
906 /// by using the [reversed](crate::RevTypeFn)
907 /// version of the `F` type-level function.
908 ///
909 /// Use this function over [`unmap`](Self::unmap)
910 /// if you want to specify the type of the passed in function explicitly.
911 ///
912 /// # Example
913 ///
914 /// ```rust
915 /// use typewit::TypeEq;
916 /// use std::ops::{Range, RangeInclusive as RangeInc};
917 ///
918 /// assert_eq!(usize_bounds(3..=5, TypeEq::NEW), (3, 5));
919 ///
920 /// const fn usize_bounds<T>(
921 /// range: RangeInc<T>,
922 /// te_range: TypeEq<Range<T>, Range<usize>>,
923 /// ) -> (usize, usize) {
924 /// let te: TypeEq<T, usize> = te_range.unproject::<RangeFn>();
925 ///
926 /// let te_range_inc: TypeEq<RangeInc<T>, RangeInc<usize>> = te.project::<RangeIncFn>();
927 ///
928 /// let range: RangeInc<usize> = te_range_inc.to_right(range);
929 ///
930 /// (*range.start(), *range.end())
931 /// }
932 ///
933 /// typewit::inj_type_fn! {
934 /// struct RangeFn;
935 ///
936 /// impl<T> T => Range<T>
937 /// }
938 /// typewit::inj_type_fn! {
939 /// struct RangeIncFn;
940 ///
941 /// impl<T> T => RangeInc<T>
942 /// }
943 /// ```
944 pub const fn unproject<F>(
945 self,
946 ) -> TypeEq<UncallFn<InvokeAlias<F>, L>, UncallFn<InvokeAlias<F>, R>>
947 where
948 InvokeAlias<F>: crate::RevTypeFn<L> + crate::RevTypeFn<R>
949 {
950 unprojected_type_cmp!{self, L, R, F}
951 }
952}
953
954impl<L: ?Sized, R: ?Sized> TypeEq<L, R> {
955 /// Converts a `TypeEq<L, R>` to `TypeEq<&L, &R>`
956 ///
957 /// # Example
958 ///
959 /// ```rust
960 /// use typewit::{MakeTypeWitness, TypeEq};
961 ///
962 /// assert_eq!(get::<u8>(), &3);
963 /// assert_eq!(get::<str>(), "hello");
964 ///
965 ///
966 /// const fn get<R: ?Sized>() -> &'static R
967 /// where
968 /// Returned<R>: MakeTypeWitness
969 /// {
970 /// match MakeTypeWitness::MAKE {
971 /// // `te` is a `TypeEq<R, u8>`
972 /// Returned::U8(te) => te.in_ref().to_left(&3),
973 ///
974 /// // `te` is a `TypeEq<R, str>`
975 /// Returned::Str(te) => te.in_ref().to_left("hello"),
976 /// }
977 /// }
978 ///
979 /// typewit::simple_type_witness! {
980 /// // declares the `enum Returned<R> {` type witness
981 /// enum Returned {
982 /// // this variant requires `R == u8`
983 /// U8 = u8,
984 /// // this variant requires `R == str`
985 /// Str = str,
986 /// }
987 /// }
988 /// ```
989 ///
990 pub const fn in_ref<'a>(self) -> TypeEq<&'a L, &'a R> {
991 projected_type_cmp!{self, L, R, type_fn::GRef<'a>}
992 }
993
994 crate::utils::conditionally_const!{
995 feature = "rust_1_83";
996
997 /// Converts a `TypeEq<L, R>` to `TypeEq<&mut L, &mut R>`
998 ///
999 /// # Constness
1000 ///
1001 /// This requires the `"rust_1_83"` feature to be a `const fn`.
1002 ///
1003 /// # Example
1004 ///
1005 /// Because this example calls `in_mut` inside a `const fn`,
1006 /// it requires the `"rust_1_83"` crate feature.
1007 #[cfg_attr(not(feature = "rust_1_83"), doc = "```ignore")]
1008 #[cfg_attr(feature = "rust_1_83", doc = "```rust")]
1009 ///
1010 /// use typewit::{TypeEq, type_eq};
1011 ///
1012 /// let foo = &mut Foo { bar: 10, baz: ['W', 'H', 'O'] };
1013 ///
1014 /// *get_mut(foo, Field::Bar(type_eq())) *= 2;
1015 /// assert_eq!(foo.bar, 20);
1016 ///
1017 /// assert_eq!(*get_mut(foo, Field::Baz(type_eq())), ['W', 'H', 'O']);
1018 ///
1019 ///
1020 /// const fn get_mut<R>(foo: &mut Foo, te: Field<R>) -> &mut R {
1021 /// match te {
1022 /// Field::Bar(te) => te.in_mut().to_left(&mut foo.bar),
1023 /// Field::Baz(te) => te.in_mut().to_left(&mut foo.baz),
1024 /// }
1025 /// }
1026 ///
1027 /// struct Foo {
1028 /// bar: u8,
1029 /// baz: [char; 3],
1030 /// }
1031 ///
1032 /// enum Field<R: ?Sized> {
1033 /// Bar(TypeEq<R, u8>),
1034 /// Baz(TypeEq<R, [char; 3]>),
1035 /// }
1036 /// ```
1037 ///
1038 pub fn in_mut['a](self) -> TypeEq<&'a mut L, &'a mut R> {
1039 projected_type_cmp!{self, L, R, type_fn::GRefMut<'a>}
1040 }
1041 }
1042
1043 /// Converts a `TypeEq<L, R>` to `TypeEq<Box<L>, Box<R>>`
1044 ///
1045 /// # Example
1046 ///
1047 /// ```rust
1048 /// use typewit::{MakeTypeWitness, TypeEq, type_eq};
1049 ///
1050 /// use std::any::Any;
1051 /// use std::fmt::Display;
1052 ///
1053 /// assert_eq!(factory::<dyn Any>().downcast::<u16>().unwrap(), Box::new(1337));
1054 /// assert_eq!(factory::<dyn Display>().to_string(), "hello bob");
1055 ///
1056 /// fn factory<R: ?Sized>() -> Box<R>
1057 /// where
1058 /// Dyn<R>: MakeTypeWitness
1059 /// {
1060 /// match MakeTypeWitness::MAKE {
1061 /// // `te` is a `TypeEq<R, dyn Any>`
1062 /// Dyn::Any(te) => te.in_box().to_left(Box::new(1337u16)),
1063 ///
1064 /// // `te` is a `TypeEq<R, dyn Display>`
1065 /// Dyn::Display(te) => te.in_box().to_left(Box::new("hello bob")),
1066 /// }
1067 /// }
1068 ///
1069 /// typewit::simple_type_witness! {
1070 /// // declares the `enum Dyn<R> {` type witness
1071 /// enum Dyn {
1072 /// // this variant requires `R == dyn Any`
1073 /// Any = dyn Any,
1074 /// // this variant requires `R == dyn Display`
1075 /// Display = dyn Display,
1076 /// }
1077 /// }
1078 ///
1079 /// ```
1080 ///
1081 #[cfg(feature = "alloc")]
1082 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
1083 pub const fn in_box(self) -> TypeEq<Box<L>, Box<R>> {
1084 projected_type_cmp!{self, L, R, type_fn::GBox}
1085 }
1086}
1087
1088impl<L: Sized, R: Sized> TypeEq<L, R> {
1089 /// Combines `TypeEq<L, R>` and `TypeEq<Usize<UL>, Usize<UR>>`
1090 /// into `TypeEq<[L; UL], [R; UR]>`
1091 ///
1092 /// # Alternative
1093 ///
1094 /// For an alternative which allows passing any
1095 /// [`BaseTypeWitness`](crate::BaseTypeWitness) for the length,
1096 /// you can use [`methods::in_array`](crate::methods::in_array)
1097 /// (requires the `"rust_1_65"` feature)
1098 ///
1099 ///
1100 /// # Example
1101 ///
1102 /// <details>
1103 /// <summary><b>motivation</b></summary>
1104 /// <p>
1105 /// The safe way to map an array in const fns(on stable Rust in 2023)
1106 /// is to create an array of the returned type with some dummy value,
1107 /// and then fill it in with the desired values.
1108 ///
1109 /// Because the function in this example takes a `[T; LEN]` where the `T` is generic,
1110 /// it copies the first element of the input array to initialize the returned array,
1111 /// so we must handle empty arrays,
1112 /// but trying to return an empty array the naive way
1113 /// ```compile_fail
1114 /// # use std::num::Wrapping;
1115 /// # const fn map_wrapping<T: Copy, const LEN: usize>(arr: [T; LEN]) -> [Wrapping<T>; LEN] {
1116 /// if LEN == 0 {
1117 /// return [];
1118 /// }
1119 /// # unimplemented!()
1120 /// # }
1121 /// ```
1122 /// does not work
1123 /// ```text
1124 /// error[E0308]: mismatched types
1125 /// --> src/type_eq.rs:827:16
1126 /// |
1127 /// 4 | const fn map_wrapping<T: Copy, const LEN: usize>(arr: [T; LEN]) -> [Wrapping<T>; LEN] {
1128 /// | ------------------ expected `[Wrapping<T>; LEN]` because of return type
1129 /// 5 | if LEN == 0 {
1130 /// 6 | return [];
1131 /// | ^^ expected `LEN`, found `0`
1132 /// |
1133 /// = note: expected array `[Wrapping<T>; LEN]`
1134 /// found array `[_; 0]`
1135 ///
1136 /// ```
1137 /// </p>
1138 /// </details>
1139 ///
1140 /// This example demonstrates how `in_array` allows one to return an empty array:
1141 /// (this example requires Rust 1.61.0, because it uses trait bounds in const fns)
1142 #[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")]
1143 #[cfg_attr(feature = "rust_1_61", doc = "```rust")]
1144 /// use typewit::{const_marker::Usize, TypeCmp, TypeEq};
1145 ///
1146 /// use std::num::Wrapping;
1147 ///
1148 /// assert_eq!(map_wrapping([""; 0]), []);
1149 /// assert_eq!(map_wrapping([3, 5, 8]), [Wrapping(3), Wrapping(5), Wrapping(8)]);
1150 ///
1151 /// const fn map_wrapping<T: Copy, const LEN: usize>(arr: [T; LEN]) -> [Wrapping<T>; LEN] {
1152 /// // `teq` is a `TypeEq<Usize<LEN>, Usize<0>>`
1153 /// if let TypeCmp::Eq(teq) = Usize::<LEN>.equals(Usize::<0>) {
1154 /// return TypeEq::new::<Wrapping<T>>()
1155 /// .in_array(teq) // `TypeEq<[Wrapping<T>; LEN], [Wrapping<T>; 0]>`
1156 /// .to_left([]);
1157 /// }
1158 ///
1159 /// let mut ret = [Wrapping(arr[0]); LEN];
1160 /// let mut i = 1;
1161 ///
1162 /// while i < LEN {
1163 /// ret[i] = Wrapping(arr[i]);
1164 /// i += 1;
1165 /// }
1166 ///
1167 /// ret
1168 /// }
1169 /// ```
1170 #[inline(always)]
1171 pub const fn in_array<const UL: usize, const UR: usize>(
1172 self,
1173 other: TypeEq<Usize<UL>, Usize<UR>>,
1174 ) -> TypeEq<[L; UL], [R; UR]> {
1175 zip_project!{
1176 self,
1177 other,
1178 crate::type_fn::PairToArrayFn,
1179 (L, R),
1180 (Usize<UL>, Usize<UR>),
1181 }
1182 }
1183}
1184
1185enum Amb {
1186 // indefinitely false/true
1187 Indefinite,
1188 // definitely false
1189 No,
1190}
1191
1192
1193
1194impl<T: ?Sized> Default for TypeEq<T, T> {
1195 fn default() -> Self {
1196 Self::NEW
1197 }
1198}
1199
1200impl<L: ?Sized, R: ?Sized> Debug for TypeEq<L, R> {
1201 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1202 f.write_str("TypeEq")
1203 }
1204}
1205
1206impl<L: ?Sized, R: ?Sized> PartialEq for TypeEq<L, R> {
1207 fn eq(&self, _: &Self) -> bool {
1208 true
1209 }
1210}
1211
1212impl<L: ?Sized, R: ?Sized> PartialOrd for TypeEq<L, R> {
1213 fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
1214 Some(Ordering::Equal)
1215 }
1216}
1217
1218impl<L: ?Sized, R: ?Sized> Ord for TypeEq<L, R> {
1219 fn cmp(&self, _: &Self) -> Ordering {
1220 Ordering::Equal
1221 }
1222}
1223
1224impl<L: ?Sized, R: ?Sized> Eq for TypeEq<L, R> {}
1225
1226
1227impl<L: ?Sized, R: ?Sized> Hash for TypeEq<L, R> {
1228 fn hash<H>(&self, _state: &mut H)
1229 where H: Hasher
1230 {}
1231}
1232