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