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