typewit/lib.rs
1#![allow(clippy::needless_doctest_main)]
2//! This crate provides abstractions for creating
3//! [type witnesses](#what-are-type-witnesses).
4//!
5//! The inciting motivation for this crate is emulating trait polymorphism in `const fn`
6//! (as of 2025-07-20, it's not possible to call trait methods in const contexts on stable).
7//!
8//! # What are type witnesses
9//!
10//! Type witnesses are values that prove the equality of a type parameter to a
11//! fixed set of possible types.
12//!
13//! The simplest type witness is [`TypeEq<L, R>`][`TypeEq`],
14//! which only proves equality of its `L` and `R` type parameters,
15//! and can be used to coerce between them.
16//!
17//! Most type witnesses are enums with [`TypeEq`] fields,
18//! which can coerce between a type parameter and as many types as there are variants.
19//!
20//! # Examples
21//!
22//! <span id="example0"></span>
23//!
24//! ### Polymorphic function
25//!
26//! This demonstrates how one can write a polymorphic `const fn`
27//! (as of 2025-07-20, trait methods can't be called in const fns on stable)
28//!
29//! (this example requires Rust 1.61.0, since it uses trait bounds in const)
30#![cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")]
31#![cfg_attr(feature = "rust_1_61", doc = "```rust")]
32//! use typewit::{HasTypeWitness, TypeEq};
33//!
34//! const VALS: [&str; 6] = [
35//! message(0),
36//! message(1),
37//! message(2),
38//! message(3),
39//! message("hi"),
40//! message("foo"),
41//! ];
42//! assert_eq!(VALS, ["A", "B", "C", "A", "hi", "foo"]);
43//!
44//!
45//! // A "method" of the `Message` trait (declared below)
46//! const fn message<'a, T: Message<'a>>(val: T) -> &'a str {
47//! match HasTypeWitness::WITNESS {
48//! MessageWitness::Usize(te) => {
49//! // `te` (a `TypeEq<T, usize>`) allows coercing between `T` and `usize`,
50//! // because `TypeEq` is a value-level proof that both types are the same.
51//! let index: usize = te.to_right(val);
52//! ["A", "B", "C"][index % 3]
53//! }
54//! MessageWitness::Str(te) => {
55//! // `te` is a `TypeEq<T, &'a str>`
56//! te.to_right(val)
57//! }
58//! }
59//! }
60//!
61//! // The trait that we use to emulate polymorphic dispatch,
62//! // the limitation is that it can only emulate it for a limited set of types known
63//! // to the crate that defines the trait, in this case that's `usize` and `&str`.
64//! trait Message<'a>: HasTypeWitness<MessageWitness<'a, Self>> { }
65//!
66//! // replacing these impls with a blanket impl leads to worse compilation errors
67//! impl<'a> Message<'a> for usize {}
68//! impl<'a> Message<'a> for &'a str {}
69//!
70//! // This macro declares `enum MessageWitness<'a, __Wit>`, a type witness enum,
71//! // where each variant requires and then guarantees `__Wit` to be a particular type.
72//! // (the `__Wit` type parameter is implicitly added after all generics)
73//! typewit::simple_type_witness! {
74//! enum MessageWitness<'a> {
75//! // This variant requires `__Wit == usize`
76//! Usize = usize,
77//!
78//! // This variant requires `__Wit == &'a str`
79//! Str = &'a str,
80//! }
81//! }
82//! ```
83//!
84//! <span id="example-uses-type-fn"></span>
85//! ### Indexing polymorphism
86//!
87//! This function demonstrates const fn polymorphism
88//! and projecting [`TypeEq`] by implementing [`TypeFn`].
89//!
90//! (this example requires Rust 1.71.0, because it uses `<[T]>::split_at` in a const context.
91#![cfg_attr(not(feature = "rust_stable"), doc = "```ignore")]
92#![cfg_attr(feature = "rust_stable", doc = "```rust")]
93//! use std::ops::Range;
94//!
95//! use typewit::{HasTypeWitness, TypeEq};
96//!
97//! fn main() {
98//! let array = [3, 5, 8, 13, 21, 34, 55, 89];
99//!
100//! assert_eq!(index(&array, 0), &3);
101//! assert_eq!(index(&array, 3), &13);
102//! assert_eq!(index(&array, 0..4), [3, 5, 8, 13]);
103//! assert_eq!(index(&array, 3..5), [13, 21]);
104//! }
105//!
106//! const fn index<T, I>(slice: &[T], idx: I) -> &SliceIndexRet<I, T>
107//! where
108//! I: SliceIndex<T>,
109//! {
110//! // `I::WITNESS` is `<I as HasTypeWitness<IndexWitness<I>>>::WITNESS`,
111//! match I::WITNESS {
112//! IndexWitness::Usize(arg_te) => {
113//! // `arg_te` (a `TypeEq<I, usize>`) allows coercing between `I` and `usize`,
114//! // because `TypeEq` is a value-level proof that both types are the same.
115//! let idx: usize = arg_te.to_right(idx);
116//!
117//! // using the `TypeFn` impl for `FnSliceIndexRet<T>` to
118//! // map `TypeEq<I, usize>`
119//! // to `TypeEq<SliceIndexRet<I, T>, SliceIndexRet<usize, T>>`
120//! arg_te.project::<FnSliceIndexRet<T>>()
121//! // converts`TypeEq<SliceIndexRet<I, T>, T>`
122//! // to `TypeEq<&SliceIndexRet<I, T>, &T>`
123//! .in_ref()
124//! .to_left(&slice[idx])
125//! }
126//! IndexWitness::Range(arg_te) => {
127//! let range: Range<usize> = arg_te.to_right(idx);
128//! let ret: &[T] = slice_range(slice, range);
129//! arg_te.project::<FnSliceIndexRet<T>>().in_ref().to_left(ret)
130//! }
131//! }
132//! }
133//!
134//! // This macro declares a type witness enum
135//! typewit::simple_type_witness! {
136//! // Declares `enum IndexWitness<__Wit>`
137//! // (the `__Wit` type parameter is implicitly added after all generics)
138//! enum IndexWitness {
139//! // This variant requires `__Wit == usize`
140//! Usize = usize,
141//!
142//! // This variant requires `__Wit == Range<usize>`
143//! Range = Range<usize>,
144//! }
145//! }
146//!
147//! /// Trait for all types that can be used as slice indices
148//! ///
149//! /// The `HasTypeWitness` supertrait allows getting a `IndexWitness<Self>`
150//! /// with its `WITNESS` associated constant.
151//! trait SliceIndex<T>: HasTypeWitness<IndexWitness<Self>> + Sized {
152//! type Returns: ?Sized;
153//! }
154//! impl<T> SliceIndex<T> for usize {
155//! type Returns = T;
156//! }
157//! impl<T> SliceIndex<T> for Range<usize> {
158//! type Returns = [T];
159//! }
160//!
161//! type SliceIndexRet<I, T> = <I as SliceIndex<T>>::Returns;
162//!
163//! // Declares `struct FnSliceIndexRet<T>`
164//! // a type-level function (TypeFn implementor) from `I` to `SliceIndexRet<I, T>`
165//! typewit::type_fn! {
166//! struct FnSliceIndexRet<T>;
167//!
168//! impl<I: SliceIndex<T>> I => SliceIndexRet<I, T>
169//! }
170//!
171//! const fn slice_range<T>(slice: &[T], range: Range<usize>) -> &[T] {
172//! let suffix = slice.split_at(range.start).1;
173//! suffix.split_at(range.end - range.start).0
174//! }
175//!
176//! ```
177//!
178//! When the wrong type is passed for the index,
179//! the compile-time error is the same as with normal generic functions:
180//! ```text
181//! error[E0277]: the trait bound `RangeFull: SliceIndex<{integer}>` is not satisfied
182//! --> src/main.rs:43:30
183//! |
184//! 13 | assert_eq!(index(&array, ..), [13, 21]);
185//! | ----- ^^ the trait `SliceIndex<{integer}>` is not implemented for `RangeFull`
186//! | |
187//! | required by a bound introduced by this call
188//! |
189//! = help: the following other types implement trait `SliceIndex<T>`:
190//! std::ops::Range<usize>
191//! usize
192//! ```
193//!
194//! ### Downcasting const generic type
195//!
196//! This example demonstrates "downcasting" from a type with a const parameter to
197//! a concrete instance of that type.
198//!
199//! ```rust
200//! use typewit::{const_marker::Usize, TypeCmp, TypeEq};
201//!
202//! assert_eq!(*mutate(&mut Arr([])), Arr([]));
203//! assert_eq!(*mutate(&mut Arr([1])), Arr([1]));
204//! assert_eq!(*mutate(&mut Arr([1, 2])), Arr([1, 2]));
205//! assert_eq!(*mutate(&mut Arr([1, 2, 3])), Arr([1, 3, 6])); // this is different!
206//! assert_eq!(*mutate(&mut Arr([1, 2, 3, 4])), Arr([1, 2, 3, 4]));
207//!
208//! #[derive(Debug, PartialEq)]
209//! struct Arr<const N: usize>([u8; N]);
210//!
211//! fn mutate<const N: usize>(arr: &mut Arr<N>) -> &mut Arr<N> {
212//! if let TypeCmp::Eq(te) = Usize::<N>.equals(Usize::<3>) {
213//! let tem = te // `te` is a `TypeEq<Usize<N>, Usize<3>>`
214//! .project::<GArr>() // returns `TypeEq<Arr<N>, Arr<3>>`
215//! .in_mut(); // returns `TypeEq<&mut Arr<N>, &mut Arr<3>>`
216//!
217//! // `tem.to_right(arr)` downcasts `arr` to `&mut Arr<3>`
218//! tetra_sum(tem.to_right(arr));
219//! }
220//!
221//! arr
222//! }
223//!
224//! fn tetra_sum(arr: &mut Arr<3>) {
225//! arr.0[1] += arr.0[0];
226//! arr.0[2] += arr.0[1];
227//! }
228//!
229//! // Declares `struct GArr`
230//! // a type-level function (TypeFn implementor) from `Usize<N>` to `Arr<N>`
231//! typewit::type_fn!{
232//! struct GArr;
233//!
234//! impl<const N: usize> Usize<N> => Arr<N>
235//! }
236//! ```
237//!
238//! ### Builder
239//!
240//! Using a type witness to help encode a type-level enum,
241//! and to match on that type-level enum inside of a function.
242//!
243//! The type-level enum is used to track the initialization of fields in a builder.
244//!
245//! This example requires Rust 1.65.0, because it uses Generic Associated Types.
246#![cfg_attr(not(feature = "rust_1_65"), doc = "```ignore")]
247#![cfg_attr(feature = "rust_1_65", doc = "```rust")]
248//! use typewit::HasTypeWitness;
249//!
250//! fn main() {
251//! // all default fields
252//! assert_eq!(
253//! StructBuilder::new().build(),
254//! Struct{foo: "default value".into(), bar: vec![3, 5, 8]},
255//! );
256//!
257//! // defaulted bar field
258//! assert_eq!(
259//! StructBuilder::new().foo("hello").build(),
260//! Struct{foo: "hello".into(), bar: vec![3, 5, 8]},
261//! );
262//!
263//! // defaulted foo field
264//! assert_eq!(
265//! StructBuilder::new().bar([13, 21, 34]).build(),
266//! Struct{foo: "default value".into(), bar: vec![13, 21, 34]},
267//! );
268//!
269//! // all initialized fields
270//! assert_eq!(
271//! StructBuilder::new().foo("world").bar([55, 89]).build(),
272//! Struct{foo: "world".into(), bar: vec![55, 89]},
273//! );
274//! }
275//!
276//!
277//! #[derive(Debug, PartialEq, Eq)]
278//! struct Struct {
279//! foo: String,
280//! bar: Vec<u32>,
281//! }
282//!
283//! struct StructBuilder<FooInit: InitState, BarInit: InitState> {
284//! // If `FooInit` is `Uninit`, then this field is a `()`
285//! // If `FooInit` is `Init`, then this field is a `String`
286//! foo: BuilderField<FooInit, String>,
287//!
288//! // If `BarInit` is `Uninit`, then this field is a `()`
289//! // If `BarInit` is `Init`, then this field is a `Vec<u32>`
290//! bar: BuilderField<BarInit, Vec<u32>>,
291//! }
292//!
293//! impl StructBuilder<Uninit, Uninit> {
294//! pub const fn new() -> Self {
295//! Self {
296//! foo: (),
297//! bar: (),
298//! }
299//! }
300//! }
301//!
302//! impl<FooInit: InitState, BarInit: InitState> StructBuilder<FooInit, BarInit> {
303//! /// Sets the `foo` field
304//! pub fn foo(self, foo: impl Into<String>) -> StructBuilder<Init, BarInit> {
305//! StructBuilder {
306//! foo: foo.into(),
307//! bar: self.bar,
308//! }
309//! }
310//!
311//! /// Sets the `bar` field
312//! pub fn bar(self, bar: impl Into<Vec<u32>>) -> StructBuilder<FooInit, Init> {
313//! StructBuilder {
314//! foo: self.foo,
315//! bar: bar.into(),
316//! }
317//! }
318//!
319//! /// Builds `Struct`,
320//! /// providing default values for fields that haven't been set.
321//! pub fn build(self) -> Struct {
322//! Struct {
323//! foo: init_or_else::<FooInit, _, _>(self.foo, || "default value".to_string()),
324//! bar: init_or_else::<BarInit, _, _>(self.bar, || vec![3, 5, 8]),
325//! }
326//! }
327//! }
328//!
329//! // Emulates a type-level `enum InitState { Init, Uninit }`
330//! trait InitState: Sized + HasTypeWitness<InitWit<Self>> {
331//! // How a builder represents an initialized/uninitialized field.
332//! // If `Self` is `Uninit`, then this is `()`.
333//! // If `Self` is `Init`, then this is `T`.
334//! type BuilderField<T>;
335//! }
336//!
337//! // If `I` is `Uninit`, then this evaluates to `()`
338//! // If `I` is `Init`, then this evaluates to `T`
339//! type BuilderField<I, T> = <I as InitState>::BuilderField::<T>;
340//!
341//! /// Gets `T` out of `maybe_init` if it's actually initialized,
342//! /// otherwise returns `else_()`.
343//! fn init_or_else<I, T, F>(maybe_init: BuilderField<I, T>, else_: F) -> T
344//! where
345//! I: InitState,
346//! F: FnOnce() -> T
347//! {
348//! typewit::type_fn! {
349//! // Declares the `HelperFn` type-level function (TypeFn implementor)
350//! // from `I` to `BuilderField<I, T>`
351//! struct HelperFn<T>;
352//! impl<I: InitState> I => BuilderField<I, T>
353//! }
354//!
355//! // matching on the type-level `InitState` enum by using `InitWit`.
356//! // `WITNESS` comes from the `HasTypeWitness` trait
357//! match I::WITNESS {
358//! // `te: TypeEq<FooInit, Init>`
359//! InitWit::InitW(te) => {
360//! te.map(HelperFn::NEW) //: TypeEq<BuilderField<I, T>, T>
361//! .to_right(maybe_init)
362//! }
363//! InitWit::UninitW(_) => else_(),
364//! }
365//! }
366//!
367//! // Emulates a type-level `InitState::Init` variant.
368//! // Marks a field as initialized.
369//! enum Init {}
370//!
371//! impl InitState for Init {
372//! type BuilderField<T> = T;
373//! }
374//!
375//! // Emulates a type-level `InitState::Uninit` variant.
376//! // Marks a field as uninitialized.
377//! enum Uninit {}
378//!
379//! impl InitState for Uninit {
380//! type BuilderField<T> = ();
381//! }
382//!
383//! typewit::simple_type_witness! {
384//! // Declares `enum InitWit<__Wit>`, a type witness.
385//! // (the `__Wit` type parameter is implicitly added after all generics)
386//! enum InitWit {
387//! // This variant requires `__Wit == Init`
388//! InitW = Init,
389//! // This variant requires `__Wit == Uninit`
390//! UninitW = Uninit,
391//! }
392//! }
393//! ```
394//!
395//! ### Generic Const Expressions
396//!
397//! This example uses [`Usize`] to coerce an arrays whose length is generic to
398//! another generic, but equal, length.
399//!
400//! This example requires the `"generic_const_exprs"` crate feature because it uses the
401//! currently-unstable [`generic_const_exprs`] language feature.
402#![cfg_attr(not(feature = "generic_const_exprs"), doc = "```ignore")]
403#![cfg_attr(feature = "generic_const_exprs", doc = "```rust")]
404//! #![feature(generic_const_exprs)]
405//!
406//! use typewit::{const_marker::Usize, TypeCmp, TypeEq};
407//!
408//!
409//! let mut arrays = Arrays::<1, 3> { a: [3, 5, 8], b: [13, 21, 34] };
410//!
411//! arrays.swap_inner();
412//!
413//! assert_eq!(arrays.a, [13, 21, 34]);
414//! assert_eq!(arrays.b, [3, 5, 8]);
415//!
416//!
417//! struct Arrays<const A: usize, const B: usize>
418//! where
419//! [u8; A * B]:,
420//! [u8; B * A]:,
421//! {
422//! a: [u8; A * B],
423//! b: [u8; B * A],
424//! }
425//!
426//! impl<const A: usize, const B: usize> Arrays<A, B>
427//! where
428//! [u8; A * B]:,
429//! [u8; B * A]:,
430//! {
431//! // Swaps the two array fields
432//! const fn swap_inner(&mut self) {
433//! let a = TypeEq::new::<u8>() // : TypeEq<u8, u8>
434//! .in_array(commutative_proof::<A, B>()) // : TypeEq<[u8; A * B], [u8; B * A]>
435//! .in_mut() // : TypeEq<&mut [u8; A * B], &mut [u8; B * A]>
436//! .to_right(
437//! &mut self.a // : &mut [u8; A * B]
438//! ); // : &mut [u8; B * A]
439//!
440//! core::mem::swap(a, &mut self.b);
441//! }
442//! }
443//!
444//! const fn commutative_proof<const A: usize, const B: usize>(
445//! ) -> TypeEq<Usize<{A * B}>, Usize<{B * A}>>
446//! {
447//! // panic-safety: A * B == B * A always holds, so this `unwrap_eq` can never panic
448//! Usize::<{A * B}>.equals(Usize::<{B * A}>).unwrap_eq()
449//! }
450//!
451//! ```
452//!
453//! If you tried to swap the fields directly, you'd get this error:
454//! ```text
455//! error[E0308]: mismatched types
456//! --> src/lib.rs:437:38
457//! |
458//! 42 | core::mem::swap(&mut self.a, &mut self.b);
459//! | ^^^^^^^^^^^ expected `A * B`, found `B * A`
460//! |
461//! = note: expected constant `A * B`
462//! found constant `B * A`
463//! ```
464//!
465//!
466//! # Cargo features
467//!
468//! These are the features of this crate.
469//!
470//! ### Default-features
471//!
472//! These features are enabled by default:
473//!
474//! - `"proc_macros"`: uses proc macros to improve compile-errors involving
475//! macro-generated impls.
476//!
477//! ### Rust-versions and standard crates
478//!
479//! These features enable items that have a minimum Rust version:
480//!
481//! - `"rust_stable"`: enables all the `"rust_1_*"` features.
482//!
483//! - `"rust_1_83"`: turns functions that take mutable references into `const fn`s,
484//! enables [`const_marker`] items for comparing [`ConstMarker`]s,
485//! and enables the `"rust_1_65"` feature.
486//!
487//! - `"rust_1_65"`: enables the [`type_constructors`] module,
488//! the [`methods`] module,
489//! and the `"rust_1_61"` feature.
490//!
491//! - `"rust_1_61"`: enables [`MetaBaseTypeWit`],
492//! [`BaseTypeWitness`],
493//! and the `{TypeCmp, TypeNe}::{zip*, in_array}` methods.
494//!
495//! These features enable items that require a non-`core` standard crate:
496//!
497//! - `"alloc"`: enable items that use anything from the standard `alloc` crate.
498//!
499//! ### Nightly features
500//!
501//! These features require the nightly Rust compiler:
502//!
503//! - `"adt_const_marker"`:
504//! enables the `"rust_stable"` crate feature,
505//! and marker types in the [`const_marker`] module that have
506//! non-primitive `const` parameters.
507//!
508//! - `"generic_const_exprs"`:
509//! enables the `"rust_stable"` crate feature,
510//! and doc examples that use the [`generic_const_exprs`] unstable language feature.
511//!
512//! # No-std support
513//!
514//! `typewit` is `#![no_std]`, it can be used anywhere Rust can be used.
515//!
516//! You need to enable the `"alloc"` feature to enable items that use anything
517//! from the standard `alloc` crate.
518//!
519//! # Minimum Supported Rust Version
520//!
521//! `typewit` supports Rust 1.57.0.
522//!
523//! Features that require newer versions of Rust, or the nightly compiler,
524//! need to be explicitly enabled with crate features.
525//!
526//!
527//!
528//! [`TypeCmp`]: crate::TypeCmp
529//! [`TypeEq`]: crate::TypeEq
530//! [`TypeNe`]: crate::TypeNe
531//! [`TypeFn`]: crate::type_fn::TypeFn
532//! [`const_marker`]: crate::const_marker
533//! [`type_constructors`]: crate::type_constructors
534//! [`methods`]: crate::methods
535//! [`MetaBaseTypeWit`]: crate::MetaBaseTypeWit
536//! [`BaseTypeWitness`]: crate::BaseTypeWitness
537//! [`Usize`]: crate::const_marker::Usize
538//! [`typewit::const_marker`]: crate::const_marker
539//! [`ConstMarker`]: crate::const_marker::ConstMarker
540//! [`generic_const_exprs`]: https://doc.rust-lang.org/unstable-book/language-features/generic-const-exprs.html
541#![no_std]
542#![cfg_attr(feature = "adt_const_marker", feature(adt_const_params))]
543#![cfg_attr(feature = "adt_const_marker", feature(unsized_const_params))]
544#![cfg_attr(feature = "adt_const_marker", allow(incomplete_features))]
545#![cfg_attr(feature = "docsrs", feature(doc_cfg))]
546#![allow(clippy::type_complexity)]
547#![deny(missing_docs)]
548#![deny(clippy::missing_const_for_fn)]
549#![deny(unused_results)]
550
551#[cfg(feature = "alloc")]
552extern crate alloc;
553
554
555// Documentation for concepts not specific to any one item
556macro_rules! explain_type_witness {
557 () => ("\
558 A [type witness](crate#what-are-type-witnesses) is \
559 an enum whose variants only have [`TypeEq`](crate::TypeEq) fields.
560 Each variant requires the enum's type parameter to be a specific type.
561 ")
562}
563
564#[macro_use]
565pub mod type_fn;
566
567pub mod const_marker;
568
569#[cfg(feature = "adt_const_marker")]
570mod all_init_bytes;
571
572mod utils;
573mod macros;
574
575#[cfg(feature = "rust_1_61")]
576mod base_type_wit;
577
578#[cfg(feature = "rust_1_61")]
579pub use crate::base_type_wit::{BaseTypeWitness, MetaBaseTypeWit};
580
581
582#[cfg(feature = "rust_1_65")]
583#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_65")))]
584pub mod methods;
585
586
587#[cfg(feature = "rust_1_61")]
588pub(crate) mod some_type_arg_is_ne;
589
590#[cfg(feature = "rust_1_61")]
591pub(crate) use self::some_type_arg_is_ne::SomeTypeArgIsNe;
592
593
594mod type_cmp;
595mod type_eq;
596mod type_eq_ne_guts;
597mod type_identity;
598
599mod type_ne_;
600
601/// [`TypeNe`]-related items
602pub mod type_ne {
603 pub use crate::type_ne_::{LeftArg, RightArg};
604
605 #[doc(no_inline)]
606 pub use crate::{TypeNe, type_ne};
607}
608
609
610mod type_witness_traits;
611
612#[cfg(feature = "rust_1_65")]
613pub mod type_constructors;
614
615
616#[doc(inline)]
617pub use crate::{
618 type_eq::*,
619 type_ne_::TypeNe,
620 type_witness_traits::*,
621 type_identity::Identity,
622};
623
624
625pub use crate::type_cmp::TypeCmp;
626
627#[doc(no_inline)]
628pub use crate::type_fn::{CallFn, CallInjFn, InjTypeFn, RevTypeFn, TypeFn, UncallFn};
629
630
631#[cfg(feature = "proc_macros")]
632#[doc(hidden)]
633pub use typewit_proc_macros::__impl_with_span;
634
635/// tests doc lints with `cargo doc --features="__test_doc_lints rust_stable"`
636#[cfg(all(feature = "__test_doc_lints"))]
637pub mod test_doc_lints;
638
639#[doc(hidden)]
640pub mod __ {
641 pub use core::{
642 clone::Clone,
643 cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering},
644 fmt::{Debug, Formatter, Result as FmtResult},
645 hash::{Hash, Hasher},
646 marker::{Copy, PhantomData},
647 mem::{ManuallyDrop, discriminant},
648 option::Option,
649 primitive::{bool, usize},
650 assert, compile_error, concat, stringify,
651 };
652
653 pub use crate::{
654 type_identity::Identity,
655 macros::{
656 generics_parsing::{
657 __parse_generic_args_with_defaults,
658 __parse_in_generics,
659 __parse_ty_bounds,
660 __parse_where_clause_for_item_inner,
661 __pg_cfg_expansion,
662 __pg_parsed_ty_bounds,
663 },
664 simple_type_witness_macro::__stw_parse_variants,
665 },
666 };
667
668}
669
670
671
672#[cfg(all(doctest, feature = "generic_const_exprs"))]
673#[doc = include_str!("../README.md")]
674pub struct ReadmeTest;