typewit-1.12.1/.cargo_vcs_info.json0000644000000001360000000000100126230ustar { "git": { "sha1": "cd9f206d0a3c07365cfb3e473c48c0e556ffd918" }, "path_in_vcs": "" }typewit-1.12.1/Cargo.lock0000644000000111060000000000100105750ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "arrayvec" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "basic-toml" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" dependencies = [ "serde", ] [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "once_cell" version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "proc-macro2" version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "serde" version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "syn" version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "trybuild" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6df60d81823ed9c520ee897489573da4b1d79ffbe006b8134f46de1a1aa03555" dependencies = [ "basic-toml", "glob", "once_cell", "serde", "serde_derive", "serde_json", "termcolor", ] [[package]] name = "typewit" version = "1.12.1" dependencies = [ "arrayvec", "trybuild", "typewit_proc_macros", ] [[package]] name = "typewit_proc_macros" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e36a83ea2b3c704935a01b4642946aadd445cea40b10935e3f8bd8052b8193d6" [[package]] name = "unicode-ident" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" typewit-1.12.1/Cargo.toml0000644000000036250000000000100106270ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.57.0" name = "typewit" version = "1.12.1" authors = ["rodrimati1992 "] build = false include = [ "Cargo.toml", "src/**/*.rs", "./README.md", "LICENSE-ZLIB.md", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "type-witness-based abstractions, mostly for emulating polymorphism in const fns" documentation = "https://docs.rs/typewit/" readme = "README.md" keywords = [ "const_fn", "GADT", "type_witness", "type-equality", "refl", ] categories = [ "no-std", "rust-patterns", ] license = "Zlib" repository = "https://github.com/rodrimati1992/typewit/" [package.metadata.docs.rs] features = [ "alloc", "rust_stable", "adt_const_marker", "generic_const_exprs", "docsrs", ] [features] __ui_tests = ["trybuild"] adt_const_marker = ["rust_stable"] alloc = [] const_marker = [] default = ["proc_macros"] docsrs = [] generic_const_exprs = ["rust_stable"] mut_refs = ["rust_stable"] nightly_mut_refs = ["mut_refs"] proc_macros = ["typewit_proc_macros"] rust_1_61 = [] rust_1_65 = ["rust_1_61"] rust_1_83 = ["rust_1_65"] rust_stable = ["rust_1_83"] [lib] name = "typewit" path = "src/lib.rs" [dependencies.trybuild] version = "1.0" optional = true [dependencies.typewit_proc_macros] version = "=1.8.1" optional = true [dev-dependencies.arrayvec] version = "0.7" default-features = false typewit-1.12.1/Cargo.toml.orig000064400000000000000000000025321046102023000143040ustar 00000000000000[package] name = "typewit" version = "1.12.1" authors = ["rodrimati1992 "] rust-version = "1.57.0" edition = "2021" license = "Zlib" description = "type-witness-based abstractions, mostly for emulating polymorphism in const fns" documentation = "https://docs.rs/typewit/" readme="./README.md" keywords = ["const_fn", "GADT", "type_witness", "type-equality", "refl"] categories = ["no-std", "rust-patterns"] repository = "https://github.com/rodrimati1992/typewit/" include = [ "Cargo.toml", "src/**/*.rs", "./README.md", "LICENSE-ZLIB.md", ] [workspace] [dependencies.typewit_proc_macros] version = "=1.8.1" path = "./typewit_proc_macros" optional = true [dev-dependencies.arrayvec] version = "0.7" default-features = false # no such thing as optional dev-dependencies, aaaaaaah [dependencies.trybuild] version = "1.0" optional = true [features] default = ["proc_macros"] rust_1_61 = [] rust_1_65 = ["rust_1_61"] rust_1_83 = ["rust_1_65"] rust_stable = ["rust_1_83"] proc_macros = ["typewit_proc_macros"] const_marker = [] adt_const_marker = ["rust_stable"] generic_const_exprs = ["rust_stable"] alloc = [] mut_refs = ["rust_stable"] nightly_mut_refs = ["mut_refs"] docsrs = [] __ui_tests = ["trybuild"] [package.metadata.docs.rs] features = ["alloc", "rust_stable", "adt_const_marker", "generic_const_exprs", "docsrs"] typewit-1.12.1/LICENSE-ZLIB.md000064400000000000000000000015271046102023000135620ustar 00000000000000Copyright (c) 2023 Matias Rodriguez. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.typewit-1.12.1/README.md000064400000000000000000000403601046102023000126750ustar 00000000000000[![Rust](https://github.com/rodrimati1992/typewit/workflows/Rust/badge.svg)](https://github.com/rodrimati1992/typewit/actions) [![crates-io](https://img.shields.io/crates/v/typewit.svg)](https://crates.io/crates/typewit) [![api-docs](https://docs.rs/typewit/badge.svg)](https://docs.rs/typewit/*) This crate provides abstractions for creating [type witnesses](#what-are-type-witnesses). The inciting motivation for this crate is emulating trait polymorphism in `const fn` (as of 2025-07-20, it's not possible to call trait methods in const contexts on stable). # What are type witnesses Type witnesses are enums that allow coercing between a type parameter and a range of possible types (one per variant). The simplest type witness is [`TypeEq`](crate::TypeEq), which only allows coercing between `L` and `R`. Most type witnesses are enums with [`TypeEq`] fields, which can coerce between a type parameter and as many types as there are variants. # Examples ### Polymorphic function This demonstrates how one can write a polymorphic `const fn` (as of 2025-07-20, trait methods can't be called in const fns on stable) (this example requires Rust 1.61.0, since it uses trait bounds in const) ```rust use typewit::{HasTypeWitness, TypeEq}; const VALS: [&str; 6] = [ message(0), message(1), message(2), message(3), message("hi"), message("foo"), ]; assert_eq!(VALS, ["A", "B", "C", "A", "hi", "foo"]); // A "method" of the `Message` trait (declared below) const fn message<'a, T: Message<'a>>(val: T) -> &'a str { match HasTypeWitness::WITNESS { MessageWitness::Usize(te) => { // `te` (a `TypeEq`) allows coercing between `T` and `usize`, // because `TypeEq` is a value-level proof that both types are the same. let index: usize = te.to_right(val); ["A", "B", "C"][index % 3] } MessageWitness::Str(te) => { // `te` is a `TypeEq` te.to_right(val) } } } // The trait that we use to emulate polymorphic dispatch, // the limitation is that it can only emulate it for a limited set of types known // to the crate that defines the trait, in this case that's `usize` and `&str`. trait Message<'a>: HasTypeWitness> { } // replacing these impls with a blanket impl leads to worse compilation errors impl<'a> Message<'a> for usize {} impl<'a> Message<'a> for &'a str {} // This macro declares `enum MessageWitness<'a, __Wit>`, a type witness enum, // where each variant requires and then guarantees `__Wit` to be a particular type. // (the `__Wit` type parameter is implicitly added after all generics) typewit::simple_type_witness! { enum MessageWitness<'a> { // This variant requires `__Wit == usize` Usize = usize, // This variant requires `__Wit == &'a str` Str = &'a str, } } ``` ### Indexing polymorphism This function demonstrates const fn polymorphism and projecting [`TypeEq`] by implementing [`TypeFn`]. (this example requires Rust 1.71.0, because it uses `<[T]>::split_at` in a const context. ```rust use std::ops::Range; use typewit::{HasTypeWitness, TypeEq}; fn main() { let array = [3, 5, 8, 13, 21, 34, 55, 89]; assert_eq!(index(&array, 0), &3); assert_eq!(index(&array, 3), &13); assert_eq!(index(&array, 0..4), [3, 5, 8, 13]); assert_eq!(index(&array, 3..5), [13, 21]); } const fn index(slice: &[T], idx: I) -> &SliceIndexRet where I: SliceIndex, { // `I::WITNESS` is `>>::WITNESS`, match I::WITNESS { IndexWitness::Usize(arg_te) => { // `arg_te` (a `TypeEq`) allows coercing between `I` and `usize`, // because `TypeEq` is a value-level proof that both types are the same. let idx: usize = arg_te.to_right(idx); // using the `TypeFn` impl for `FnSliceIndexRet` to // map `TypeEq` // to `TypeEq, SliceIndexRet>` arg_te.project::>() // converts`TypeEq, T>` // to `TypeEq<&SliceIndexRet, &T>` .in_ref() .to_left(&slice[idx]) } IndexWitness::Range(arg_te) => { let range: Range = arg_te.to_right(idx); let ret: &[T] = slice_range(slice, range); arg_te.project::>().in_ref().to_left(ret) } } } // This macro declares a type witness enum typewit::simple_type_witness! { // Declares `enum IndexWitness<__Wit>` // (the `__Wit` type parameter is implicitly added after all generics) enum IndexWitness { // This variant requires `__Wit == usize` Usize = usize, // This variant requires `__Wit == Range` Range = Range, } } /// Trait for all types that can be used as slice indices /// /// The `HasTypeWitness` supertrait allows getting a `IndexWitness` /// with its `WITNESS` associated constant. trait SliceIndex: HasTypeWitness> + Sized { type Returns: ?Sized; } impl SliceIndex for usize { type Returns = T; } impl SliceIndex for Range { type Returns = [T]; } type SliceIndexRet = >::Returns; // Declares `struct FnSliceIndexRet` // a type-level function (TypeFn implementor) from `I` to `SliceIndexRet` typewit::type_fn! { struct FnSliceIndexRet; impl> I => SliceIndexRet } const fn slice_range(slice: &[T], range: Range) -> &[T] { let suffix = slice.split_at(range.start).1; suffix.split_at(range.end - range.start).0 } ``` When the wrong type is passed for the index, the compile-time error is the same as with normal generic functions: ```text error[E0277]: the trait bound `RangeFull: SliceIndex<{integer}>` is not satisfied --> src/main.rs:43:30 | 13 | assert_eq!(index(&array, ..), [13, 21]); | ----- ^^ the trait `SliceIndex<{integer}>` is not implemented for `RangeFull` | | | required by a bound introduced by this call | = help: the following other types implement trait `SliceIndex`: std::ops::Range usize ``` ### Downcasting const generic type This example demonstrates "downcasting" from a type with a const parameter to a concrete instance of that type. ```rust use typewit::{const_marker::Usize, TypeCmp, TypeEq}; assert_eq!(*mutate(&mut Arr([])), Arr([])); assert_eq!(*mutate(&mut Arr([1])), Arr([1])); assert_eq!(*mutate(&mut Arr([1, 2])), Arr([1, 2])); assert_eq!(*mutate(&mut Arr([1, 2, 3])), Arr([1, 3, 6])); // this is different! assert_eq!(*mutate(&mut Arr([1, 2, 3, 4])), Arr([1, 2, 3, 4])); #[derive(Debug, PartialEq)] struct Arr([u8; N]); fn mutate(arr: &mut Arr) -> &mut Arr { if let TypeCmp::Eq(te) = Usize::.equals(Usize::<3>) { let tem = te // `te` is a `TypeEq, Usize<3>>` .project::() // returns `TypeEq, Arr<3>>` .in_mut(); // returns `TypeEq<&mut Arr, &mut Arr<3>>` // `tem.to_right(arr)` downcasts `arr` to `&mut Arr<3>` tetra_sum(tem.to_right(arr)); } arr } fn tetra_sum(arr: &mut Arr<3>) { arr.0[1] += arr.0[0]; arr.0[2] += arr.0[1]; } // Declares `struct GArr` // a type-level function (TypeFn implementor) from `Usize` to `Arr` typewit::type_fn!{ struct GArr; impl Usize => Arr } ``` ### Builder Using a type witness to help encode a type-level enum, and to match on that type-level enum inside of a function. The type-level enum is used to track the initialization of fields in a builder. This example requires Rust 1.65.0, because it uses Generic Associated Types. ```rust use typewit::HasTypeWitness; fn main() { // all default fields assert_eq!( StructBuilder::new().build(), Struct{foo: "default value".into(), bar: vec![3, 5, 8]}, ); // defaulted bar field assert_eq!( StructBuilder::new().foo("hello").build(), Struct{foo: "hello".into(), bar: vec![3, 5, 8]}, ); // defaulted foo field assert_eq!( StructBuilder::new().bar([13, 21, 34]).build(), Struct{foo: "default value".into(), bar: vec![13, 21, 34]}, ); // all initialized fields assert_eq!( StructBuilder::new().foo("world").bar([55, 89]).build(), Struct{foo: "world".into(), bar: vec![55, 89]}, ); } #[derive(Debug, PartialEq, Eq)] struct Struct { foo: String, bar: Vec, } struct StructBuilder { // If `FooInit` is `Uninit`, then this field is a `()` // If `FooInit` is `Init`, then this field is a `String` foo: BuilderField, // If `BarInit` is `Uninit`, then this field is a `()` // If `BarInit` is `Init`, then this field is a `Vec` bar: BuilderField>, } impl StructBuilder { pub const fn new() -> Self { Self { foo: (), bar: (), } } } impl StructBuilder { /// Sets the `foo` field pub fn foo(self, foo: impl Into) -> StructBuilder { StructBuilder { foo: foo.into(), bar: self.bar, } } /// Sets the `bar` field pub fn bar(self, bar: impl Into>) -> StructBuilder { StructBuilder { foo: self.foo, bar: bar.into(), } } /// Builds `Struct`, /// providing default values for fields that haven't been set. pub fn build(self) -> Struct { Struct { foo: init_or_else::(self.foo, || "default value".to_string()), bar: init_or_else::(self.bar, || vec![3, 5, 8]), } } } // Emulates a type-level `enum InitState { Init, Uninit }` trait InitState: Sized + HasTypeWitness> { // How a builder represents an initialized/uninitialized field. // If `Self` is `Uninit`, then this is `()`. // If `Self` is `Init`, then this is `T`. type BuilderField; } // If `I` is `Uninit`, then this evaluates to `()` // If `I` is `Init`, then this evaluates to `T` type BuilderField = ::BuilderField::; /// Gets `T` out of `maybe_init` if it's actually initialized, /// otherwise returns `else_()`. fn init_or_else(maybe_init: BuilderField, else_: F) -> T where I: InitState, F: FnOnce() -> T { typewit::type_fn! { // Declares the `HelperFn` type-level function (TypeFn implementor) // from `I` to `BuilderField` struct HelperFn; impl I => BuilderField } // matching on the type-level `InitState` enum by using `InitWit`. // `WITNESS` comes from the `HasTypeWitness` trait match I::WITNESS { // `te: TypeEq` InitWit::InitW(te) => { te.map(HelperFn::NEW) //: TypeEq, T> .to_right(maybe_init) } InitWit::UninitW(_) => else_(), } } // Emulates a type-level `InitState::Init` variant. // Marks a field as initialized. enum Init {} impl InitState for Init { type BuilderField = T; } // Emulates a type-level `InitState::Uninit` variant. // Marks a field as uninitialized. enum Uninit {} impl InitState for Uninit { type BuilderField = (); } typewit::simple_type_witness! { // Declares `enum InitWit<__Wit>`, a type witness. // (the `__Wit` type parameter is implicitly added after all generics) enum InitWit { // This variant requires `__Wit == Init` InitW = Init, // This variant requires `__Wit == Uninit` UninitW = Uninit, } } ``` ### Generic Const Expressions This example uses [`Usize`] to coerce an arrays whose length is generic to another generic, but equal, length. This example requires the `"generic_const_exprs"` crate feature because it uses the currently-unstable [`generic_const_exprs`] language feature. ```rust #![feature(generic_const_exprs)] use typewit::{const_marker::Usize, TypeCmp, TypeEq}; let mut arrays = Arrays::<1, 3> { a: [3, 5, 8], b: [13, 21, 34] }; arrays.swap_inner(); assert_eq!(arrays.a, [13, 21, 34]); assert_eq!(arrays.b, [3, 5, 8]); struct Arrays where [u8; A * B]:, [u8; B * A]:, { a: [u8; A * B], b: [u8; B * A], } impl Arrays where [u8; A * B]:, [u8; B * A]:, { // Swaps the two array fields const fn swap_inner(&mut self) { let a = TypeEq::new::() // : TypeEq .in_array(commutative_proof::()) // : TypeEq<[u8; A * B], [u8; B * A]> .in_mut() // : TypeEq<&mut [u8; A * B], &mut [u8; B * A]> .to_right( &mut self.a // : &mut [u8; A * B] ); // : &mut [u8; B * A] core::mem::swap(a, &mut self.b); } } const fn commutative_proof( ) -> TypeEq, Usize<{B * A}>> { // panic-safety: A * B == B * A always holds, so this `unwrap_eq` can never panic Usize::<{A * B}>.equals(Usize::<{B * A}>).unwrap_eq() } ``` If you tried to swap the fields directly, you'd get this error: ```text error[E0308]: mismatched types --> src/lib.rs:437:38 | 42 | core::mem::swap(&mut self.a, &mut self.b); | ^^^^^^^^^^^ expected `A * B`, found `B * A` | = note: expected constant `A * B` found constant `B * A` ``` # Cargo features These are the features of this crate. ### Default-features These features are enabled by default: - `"proc_macros"`: uses proc macros to improve compile-errors involving macro-generated impls. ### Rust-versions and standard crates These features enable items that have a minimum Rust version: - `"rust_stable"`: enables all the `"rust_1_*"` features. - `"rust_1_83"`: turns functions that take mutable references into `const fn`s, and enables the `"rust_1_65"` feature. - `"rust_1_65"`: enables the [`type_constructors`] module, the [`methods`] module, and the `"rust_1_61"` feature. - `"rust_1_61"`: enables [`MetaBaseTypeWit`], [`BaseTypeWitness`], and the `{TypeCmp, TypeNe}::{zip*, in_array}` methods. These features enable items that require a non-`core` standard crate: - `"alloc"`: enable items that use anything from the standard `alloc` crate. ### Nightly features These features require the nightly Rust compiler: - `"adt_const_marker"`: enables the `"rust_stable"` crate feature, and marker types in the [`const_marker`] module that have non-primitive `const` parameters. - `"generic_const_exprs"`: enables the `"rust_stable"` crate feature, and doc examples that use the [`generic_const_exprs`] unstable language feature. # No-std support `typewit` is `#![no_std]`, it can be used anywhere Rust can be used. You need to enable the `"alloc"` feature to enable items that use anything from the standard `alloc` crate. # Minimum Supported Rust Version `typewit` supports Rust 1.57.0. Features that require newer versions of Rust, or the nightly compiler, need to be explicitly enabled with crate features. [`TypeCmp`]: https://docs.rs/typewit/latest/typewit/enum.TypeCmp.html [`TypeEq`]: https://docs.rs/typewit/latest/typewit/struct.TypeEq.html [`TypeNe`]: https://docs.rs/typewit/latest/typewit/struct.TypeEq.html [`TypeFn`]: https://docs.rs/typewit/latest/typewit/type_fn/trait.TypeFn.html [`const_marker`]: https://docs.rs/typewit/latest/typewit/const_marker/index.html [`type_constructors`]: https://docs.rs/typewit/latest/typewit/type_constructors/index.html [`methods`]: https://docs.rs/typewit/latest/typewit/methods/index.html [`MetaBaseTypeWit`]: https://docs.rs/typewit/latest/typewit/enum.MetaBaseTypeWit.html [`BaseTypeWitness`]: https://docs.rs/typewit/latest/typewit/trait.BaseTypeWitness.html [`Usize`]: https://docs.rs/typewit/latest/typewit/const_marker/struct.Usize.html [`generic_const_exprs`]: https://doc.rust-lang.org/unstable-book/language-features/generic-const-exprs.html typewit-1.12.1/src/all_init_bytes/tests.rs000064400000000000000000000050721046102023000167170ustar 00000000000000use super::{as_bytes, slice_as_bytes}; macro_rules! test_int { ($vals:expr) => ({ for val in $vals { assert_eq!(as_bytes(&val), val.to_ne_bytes()); let mut vec = arrayvec::ArrayVec::::new(); vec.try_extend_from_slice(&val.to_ne_bytes()).unwrap(); vec.try_extend_from_slice(&val.to_ne_bytes()).unwrap(); assert_eq!(slice_as_bytes(&[val, val]), &vec[..]); } }); } macro_rules! test_signed_int { ($vals:expr) => ({ for val in $vals { test_int!{[val, -val]} } }); } #[test] fn test_bool_as_bytes() { for b in [false, true] { assert_eq!(as_bytes(&b), &[b as u8][..]); assert_eq!(slice_as_bytes(&[b]), &[b as u8][..]); } } #[test] fn test_char_as_bytes() { for c in ['f', 'o', '\n', '\t', 'ñ', '个', '\u{100000}', char::MAX] { assert_eq!(as_bytes(&c), (c as u32).to_ne_bytes()); assert_eq!(slice_as_bytes(&[c]), (c as u32).to_ne_bytes()); } } #[test] fn test_u8_as_bytes() { test_int!{[0u8, 233u8]} } #[test] fn test_u16_as_bytes() { test_int!{[0u16, 500u16, 1000u16]} } #[test] fn test_u32_as_bytes() { test_int!{[0u32, 500u32, 1000u32, 1_000_000u32, 1_000_000_000u32]} } #[test] fn test_u64_as_bytes() { test_int!{[ 0u64, 500u64, 1000u64, 1_000_000u64, 1_000_000_000u64, 1_000_000_000_000_000_000u64, ]} } #[test] fn test_u128_as_bytes() { test_int!{[ 0u128, 500u128, 1000u128, 1_000_000u128, 1_000_000_000u128, 1_000_000_000_000_000_000u128, 1_000_000_000_000_000_000_000_000_000u128, 1_000_000_000_000_000_000_000_000_000_000_000_000u128, ]} } #[test] fn test_usize_as_bytes() { test_int!{[0usize, 500usize, 1000usize, 12345usize]} } #[test] fn test_i8_as_bytes() { test_signed_int!{[0i8, 111i8]} } #[test] fn test_i16_as_bytes() { test_signed_int!{[0i16, 500i16, 1000i16]} } #[test] fn test_i32_as_bytes() { test_signed_int!{[0i32, 500i32, 1000i32, 1_000_000i32, 1_000_000_000i32]} } #[test] fn test_i64_as_bytes() { test_signed_int!{[ 0i64, 500i64, 1000i64, 1_000_000i64, 1_000_000_000i64, 1_000_000_000_000_000_000i64, ]} } #[test] fn test_i128_as_bytes() { test_signed_int!{[ 0i128, 500i128, 1000i128, 1_000_000i128, 1_000_000_000i128, 1_000_000_000_000_000_000i128, 1_000_000_000_000_000_000_000_000_000i128, 1_000_000_000_000_000_000_000_000_000_000_000_000i128, ]} } #[test] fn test_isize_as_bytes() { test_signed_int!{[0isize, 500isize, 1000isize, 12345isize]} } typewit-1.12.1/src/all_init_bytes.rs000064400000000000000000000023531046102023000155540ustar 00000000000000#[cfg(test)] mod tests; /// Marker trait for type for which all bytes are initialized /// /// # Safety /// /// All of the bytes in this type must be initialized. /// Uninitialized bytes includes padding and `MaybeUninit` fields. pub(crate) unsafe trait AllInitBytes {} #[allow(dead_code)] pub(crate) const fn as_bytes(reff: &T) -> &[u8] { unsafe { core::slice::from_raw_parts ( reff as *const T as *const u8, core::mem::size_of::(), ) } } pub(crate) const fn slice_as_bytes(reff: &[T]) -> &[u8] { unsafe { core::slice::from_raw_parts ( reff.as_ptr() as *const u8, reff.len() * core::mem::size_of::(), ) } } unsafe impl AllInitBytes for bool {} unsafe impl AllInitBytes for char {} unsafe impl AllInitBytes for u8 {} unsafe impl AllInitBytes for u16 {} unsafe impl AllInitBytes for u32 {} unsafe impl AllInitBytes for u64 {} unsafe impl AllInitBytes for u128 {} unsafe impl AllInitBytes for usize {} unsafe impl AllInitBytes for i8 {} unsafe impl AllInitBytes for i16 {} unsafe impl AllInitBytes for i32 {} unsafe impl AllInitBytes for i64 {} unsafe impl AllInitBytes for i128 {} unsafe impl AllInitBytes for isize {} typewit-1.12.1/src/base_type_wit/meta_base_type_wit.rs000064400000000000000000000036101046102023000212520ustar 00000000000000use crate::{MakeTypeWitness, TypeWitnessTypeArg, TypeEq, TypeNe, TypeCmp}; use core::fmt::{self, Debug}; /// Type witness for /// [`TypeEq`](crate::TypeEq)/[`TypeNe`](crate::TypeNe)/[`TypeCmp`](crate::TypeCmp). #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))] pub enum MetaBaseTypeWit { /// `where W == TypeEq` Eq(TypeEq>), /// `where W == TypeNe` Ne(TypeEq>), /// `where W == TypeCmp` Cmp(TypeEq>), } impl MetaBaseTypeWit { /// Converts `W` to `TypeCmp` pub const fn to_cmp(self, witness: W) -> TypeCmp { match self { Self::Cmp(te) => te.to_right(witness), Self::Eq(te) => TypeCmp::Eq(te.to_right(witness)), Self::Ne(te) => TypeCmp::Ne(te.to_right(witness)), } } } impl Copy for MetaBaseTypeWit {} impl Clone for MetaBaseTypeWit { fn clone(&self) -> Self { *self } } impl Debug for MetaBaseTypeWit { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let isa = match self { Self::Eq{..} => "TypeEq", Self::Ne{..} => "TypeNe", Self::Cmp{..} => "TypeCmp", }; f.write_str(isa) } } impl TypeWitnessTypeArg for MetaBaseTypeWit { type Arg = W; } impl MakeTypeWitness for MetaBaseTypeWit> { const MAKE: Self = Self::Cmp(TypeEq::NEW); } impl MakeTypeWitness for MetaBaseTypeWit> { const MAKE: Self = Self::Eq(TypeEq::NEW); } impl MakeTypeWitness for MetaBaseTypeWit> { const MAKE: Self = Self::Ne(TypeEq::NEW); } typewit-1.12.1/src/base_type_wit.rs000064400000000000000000000032411046102023000154060ustar 00000000000000//! abstractions over //! [`TypeEq`](crate::TypeEq)/[`TypeNe`](crate::TypeNe)/[`TypeCmp`](crate::TypeCmp). mod meta_base_type_wit; pub use meta_base_type_wit::MetaBaseTypeWit; /// Marker trait for /// [`TypeCmp`](crate::TypeCmp)/[`TypeEq`](crate::TypeEq)/[`TypeNe`](crate::TypeNe). /// /// [`TypeEq`]: crate::TypeEq /// [`TypeNe`]: crate::TypeNe /// [`TypeCmp`]: crate::TypeCmp #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))] pub trait BaseTypeWitness: core::fmt::Debug + Copy + crate::HasTypeWitness> { /// The `L` type parameter of `TypeEq`/`TypeNe`/`TypeCmp` types. type L: ?Sized; /// The `R` type parameter of `TypeEq`/`TypeNe`/`TypeCmp` types. type R: ?Sized; /// The [type constructor] corresponding to this type. /// /// [type constructor]: crate::type_constructors::BaseTypeWitnessTc #[cfg(feature = "rust_1_65")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_65")))] type TypeCtor: crate::type_constructors::BaseTypeWitnessTc = Self>; } impl BaseTypeWitness for crate::TypeEq { type L = L; type R = R; #[cfg(feature = "rust_1_65")] type TypeCtor = crate::type_constructors::TcTypeEq; } impl BaseTypeWitness for crate::TypeNe { type L = L; type R = R; #[cfg(feature = "rust_1_65")] type TypeCtor = crate::type_constructors::TcTypeNe; } impl BaseTypeWitness for crate::TypeCmp { type L = L; type R = R; #[cfg(feature = "rust_1_65")] type TypeCtor = crate::type_constructors::TcTypeCmp; } typewit-1.12.1/src/const_marker/boolwit.rs000064400000000000000000000235541046102023000167270ustar 00000000000000use core::fmt::{self, Debug}; use crate::{ const_marker::Bool, TypeCmp, TypeEq, TypeWitnessTypeArg, MakeTypeWitness, }; /// Type Witness that [`Bool`](Bool) is either `Bool` or `Bool`. /// /// Use this over [`BoolWitG`] if you have a `const B: bool` parameter already. /// /// # Example /// /// Making a function that takes a generic `Foo` and calls methods on /// `Foo` or `Foo` depending on the value of the `const B: bool` parameter. /// /// ```rust /// use typewit::{const_marker::{Bool, BoolWit}, MakeTypeWitness}; /// /// /// assert_eq!(call_next(Incrementor::(4)), Incrementor(5)); /// assert_eq!(call_next(Incrementor::(5)), Incrementor(6)); /// /// assert_eq!(call_next(Incrementor::(4)), Incrementor(3)); /// assert_eq!(call_next(Incrementor::(3)), Incrementor(2)); /// /// /// const fn call_next(incrementor: Incrementor) -> Incrementor { /// typewit::type_fn! { /// // type-level function from `Bool` to `Incrementor` /// struct IncrementorFn; /// impl Bool => Incrementor /// } /// /// // The example below this one shows how to write this match more concisely /// match BoolWit::MAKE { /// // `bw: TypeEq, Bool>` /// BoolWit::True(bw) => { /// // `te: TypeEq, Incrementor>` /// let te = bw.project::(); /// /// // `te.to_right` casts `Incrementor` to `Incrementor`, /// // (this allows calling the inherent method). /// // /// // `te.to_left` casts `Incrementor` to `Incrementor` /// te.to_left(te.to_right(incrementor).next()) /// } /// // `bw: TypeEq, Bool>` /// BoolWit::False(bw) => { /// // `te: TypeEq, Incrementor>` /// let te = bw.project::(); /// /// // like the other branch, but with `Incrementor` /// te.to_left(te.to_right(incrementor).next()) /// } /// } /// } /// /// /// #[derive(Debug, Copy, Clone, PartialEq, Eq)] /// struct Incrementor(usize); /// /// const GO_UP: bool = true; /// const GO_DOWN: bool = false; /// /// impl Incrementor { /// #[track_caller] /// pub const fn next(self) -> Self { /// Self(self.0 - 1) /// } /// } /// /// impl Incrementor { /// pub const fn next(self) -> Self { /// Self(self.0 + 1) /// } /// } /// /// ``` /// /// ### Using `polymatch` for conciseness /// /// The [`polymatch`](crate::polymatch) macro can be used to /// more concisely implement the `call_next` function. /// /// ``` /// # use typewit::{const_marker::{Bool, BoolWit}, MakeTypeWitness}; /// # /// const fn call_next(incrementor: Incrementor) -> Incrementor { /// typewit::type_fn! { /// struct IncrementorFn; /// impl Bool => Incrementor /// } /// /// // expands to a match with two arms, /// // one for `BoolWit::True` and one for `BoolWit::False`, /// // copying the expression to the right of the `=>` to both arms. /// typewit::polymatch! {BoolWit::MAKE; /// BoolWit::True(bw) | BoolWit::False(bw) => { /// let te = bw.project::(); /// te.to_left(te.to_right(incrementor).next()) /// } /// } /// } /// # /// # #[derive(Debug, Copy, Clone, PartialEq, Eq)] /// # struct Incrementor(usize); /// # /// # const GO_UP: bool = true; /// # const GO_DOWN: bool = false; /// # /// # impl Incrementor { /// # #[track_caller] /// # pub const fn next(self) -> Self { unimplemented!() } /// # } /// # /// # impl Incrementor { /// # pub const fn next(self) -> Self { unimplemented!() } /// # } /// ``` /// /// ### What happens without `BoolWit` /// /// If the `call_next` function was defined like this: /// ```rust,compile_fail /// # use typewit::{const_marker::{Bool, BoolWit}, MakeTypeWitness}; /// # /// const fn call_next(incrementor: Incrementor) -> Incrementor { /// incrementor.next() /// } /// # #[derive(Copy, Clone)] /// # struct Incrementor(usize); /// # /// # impl Incrementor { /// # pub const fn next(self) -> Self { /// # unimplemented!() /// # } /// # } /// # /// # impl Incrementor { /// # pub const fn next(self) -> Self { /// # unimplemented!() /// # } /// # } /// ``` /// it would produce this error /// ```text /// error[E0599]: no method named `next` found for struct `Incrementor` in the current scope /// --> src/const_marker/const_witnesses.rs:20:17 /// | /// 7 | incrementor.next() /// | ^^^^ method not found in `Incrementor` /// ... /// 38 | struct Incrementor(usize); /// | ---------------------------------------- method `next` not found for this struct /// | /// = note: the method was found for /// - `Incrementor` /// - `Incrementor` /// ``` /// /// pub type BoolWit = BoolWitG>; /// Type witness that `B` is either [`Bool`]`` or [`Bool`]`` /// /// Use this over [`BoolWit`] if you want to write a [`HasTypeWitness`] bound /// and adding a `const B: bool` parameter would be impossible. /// /// # Example /// /// This basic example demonstrates where `BoolWitG` would be used instead of `BoolWit`. /// /// ```rust /// use typewit::const_marker::{Bool, BoolWitG}; /// use typewit::HasTypeWitness; /// /// /// trait Boolean: Sized + HasTypeWitness> { /// type Not: Boolean; /// } /// /// impl Boolean for Bool { /// type Not = Bool; /// } /// /// impl Boolean for Bool { /// type Not = Bool; /// } /// ``` /// /// [`HasTypeWitness`]: crate::HasTypeWitness pub enum BoolWitG { /// Witnesses that `B == true` True(TypeEq>), /// Witnesses that `B == false` False(TypeEq>), } impl BoolWitG { /// Whether `B == Bool` /// /// # Example /// /// ```rust /// use typewit::{const_marker::BoolWitG, TypeEq}; /// /// assert_eq!(BoolWitG::True(TypeEq::NEW).is_true(), true); /// assert_eq!(BoolWitG::False(TypeEq::NEW).is_true(), false); /// ``` /// pub const fn is_true(self) -> bool { matches!(self, Self::True{..}) } /// Whether `B == Bool` /// /// # Example /// /// ```rust /// use typewit::{const_marker::BoolWitG, TypeEq}; /// /// assert_eq!(BoolWitG::True(TypeEq::NEW).is_false(), false); /// assert_eq!(BoolWitG::False(TypeEq::NEW).is_false(), true); /// ``` /// pub const fn is_false(self) -> bool { matches!(self, Self::False{..}) } /// Gets a proof of `B == Bool`, returns None if `B == Bool` /// /// # Example /// /// ```rust /// use typewit::{const_marker::{Bool, BoolWitG}, TypeEq}; /// /// assert_eq!(BoolWitG::True(TypeEq::NEW).to_true(), Some(TypeEq::new::>())); /// assert_eq!(BoolWitG::False(TypeEq::NEW).to_true(), None); /// ``` /// pub const fn to_true(self) -> Option>> { match self { Self::True(x) => Some(x), Self::False{..} => None } } /// Gets a proof of `B == Bool`, returns None if `B == Bool` /// /// # Example /// /// ```rust /// use typewit::{const_marker::{Bool, BoolWitG}, TypeEq}; /// /// assert_eq!(BoolWitG::True(TypeEq::NEW).to_false(), None); /// assert_eq!(BoolWitG::False(TypeEq::NEW).to_false(), Some(TypeEq::new::>())); /// ``` /// pub const fn to_false(self) -> Option>> { match self { Self::False(x) => Some(x), Self::True{..} => None } } /// Gets a proof of `B == Bool`. /// /// # Panic /// /// Panics if `B == Bool` /// /// # Example /// /// ```rust /// use typewit::{const_marker::{Bool, BoolWitG}, TypeEq}; /// /// assert_eq!(BoolWitG::True(TypeEq::NEW).unwrap_true(), TypeEq::new::>()); /// ``` /// pub const fn unwrap_true(self) -> TypeEq> { match self { Self::True(x) => x, Self::False{..} => panic!("attempted to unwrap into True on False variant") } } /// Gets a proof of `B == Bool`. /// /// # Panic /// /// Panics if `B == Bool` /// /// # Example /// /// ```rust /// use typewit::{const_marker::{Bool, BoolWitG}, TypeEq}; /// /// assert_eq!(BoolWitG::False(TypeEq::NEW).unwrap_false(), TypeEq::new::>()); /// ``` /// pub const fn unwrap_false(self) -> TypeEq> { match self { Self::False(x) => x, Self::True{..} => panic!("attempted to unwrap into False on True variant") } } } impl Copy for BoolWitG {} impl Clone for BoolWitG { fn clone(&self) -> Self { *self } } impl Debug for BoolWitG { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(match self { Self::True{..} => "True", Self::False{..} => "False", }) } } impl TypeWitnessTypeArg for BoolWitG { type Arg = B; } impl MakeTypeWitness for BoolWitG> { const MAKE: Self = { if let TypeCmp::Eq(te) = Bool.equals(Bool) { BoolWit::True(te) } else if let TypeCmp::Eq(te) = Bool.equals(Bool) { BoolWit::False(te) } else { panic!("unreachable: `B` is either `true` or `false`") } }; } typewit-1.12.1/src/const_marker/slice_const_markers/tests.rs000064400000000000000000000026361046102023000224410ustar 00000000000000use super::{u8_slice_eq, str_slice_eq}; #[test] fn u8_slice_test() { assert!(u8_slice_eq(b"", b"")); assert!(!u8_slice_eq(b"", b"0")); assert!(!u8_slice_eq(b"0", b"")); assert!(u8_slice_eq(b"0", b"0")); assert!(!u8_slice_eq(b"0", b"1")); assert!(!u8_slice_eq(b"1", b"0")); assert!(!u8_slice_eq(b"0", b"0, 1")); assert!(!u8_slice_eq(b"0, 1", b"0")); assert!(!u8_slice_eq(b"0, 1", b"1")); assert!(u8_slice_eq(b"0, 1", b"0, 1")); assert!(!u8_slice_eq(b"0, 1", b"0, 2")); } #[test] fn str_slice_eq_test() { // different lengths assert!(str_slice_eq(&[], &[])); assert!(str_slice_eq(&[""], &[""])); assert!(!str_slice_eq(&[], &[""])); assert!(!str_slice_eq(&[""], &[])); // length 1 assert!(str_slice_eq(&["foo"], &["foo"])); assert!(!str_slice_eq(&["foo"], &["bar"])); // length 2 assert!(str_slice_eq(&["foo", "bar"], &["foo", "bar"])); assert!(!str_slice_eq(&["foo", "bar"], &["foo", "baz"])); assert!(!str_slice_eq(&["foo", "bar"], &["foo", "bbr"])); assert!(!str_slice_eq(&["foo", "bar"], &["foo", "car"])); // length 3 assert!(str_slice_eq(&["foo", "foo2", "bar"], &["foo", "foo2", "bar"])); assert!(!str_slice_eq(&["foo", "foo2", "bar"], &["foo", "foo2", "baz"])); assert!(!str_slice_eq(&["foo", "foo2", "bar"], &["foo", "foo2", "bbr"])); assert!(!str_slice_eq(&["foo", "foo2", "bar"], &["foo", "foo2", "car"])); }typewit-1.12.1/src/const_marker/slice_const_markers.rs000064400000000000000000000120561046102023000212740ustar 00000000000000use crate::{ all_init_bytes::slice_as_bytes, TypeEq, TypeNe, }; #[cfg(test)] mod tests; super::declare_const_param_type! { /// # Example /// /// Using this marker type to implement dispatching of fields by name. /// /// ```rust /// #![feature(adt_const_params)] /// #![feature(unsized_const_params)] /// /// use typewit::{const_marker::Str, MakeTypeWitness}; /// /// let value = Stuff { /// foo: 3, /// bar: "hello", /// }; /// /// assert_eq!(value.get::<"foo">(), &3); /// assert_eq!(value.get::<"bar">(), &"hello"); /// /// pub struct Stuff<'a> { /// foo: u32, /// bar: &'a str, /// } /// /// impl<'a> Stuff<'a> { /// const fn get(&self) -> &>::Type /// where /// FieldWit>: MakeTypeWitness, /// Self: Field, /// { /// let func = FnFieldTy::::NEW; /// /// match FieldWit::MAKE { /// FieldWit::Foo(te) => te.map(func).in_ref().to_left(&self.foo), /// FieldWit::Bar(te) => te.map(func).in_ref().to_left(&self.bar), /// } /// } /// } /// /// typewit::type_fn! { /// struct FnFieldTy; /// /// impl Str => >::Type /// where Struct: Field /// } /// /// trait Field { /// type Type: ?Sized; /// } /// impl<'a> Field<"foo"> for Stuff<'a> { /// type Type = u32; /// } /// impl<'a> Field<"bar"> for Stuff<'a> { /// type Type = &'a str; /// } /// /// typewit::simple_type_witness! { /// // the #[non_exhaustive] is necessary to be able to add fields to Stuff /// #[non_exhaustive] /// pub enum FieldWit { /// Foo = Str<"foo">, /// Bar = Str<"bar">, /// } /// } /// /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "adt_const_marker")))] Str(&'static str) fn equals(l, r) { u8_slice_eq(l.as_bytes(), r.as_bytes()) }; } super::declare_const_param_type! { StrSlice(&'static [&'static str]) #[cfg_attr(feature = "docsrs", doc(cfg(feature = "adt_const_marker")))] fn equals(l, r) { str_slice_eq(l, r) }; } super::declare_const_param_type! { BoolSlice(&'static [bool]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { CharSlice(&'static [char]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { U8Slice(&'static [u8]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { U16Slice(&'static [u16]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { U32Slice(&'static [u32]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { U64Slice(&'static [u64]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { U128Slice(&'static [u128]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { UsizeSlice(&'static [usize]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { I8Slice(&'static [i8]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { I16Slice(&'static [i16]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { I32Slice(&'static [i32]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { I64Slice(&'static [i64]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { I128Slice(&'static [i128]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } super::declare_const_param_type! { IsizeSlice(&'static [isize]) fn equals(l, r) { u8_slice_eq(slice_as_bytes(l), slice_as_bytes(r)) }; } macro_rules! cmp_slice_of { ($left:ident, $right:ident, |$l:ident, $r:ident| $eq:expr) => { if $left.len() != $right.len() { false } else { let mut i = 0; loop { if i == $left.len() { break true; } let $l = &$left[i]; let $r = &$right[i]; if !$eq { break false; } i += 1; } } } } const fn str_slice_eq(left: &[&str], right: &[&str]) -> bool { cmp_slice_of!{left, right, |l, r| u8_slice_eq(l.as_bytes(), r.as_bytes())} } const fn u8_slice_eq(left: &[u8], right: &[u8]) -> bool { cmp_slice_of!{left, right, |l, r| *l == *r} } typewit-1.12.1/src/const_marker.rs000064400000000000000000000225511046102023000152440ustar 00000000000000//! Marker types for passing constants as type arguments. //! //! # Example //! //! This example emulates specialization, //! eliding a `.clone()` call when the created array is only one element long. //! //! ```rust //! use typewit::{const_marker::Usize, TypeCmp, TypeEq}; //! //! let arr = [3u8, 5, 8]; //! //! assert_eq!(repeat(3), []); //! assert_eq!(repeat(3), [3]); //! assert_eq!(repeat(3), [3, 3]); //! assert_eq!(repeat(3), [3, 3, 3]); //! assert_eq!(repeat(3), [3, 3, 3, 3]); //! //! //! fn repeat(val: T) -> [T; OUT] { //! // `te_len` ìs a `TypeEq, Usize<1>>` //! if let TypeCmp::Eq(te_len) = Usize::.equals(Usize::<1>) { //! // This branch is ran when `OUT == 1` //! TypeEq::new::() // returns `TypeEq` //! .in_array(te_len) // returns `TypeEq<[T; OUT], [T; 1]>` //! .to_left([val]) // goes from `[T; 1]` to `[T; OUT]` //! } else { //! // This branch is ran when `OUT != 1` //! [(); OUT].map(|_| val.clone()) //! } //! } //! ``` //! //! use crate::{ TypeEq, TypeNe, }; mod boolwit; pub use boolwit::*; #[cfg(feature = "adt_const_marker")] mod slice_const_markers; #[cfg(feature = "adt_const_marker")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "adt_const_marker")))] pub use slice_const_markers::Str; /// Marker types for `const FOO: &'static [T]` parameters. #[cfg(feature = "adt_const_marker")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "adt_const_marker")))] pub mod slice { pub use super::slice_const_markers::{ BoolSlice, CharSlice, U8Slice, U16Slice, U32Slice, U64Slice, U128Slice, UsizeSlice, I8Slice, I16Slice, I32Slice, I64Slice, I128Slice, IsizeSlice, StrSlice, }; } struct Helper(L, R); macro_rules! __const_eq_with { ($L:ident, $R:ident) => { $L == $R }; ($L:ident, $R:ident, ($L2:ident, $R2:ident) $cmp:expr) => ({ let $L2 = $L; let $R2 = $R; $cmp }); } pub(crate) use __const_eq_with; macro_rules! declare_const_param_type { ( $(#[$struct_docs:meta])* $struct:ident($prim:ty) $( $(#[$eq_docs:meta])* fn equals $(($L:ident, $R:ident) $comparator:block)?; )? ) => { #[doc = concat!( "Marker type for passing `const VAL: ", stringify!($prim), "` as a type parameter." )] $(#[$struct_docs])* #[derive(Debug, Copy, Clone)] pub struct $struct; impl $crate::const_marker::Helper<$struct, $struct> { const EQ: Result< TypeEq<$struct, $struct>, TypeNe<$struct, $struct>, > = if crate::const_marker::__const_eq_with!( L, R $($(, ($L, $R) $comparator)?)? ) { // SAFETY: `L == R` (both are std types with sensible Eq impls) // therefore `$struct == $struct` unsafe { Ok(TypeEq::<$struct, $struct>::new_unchecked()) } } else { // SAFETY: `L != R` (both are std types with sensible Eq impls) // therefore `$struct != $struct` unsafe { Err(TypeNe::<$struct, $struct>::new_unchecked()) } }; const EQUALS: crate::TypeCmp<$struct, $struct> = match Self::EQ { Ok(x) => crate::TypeCmp::Eq(x), Err(x) => crate::TypeCmp::Ne(x), }; } impl $struct { /// Compares `self` and `other` for equality. /// /// Returns: /// - `Ok(TypeEq)`: if `VAL == OTHER` /// - `Err(TypeNe)`: if `VAL != OTHER` /// #[inline(always)] #[deprecated(note = "superceeded by `equals` method", since = "1.8.0")] pub const fn eq( self, _other: $struct, ) -> Result< TypeEq<$struct, $struct>, TypeNe<$struct, $struct>, > { $crate::const_marker::Helper::<$struct, $struct>::EQ } /// Compares `self` and `other` for equality. /// /// Returns: /// - `TypeCmp::Eq(TypeEq)`: if `VAL == OTHER` /// - `TypeCmp::Ne(TypeNe)`: if `VAL != OTHER` /// $($(#[$eq_docs])*)? #[inline(always)] pub const fn equals( self, _other: $struct, ) -> crate::TypeCmp<$struct, $struct> { $crate::const_marker::Helper::<$struct, $struct>::EQUALS } } }; } pub(crate) use declare_const_param_type; declare_const_param_type!{ Bool(bool) /// /// For getting a type witness that /// `Bool` is either `Bool` or `Bool`, /// you can use [`BoolWit`]. /// fn equals; } declare_const_param_type!{Char(char)} declare_const_param_type!{U8(u8)} declare_const_param_type!{U16(u16)} declare_const_param_type!{U32(u32)} declare_const_param_type!{U64(u64)} declare_const_param_type!{U128(u128)} declare_const_param_type!{ Usize(usize) /// # Examples /// /// ### Array /// /// This example demonstrates how `Usize` can be used to /// specialize behavior on array length. /// /// (this example requires Rust 1.61.0, because it uses trait bounds in const fns) #[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")] #[cfg_attr(feature = "rust_1_61", doc = "```rust")] /// use typewit::{const_marker::Usize, TypeCmp, TypeEq}; /// /// assert_eq!(try_from_pair::<_, 0>((3, 5)), Ok([])); /// assert_eq!(try_from_pair::<_, 1>((3, 5)), Ok([3])); /// assert_eq!(try_from_pair::<_, 2>((3, 5)), Ok([3, 5])); /// assert_eq!(try_from_pair::<_, 3>((3, 5)), Err((3, 5))); /// /// /// const fn try_from_pair(pair: (T, T)) -> Result<[T; LEN], (T, T)> { /// if let TypeCmp::Eq(te_len) = Usize::.equals(Usize::<0>) { /// // this branch is ran on `LEN == 0` /// // `te_len` is a `TypeEq, Usize<0>>` /// Ok( /// TypeEq::new::() // `TypeEq` /// .in_array(te_len) // `TypeEq<[T; LEN], [T; 0]>` /// .to_left([]) // Goes from `[T; 0]` to `[T; LEN]` /// ) /// } else if let TypeCmp::Eq(te_len) = Usize.equals(Usize) { /// // this branch is ran on `LEN == 1` /// // `te_len` is inferred to be `TypeEq, Usize<1>>` /// Ok(TypeEq::NEW.in_array(te_len).to_left([pair.0])) /// } else if let TypeCmp::Eq(te_len) = Usize.equals(Usize) { /// // this branch is ran on `LEN == 2` /// // `te_len` is inferred to be `TypeEq, Usize<2>>` /// Ok(TypeEq::NEW.in_array(te_len).to_left([pair.0, pair.1])) /// } else { /// Err(pair) /// } /// } /// /// ``` /// /// ### Struct /// /// This example demonstrates how `Usize` can be used to pass a /// const-generic struct to a function expecting a concrete type of that struct. /// /// ```rust /// use typewit::{const_marker::Usize, TypeCmp}; /// /// assert_eq!(mutate(Array([])), Array([])); /// assert_eq!(mutate(Array([3])), Array([3])); /// assert_eq!(mutate(Array([3, 5])), Array([3, 5])); /// assert_eq!(mutate(Array([3, 5, 8])), Array([8, 5, 3])); // reversed! /// assert_eq!(mutate(Array([3, 5, 8, 13])), Array([3, 5, 8, 13])); /// /// /// #[derive(Debug, PartialEq)] /// struct Array([u32; CAP]); /// /// const fn mutate(arr: Array) -> Array { /// match Usize::.equals(Usize::<3>) { /// // `te_len` is a `TypeEq, Usize<3>>` /// // this branch is ran on `LEN == 3` /// TypeCmp::Eq(te_len) => { /// // `te` is a `TypeEq, Array<3>>` /// let te = te_len.project::(); /// /// // `te.to_right(...)` here goes from `Array` to `Array<3>` /// let ret = reverse3(te.to_right(arr)); /// /// // `te.to_left(...)` here goes from `Array<3>` to `Array` /// te.to_left(ret) /// } /// TypeCmp::Ne(_) => arr, /// } /// } /// /// const fn reverse3(Array([a, b, c]): Array<3>) -> Array<3> { /// Array([c, b, a]) /// } /// /// typewit::type_fn!{ /// // Type-level function from `Usize` to `Array` /// struct GArray; /// /// impl Usize => Array /// } /// ``` fn equals; } declare_const_param_type!{I8(i8)} declare_const_param_type!{I16(i16)} declare_const_param_type!{I32(i32)} declare_const_param_type!{I64(i64)} declare_const_param_type!{I128(i128)} declare_const_param_type!{Isize(isize)} typewit-1.12.1/src/lib.rs000064400000000000000000000517741046102023000133340ustar 00000000000000#![allow(clippy::needless_doctest_main)] //! This crate provides abstractions for creating //! [type witnesses](#what-are-type-witnesses). //! //! The inciting motivation for this crate is emulating trait polymorphism in `const fn` //! (as of 2025-07-20, it's not possible to call trait methods in const contexts on stable). //! //! # What are type witnesses //! //! Type witnesses are enums that allow coercing between a type parameter and a //! range of possible types (one per variant). //! //! The simplest type witness is [`TypeEq`](crate::TypeEq), //! which only allows coercing between `L` and `R`. //! //! Most type witnesses are enums with [`TypeEq`] fields, //! which can coerce between a type parameter and as many types as there are variants. //! //! # Examples //! //! //! //! ### Polymorphic function //! //! This demonstrates how one can write a polymorphic `const fn` //! (as of 2025-07-20, trait methods can't be called in const fns on stable) //! //! (this example requires Rust 1.61.0, since it uses trait bounds in const) #![cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")] #![cfg_attr(feature = "rust_1_61", doc = "```rust")] //! use typewit::{HasTypeWitness, TypeEq}; //! //! const VALS: [&str; 6] = [ //! message(0), //! message(1), //! message(2), //! message(3), //! message("hi"), //! message("foo"), //! ]; //! assert_eq!(VALS, ["A", "B", "C", "A", "hi", "foo"]); //! //! //! // A "method" of the `Message` trait (declared below) //! const fn message<'a, T: Message<'a>>(val: T) -> &'a str { //! match HasTypeWitness::WITNESS { //! MessageWitness::Usize(te) => { //! // `te` (a `TypeEq`) allows coercing between `T` and `usize`, //! // because `TypeEq` is a value-level proof that both types are the same. //! let index: usize = te.to_right(val); //! ["A", "B", "C"][index % 3] //! } //! MessageWitness::Str(te) => { //! // `te` is a `TypeEq` //! te.to_right(val) //! } //! } //! } //! //! // The trait that we use to emulate polymorphic dispatch, //! // the limitation is that it can only emulate it for a limited set of types known //! // to the crate that defines the trait, in this case that's `usize` and `&str`. //! trait Message<'a>: HasTypeWitness> { } //! //! // replacing these impls with a blanket impl leads to worse compilation errors //! impl<'a> Message<'a> for usize {} //! impl<'a> Message<'a> for &'a str {} //! //! // This macro declares `enum MessageWitness<'a, __Wit>`, a type witness enum, //! // where each variant requires and then guarantees `__Wit` to be a particular type. //! // (the `__Wit` type parameter is implicitly added after all generics) //! typewit::simple_type_witness! { //! enum MessageWitness<'a> { //! // This variant requires `__Wit == usize` //! Usize = usize, //! //! // This variant requires `__Wit == &'a str` //! Str = &'a str, //! } //! } //! ``` //! //! //! ### Indexing polymorphism //! //! This function demonstrates const fn polymorphism //! and projecting [`TypeEq`] by implementing [`TypeFn`]. //! //! (this example requires Rust 1.71.0, because it uses `<[T]>::split_at` in a const context. #![cfg_attr(not(feature = "rust_stable"), doc = "```ignore")] #![cfg_attr(feature = "rust_stable", doc = "```rust")] //! use std::ops::Range; //! //! use typewit::{HasTypeWitness, TypeEq}; //! //! fn main() { //! let array = [3, 5, 8, 13, 21, 34, 55, 89]; //! //! assert_eq!(index(&array, 0), &3); //! assert_eq!(index(&array, 3), &13); //! assert_eq!(index(&array, 0..4), [3, 5, 8, 13]); //! assert_eq!(index(&array, 3..5), [13, 21]); //! } //! //! const fn index(slice: &[T], idx: I) -> &SliceIndexRet //! where //! I: SliceIndex, //! { //! // `I::WITNESS` is `>>::WITNESS`, //! match I::WITNESS { //! IndexWitness::Usize(arg_te) => { //! // `arg_te` (a `TypeEq`) allows coercing between `I` and `usize`, //! // because `TypeEq` is a value-level proof that both types are the same. //! let idx: usize = arg_te.to_right(idx); //! //! // using the `TypeFn` impl for `FnSliceIndexRet` to //! // map `TypeEq` //! // to `TypeEq, SliceIndexRet>` //! arg_te.project::>() //! // converts`TypeEq, T>` //! // to `TypeEq<&SliceIndexRet, &T>` //! .in_ref() //! .to_left(&slice[idx]) //! } //! IndexWitness::Range(arg_te) => { //! let range: Range = arg_te.to_right(idx); //! let ret: &[T] = slice_range(slice, range); //! arg_te.project::>().in_ref().to_left(ret) //! } //! } //! } //! //! // This macro declares a type witness enum //! typewit::simple_type_witness! { //! // Declares `enum IndexWitness<__Wit>` //! // (the `__Wit` type parameter is implicitly added after all generics) //! enum IndexWitness { //! // This variant requires `__Wit == usize` //! Usize = usize, //! //! // This variant requires `__Wit == Range` //! Range = Range, //! } //! } //! //! /// Trait for all types that can be used as slice indices //! /// //! /// The `HasTypeWitness` supertrait allows getting a `IndexWitness` //! /// with its `WITNESS` associated constant. //! trait SliceIndex: HasTypeWitness> + Sized { //! type Returns: ?Sized; //! } //! impl SliceIndex for usize { //! type Returns = T; //! } //! impl SliceIndex for Range { //! type Returns = [T]; //! } //! //! type SliceIndexRet = >::Returns; //! //! // Declares `struct FnSliceIndexRet` //! // a type-level function (TypeFn implementor) from `I` to `SliceIndexRet` //! typewit::type_fn! { //! struct FnSliceIndexRet; //! //! impl> I => SliceIndexRet //! } //! //! const fn slice_range(slice: &[T], range: Range) -> &[T] { //! let suffix = slice.split_at(range.start).1; //! suffix.split_at(range.end - range.start).0 //! } //! //! ``` //! //! When the wrong type is passed for the index, //! the compile-time error is the same as with normal generic functions: //! ```text //! error[E0277]: the trait bound `RangeFull: SliceIndex<{integer}>` is not satisfied //! --> src/main.rs:43:30 //! | //! 13 | assert_eq!(index(&array, ..), [13, 21]); //! | ----- ^^ the trait `SliceIndex<{integer}>` is not implemented for `RangeFull` //! | | //! | required by a bound introduced by this call //! | //! = help: the following other types implement trait `SliceIndex`: //! std::ops::Range //! usize //! ``` //! //! ### Downcasting const generic type //! //! This example demonstrates "downcasting" from a type with a const parameter to //! a concrete instance of that type. //! //! ```rust //! use typewit::{const_marker::Usize, TypeCmp, TypeEq}; //! //! assert_eq!(*mutate(&mut Arr([])), Arr([])); //! assert_eq!(*mutate(&mut Arr([1])), Arr([1])); //! assert_eq!(*mutate(&mut Arr([1, 2])), Arr([1, 2])); //! assert_eq!(*mutate(&mut Arr([1, 2, 3])), Arr([1, 3, 6])); // this is different! //! assert_eq!(*mutate(&mut Arr([1, 2, 3, 4])), Arr([1, 2, 3, 4])); //! //! #[derive(Debug, PartialEq)] //! struct Arr([u8; N]); //! //! fn mutate(arr: &mut Arr) -> &mut Arr { //! if let TypeCmp::Eq(te) = Usize::.equals(Usize::<3>) { //! let tem = te // `te` is a `TypeEq, Usize<3>>` //! .project::() // returns `TypeEq, Arr<3>>` //! .in_mut(); // returns `TypeEq<&mut Arr, &mut Arr<3>>` //! //! // `tem.to_right(arr)` downcasts `arr` to `&mut Arr<3>` //! tetra_sum(tem.to_right(arr)); //! } //! //! arr //! } //! //! fn tetra_sum(arr: &mut Arr<3>) { //! arr.0[1] += arr.0[0]; //! arr.0[2] += arr.0[1]; //! } //! //! // Declares `struct GArr` //! // a type-level function (TypeFn implementor) from `Usize` to `Arr` //! typewit::type_fn!{ //! struct GArr; //! //! impl Usize => Arr //! } //! ``` //! //! ### Builder //! //! Using a type witness to help encode a type-level enum, //! and to match on that type-level enum inside of a function. //! //! The type-level enum is used to track the initialization of fields in a builder. //! //! This example requires Rust 1.65.0, because it uses Generic Associated Types. #![cfg_attr(not(feature = "rust_1_65"), doc = "```ignore")] #![cfg_attr(feature = "rust_1_65", doc = "```rust")] //! use typewit::HasTypeWitness; //! //! fn main() { //! // all default fields //! assert_eq!( //! StructBuilder::new().build(), //! Struct{foo: "default value".into(), bar: vec![3, 5, 8]}, //! ); //! //! // defaulted bar field //! assert_eq!( //! StructBuilder::new().foo("hello").build(), //! Struct{foo: "hello".into(), bar: vec![3, 5, 8]}, //! ); //! //! // defaulted foo field //! assert_eq!( //! StructBuilder::new().bar([13, 21, 34]).build(), //! Struct{foo: "default value".into(), bar: vec![13, 21, 34]}, //! ); //! //! // all initialized fields //! assert_eq!( //! StructBuilder::new().foo("world").bar([55, 89]).build(), //! Struct{foo: "world".into(), bar: vec![55, 89]}, //! ); //! } //! //! //! #[derive(Debug, PartialEq, Eq)] //! struct Struct { //! foo: String, //! bar: Vec, //! } //! //! struct StructBuilder { //! // If `FooInit` is `Uninit`, then this field is a `()` //! // If `FooInit` is `Init`, then this field is a `String` //! foo: BuilderField, //! //! // If `BarInit` is `Uninit`, then this field is a `()` //! // If `BarInit` is `Init`, then this field is a `Vec` //! bar: BuilderField>, //! } //! //! impl StructBuilder { //! pub const fn new() -> Self { //! Self { //! foo: (), //! bar: (), //! } //! } //! } //! //! impl StructBuilder { //! /// Sets the `foo` field //! pub fn foo(self, foo: impl Into) -> StructBuilder { //! StructBuilder { //! foo: foo.into(), //! bar: self.bar, //! } //! } //! //! /// Sets the `bar` field //! pub fn bar(self, bar: impl Into>) -> StructBuilder { //! StructBuilder { //! foo: self.foo, //! bar: bar.into(), //! } //! } //! //! /// Builds `Struct`, //! /// providing default values for fields that haven't been set. //! pub fn build(self) -> Struct { //! Struct { //! foo: init_or_else::(self.foo, || "default value".to_string()), //! bar: init_or_else::(self.bar, || vec![3, 5, 8]), //! } //! } //! } //! //! // Emulates a type-level `enum InitState { Init, Uninit }` //! trait InitState: Sized + HasTypeWitness> { //! // How a builder represents an initialized/uninitialized field. //! // If `Self` is `Uninit`, then this is `()`. //! // If `Self` is `Init`, then this is `T`. //! type BuilderField; //! } //! //! // If `I` is `Uninit`, then this evaluates to `()` //! // If `I` is `Init`, then this evaluates to `T` //! type BuilderField = ::BuilderField::; //! //! /// Gets `T` out of `maybe_init` if it's actually initialized, //! /// otherwise returns `else_()`. //! fn init_or_else(maybe_init: BuilderField, else_: F) -> T //! where //! I: InitState, //! F: FnOnce() -> T //! { //! typewit::type_fn! { //! // Declares the `HelperFn` type-level function (TypeFn implementor) //! // from `I` to `BuilderField` //! struct HelperFn; //! impl I => BuilderField //! } //! //! // matching on the type-level `InitState` enum by using `InitWit`. //! // `WITNESS` comes from the `HasTypeWitness` trait //! match I::WITNESS { //! // `te: TypeEq` //! InitWit::InitW(te) => { //! te.map(HelperFn::NEW) //: TypeEq, T> //! .to_right(maybe_init) //! } //! InitWit::UninitW(_) => else_(), //! } //! } //! //! // Emulates a type-level `InitState::Init` variant. //! // Marks a field as initialized. //! enum Init {} //! //! impl InitState for Init { //! type BuilderField = T; //! } //! //! // Emulates a type-level `InitState::Uninit` variant. //! // Marks a field as uninitialized. //! enum Uninit {} //! //! impl InitState for Uninit { //! type BuilderField = (); //! } //! //! typewit::simple_type_witness! { //! // Declares `enum InitWit<__Wit>`, a type witness. //! // (the `__Wit` type parameter is implicitly added after all generics) //! enum InitWit { //! // This variant requires `__Wit == Init` //! InitW = Init, //! // This variant requires `__Wit == Uninit` //! UninitW = Uninit, //! } //! } //! ``` //! //! ### Generic Const Expressions //! //! This example uses [`Usize`] to coerce an arrays whose length is generic to //! another generic, but equal, length. //! //! This example requires the `"generic_const_exprs"` crate feature because it uses the //! currently-unstable [`generic_const_exprs`] language feature. #![cfg_attr(not(feature = "generic_const_exprs"), doc = "```ignore")] #![cfg_attr(feature = "generic_const_exprs", doc = "```rust")] //! #![feature(generic_const_exprs)] //! //! use typewit::{const_marker::Usize, TypeCmp, TypeEq}; //! //! //! let mut arrays = Arrays::<1, 3> { a: [3, 5, 8], b: [13, 21, 34] }; //! //! arrays.swap_inner(); //! //! assert_eq!(arrays.a, [13, 21, 34]); //! assert_eq!(arrays.b, [3, 5, 8]); //! //! //! struct Arrays //! where //! [u8; A * B]:, //! [u8; B * A]:, //! { //! a: [u8; A * B], //! b: [u8; B * A], //! } //! //! impl Arrays //! where //! [u8; A * B]:, //! [u8; B * A]:, //! { //! // Swaps the two array fields //! const fn swap_inner(&mut self) { //! let a = TypeEq::new::() // : TypeEq //! .in_array(commutative_proof::()) // : TypeEq<[u8; A * B], [u8; B * A]> //! .in_mut() // : TypeEq<&mut [u8; A * B], &mut [u8; B * A]> //! .to_right( //! &mut self.a // : &mut [u8; A * B] //! ); // : &mut [u8; B * A] //! //! core::mem::swap(a, &mut self.b); //! } //! } //! //! const fn commutative_proof( //! ) -> TypeEq, Usize<{B * A}>> //! { //! // panic-safety: A * B == B * A always holds, so this `unwrap_eq` can never panic //! Usize::<{A * B}>.equals(Usize::<{B * A}>).unwrap_eq() //! } //! //! ``` //! //! If you tried to swap the fields directly, you'd get this error: //! ```text //! error[E0308]: mismatched types //! --> src/lib.rs:437:38 //! | //! 42 | core::mem::swap(&mut self.a, &mut self.b); //! | ^^^^^^^^^^^ expected `A * B`, found `B * A` //! | //! = note: expected constant `A * B` //! found constant `B * A` //! ``` //! //! //! # Cargo features //! //! These are the features of this crate. //! //! ### Default-features //! //! These features are enabled by default: //! //! - `"proc_macros"`: uses proc macros to improve compile-errors involving //! macro-generated impls. //! //! ### Rust-versions and standard crates //! //! These features enable items that have a minimum Rust version: //! //! - `"rust_stable"`: enables all the `"rust_1_*"` features. //! //! - `"rust_1_83"`: turns functions that take mutable references into `const fn`s, //! and enables the `"rust_1_65"` feature. //! //! - `"rust_1_65"`: enables the [`type_constructors`] module, //! the [`methods`] module, //! and the `"rust_1_61"` feature. //! //! - `"rust_1_61"`: enables [`MetaBaseTypeWit`], //! [`BaseTypeWitness`], //! and the `{TypeCmp, TypeNe}::{zip*, in_array}` methods. //! //! These features enable items that require a non-`core` standard crate: //! //! - `"alloc"`: enable items that use anything from the standard `alloc` crate. //! //! ### Nightly features //! //! These features require the nightly Rust compiler: //! //! - `"adt_const_marker"`: //! enables the `"rust_stable"` crate feature, //! and marker types in the [`const_marker`] module that have //! non-primitive `const` parameters. //! //! - `"generic_const_exprs"`: //! enables the `"rust_stable"` crate feature, //! and doc examples that use the [`generic_const_exprs`] unstable language feature. //! //! # No-std support //! //! `typewit` is `#![no_std]`, it can be used anywhere Rust can be used. //! //! You need to enable the `"alloc"` feature to enable items that use anything //! from the standard `alloc` crate. //! //! # Minimum Supported Rust Version //! //! `typewit` supports Rust 1.57.0. //! //! Features that require newer versions of Rust, or the nightly compiler, //! need to be explicitly enabled with crate features. //! //! //! //! [`TypeCmp`]: crate::TypeCmp //! [`TypeEq`]: crate::TypeEq //! [`TypeNe`]: crate::TypeNe //! [`TypeFn`]: crate::type_fn::TypeFn //! [`const_marker`]: crate::const_marker //! [`type_constructors`]: crate::type_constructors //! [`methods`]: crate::methods //! [`MetaBaseTypeWit`]: crate::MetaBaseTypeWit //! [`BaseTypeWitness`]: crate::BaseTypeWitness //! [`Usize`]: crate::const_marker::Usize //! [`generic_const_exprs`]: https://doc.rust-lang.org/unstable-book/language-features/generic-const-exprs.html #![no_std] #![cfg_attr(feature = "adt_const_marker", feature(adt_const_params))] #![cfg_attr(feature = "adt_const_marker", feature(unsized_const_params))] #![cfg_attr(feature = "adt_const_marker", allow(incomplete_features))] #![cfg_attr(feature = "docsrs", feature(doc_cfg))] #![allow(clippy::type_complexity)] #![deny(missing_docs)] #![deny(clippy::missing_const_for_fn)] #![deny(unused_results)] #[cfg(feature = "alloc")] extern crate alloc; // Documentation for concepts not specific to any one item macro_rules! explain_type_witness { () => ("\ A [type witness](crate#what-are-type-witnesses) is \ an enum whose variants only have [`TypeEq`](crate::TypeEq) fields. Each variant requires the enum's type parameter to be a specific type. ") } #[macro_use] pub mod type_fn; pub mod const_marker; #[cfg(feature = "adt_const_marker")] mod all_init_bytes; mod utils; mod macros; #[cfg(feature = "rust_1_61")] mod base_type_wit; #[cfg(feature = "rust_1_61")] pub use crate::base_type_wit::{BaseTypeWitness, MetaBaseTypeWit}; #[cfg(feature = "rust_1_65")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_65")))] pub mod methods; #[cfg(feature = "rust_1_61")] pub(crate) mod some_type_arg_is_ne; #[cfg(feature = "rust_1_61")] pub(crate) use self::some_type_arg_is_ne::SomeTypeArgIsNe; mod type_cmp; mod type_eq; mod type_eq_ne_guts; mod type_identity; mod type_ne_; /// [`TypeNe`]-related items pub mod type_ne { pub use crate::type_ne_::{LeftArg, RightArg}; #[doc(no_inline)] pub use crate::{TypeNe, type_ne}; } mod type_witness_traits; #[cfg(feature = "rust_1_65")] pub mod type_constructors; #[doc(inline)] pub use crate::{ type_eq::*, type_ne_::TypeNe, type_witness_traits::*, type_identity::Identity, }; pub use crate::type_cmp::TypeCmp; #[doc(no_inline)] pub use crate::type_fn::{CallFn, CallInjFn, InjTypeFn, RevTypeFn, TypeFn, UncallFn}; #[cfg(feature = "proc_macros")] #[doc(hidden)] pub use typewit_proc_macros::__impl_with_span; #[doc(hidden)] pub mod __ { pub use core::{ clone::Clone, cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}, fmt::{Debug, Formatter, Result as FmtResult}, hash::{Hash, Hasher}, marker::{Copy, PhantomData}, mem::{ManuallyDrop, discriminant}, option::Option, primitive::{bool, usize}, assert, compile_error, concat, stringify, }; pub use crate::{ type_identity::Identity, macros::{ generics_parsing::{ __parse_generic_args_with_defaults, __parse_in_generics, __parse_ty_bounds, __parse_where_clause_for_item_inner, __pg_cfg_expansion, __pg_parsed_ty_bounds, }, simple_type_witness_macro::__stw_parse_variants, }, }; } #[cfg(all(doctest, feature = "generic_const_exprs"))] #[doc = include_str!("../README.md")] pub struct ReadmeTest; typewit-1.12.1/src/macros/generics_parsing.rs000064400000000000000000000500201046102023000173530ustar 00000000000000// Generates a macro that takes a sequence of tokens with balanced `<` and `>` tokens // and collects it until one of the additional rules decides macro_rules! declare_generics_consuming_macro {( $_:tt $gen_consuming_macro_:ident = $gen_consuming_macro:ident $parsing_where:expr; $($additional_rules:tt)* ) => { #[doc(hidden)] #[macro_export] macro_rules! $gen_consuming_macro_ { ( $fixed:tt [$_($counter:tt)*] [$_($prev:tt)*] [< $_($rem:tt)*] ) => { $crate::__::$gen_consuming_macro!{ $fixed [1 $_($counter)*] [$_($prev)* <] [$_($rem)*] } }; ( $fixed:tt [$_($counter:tt)*] [$_($prev:tt)*] [<< $_($rem:tt)*] ) => { $crate::__::$gen_consuming_macro!{ $fixed [1 1 $_($counter)*] [$_($prev)* <<] [$_($rem)*] } }; ( $fixed:tt [$counter0:tt $_($counter:tt)*] [$_($prev:tt)*] [> $_($rem:tt)*] ) => { $crate::__::$gen_consuming_macro!{ $fixed [$_($counter)*] [$_($prev)* >] [$_($rem)*] } }; ( $fixed:tt [$counter0:tt $_($counter:tt)*] [$_($prev:tt)*] [>> $_($rem:tt)*] ) => { $crate::__::$gen_consuming_macro!{ $fixed [$_($counter)*] [$_($prev)* >] [> $_($rem)*] } }; ( $fixed:tt [$counter0:tt $_($counter:tt)*] [$_($prev:tt)*] [>== $_($rem:tt)*] ) => { $crate::__::$gen_consuming_macro!{ $fixed [$_($counter)*] [$_($prev)* >] [== $_($rem)*] } }; ( $fixed:tt [$counter0:tt $_($counter:tt)*] [$_($prev:tt)*] [>= $_($rem:tt)*] ) => { $crate::__::$gen_consuming_macro!{ $fixed [$_($counter)*] [$_($prev)* >] [= $_($rem)*] } }; $($additional_rules)* ( $fixed:tt $counter:tt [$_($prev:tt)*] [$token:tt $_($rem:tt)*] ) => { $crate::__::$gen_consuming_macro!{ $fixed $counter [$_($prev)* $token] [$_($rem)*] } }; ( $fixed:tt $counter:tt [$_($prev:tt)*] [$_($token0:tt $_($other:tt)*)?]) => { $crate::__::compile_error!{$crate::__::concat!( "unexpected end of ", $parsing_where,": `", stringify!($_($prev)* $_($token0)?), "`", )} }; ( $_($other:tt)* ) => { $crate::__::compile_error!{$crate::__::concat!( "bug: unhandled syntax in `typewit` macro: ", stringify!($_($other)*), )} }; } pub use $gen_consuming_macro_ as $gen_consuming_macro; }} macro_rules! declare_parse_generics_macros {($_:tt [$($sep:tt)*] [$($err_token:tt)*]) => { #[doc(hidden)] #[macro_export] macro_rules! __parse_in_generics_ { $( ($fixed:tt $gen_args:tt $gen:tt [$_(,)? $err_token $_($rem:tt)*]) => { $crate::__::compile_error!{$crate::__::concat!( "unexpected `", $crate::__::stringify!($err_token), "` in generic parameter list", )} }; )* ( ( $_($callback:ident)::* !($_($callback_args:tt)*) ) // [$( (($($attrs)*) $generic_arg $phantom_arg = $default_val) )*] // Example of a single parameter list: // (() 'a (fn() -> &'a (),)) // (() T (fn() -> $crate::__::PhantomData,)) // ((#[foo]) U (fn() -> $crate::__::PhantomData,) = u32) // (() N ()) // (() M () = 10) $gen_args:tt [$_(((/* no attributes */) $_($generics:tt)*))*] [$_(,)* $_(> $_($rem:tt)*)?] ) => { $_($callback)::* ! { $_($callback_args)* $gen_args [$_(($_($generics)*))*] [] $_($_($rem)*)? } }; // if there is at least one generic param with cfg attributes ( ($_($fixed:tt)*) $gen_args:tt [$_((($_( $_(#[cfg($_($cfg:tt)+)])+ )?) $generics_first:tt $_($generics:tt)*))+] [$_(,)* $_(> $_($rem:tt)*)?] ) => { $crate::__::__pg_cfg_expansion!{ ($_($fixed)* $_($_($rem)+)?) [] $gen_args [] [$_(($generics_first $_($generics)*))*] [] [$_( ($_($generics_first all( $_( $_($cfg)+ ),* ))?) )+] } }; ( ($_($fixed:tt)*) $gen_args:tt [$_((($_(#[$_($attr:tt)*])*) $_($generics:tt)*))+] [$_(,)* $_(> $_($rem:tt)*)?] ) => { $_( $crate::__assert_valid_gen_attr!{ [] [$_(#[$_($attr)*])*] } )* }; $( ( $fixed:tt [$_($prev_gen_args:tt)*] [$_($prev_gen:tt)*] [ $_(,)? $_(#[$_($attr:tt)*])* $lt:lifetime $_(: $_($lt_bound0:lifetime $_( + $lt_bound1:lifetime)*)? )? $_($sep $_($rem:tt)*)? ] ) => { $crate::__::__parse_in_generics!{ $fixed [$_($prev_gen_args)* ($lt (fn() -> &$lt (),) )] [ $_($prev_gen)* (($_(#[$_($attr)*])*) $lt $_(: $_($lt_bound0 $_( + $lt_bound1 )* )?)?) ] [$_($sep $_($rem)*)?] } }; ( $fixed:tt [$_($prev_gen_args:tt)*] [$_($prev_gen:tt)*] [ $_(,)? $_(#[$_($attr:tt)*])* const $const:ident: $const_ty:ty $_(= $default:tt)? $_($sep $_($rem:tt)*)? ] ) => { $crate::__::__parse_in_generics!{ $fixed [$_($prev_gen_args)* ($const () $_(= $default)?)] [$_($prev_gen)* (($_(#[$_($attr)*])*) const $const: $const_ty)] [$_($sep $_($rem)*)?] } }; )* ( $fixed:tt $prev_gen_args:tt $prev_gen:tt [ $_(,)? $_(#[$_($attr:tt)*])* $ty:ident: $_($rem:tt)* ] ) => { $crate::__::__parse_ty_bounds!{ ( $fixed $prev_gen_args $prev_gen ($_(#[$_($attr)*])*) $ty ) [] // counter for depth between < > pairs [] [$_($rem)*] } }; ( $fixed:tt $prev_gen_args:tt $prev_gen:tt [ $_(,)? $_(#[$_($attr:tt)*])* $ty:ident $_($rem:tt)* ] ) => { $crate::__::__pg_parsed_ty_bounds!{ $fixed $prev_gen_args $prev_gen ($_(#[$_($attr)*])*) $ty [] $_($rem)* } }; ($fixed:tt $gen_args:tt $gen:tt []) => { $crate::__::compile_error!{"unexpected end of generic parameter list"} }; ($fixed:tt $gen_args:tt $gen:tt [$token0:tt $_($token1:tt $_($other:tt)*)?]) => { $crate::__::compile_error!{$crate::__::concat!( "unexpected token(s) in generic parameter list: `", stringify!($token0 $_($token1)?) "`" )} }; } #[doc(hidden)] #[macro_export] macro_rules! __pg_parsed_ty_bounds_ { $( ( $fixed:tt $gen_args:tt $gen:tt $attrs:tt $ty:tt $bound:tt [$err_token $_($rem:tt)*] ) => { $crate::__::compile_error!{$crate::__::concat!( "unexpected `", $crate::__::stringify!($err_token), "` in type parameter declaration", )} }; )* $( ( $fixed:tt [$_($prev_gen_args:tt)*] [$_($prev_gen:tt)*] $attrs:tt $ty:ident [$_($_($bound:tt)+)?] $_(= $default:ty)? $sep $_($rem:tt)* ) => { $crate::__::__parse_in_generics!{ $fixed [ $_($prev_gen_args)* ($ty (fn() -> $crate::__::PhantomData<$ty>,) $_(= $default)?) ] [$_($prev_gen)* ($attrs $ty $_(: $_($bound)+)?)] [$sep $_($rem)*] } }; )* } declare_generics_consuming_macro! { $ __parse_ty_bounds_ = __parse_ty_bounds "bound"; ( ($_($fixed:tt)*) [] $prev:tt [$_(= $_($rem:tt)*)?] ) => { $crate::__::__pg_parsed_ty_bounds!{ $_($fixed)* $prev $_(= $_($rem)*)? } }; $( ( ($_($fixed:tt)*) [] $prev:tt [$sep $_($rem:tt)*] ) => { $crate::__::__pg_parsed_ty_bounds!{ $_($fixed)* $prev $sep $_($rem)* } }; )* $( ($fixed:tt $count:tt [$_($prev:tt)*] [$err_token $_($rem:tt)*]) => { $crate::__::compile_error!{$crate::__::concat!( "unexpected end of bound: `", stringify!($_($prev)* $err_token), "`", )} }; )* } }} declare_parse_generics_macros!{$ [, >] [; where impl]} pub use { __parse_in_generics_ as __parse_in_generics, __pg_parsed_ty_bounds_ as __pg_parsed_ty_bounds, }; macro_rules! declare_pg_cfg_expansion { ($_:tt $( [($deleted_lt_ty_marker_:ident) ($($gp_rule:tt)*) => {$($erase_marker_token:tt)*}] )* ) => { #[doc(hidden)] #[macro_export] macro_rules! __pg_cfg_expansion_ { ( $fixed:tt [$_($prev_gen_args:tt)*] [$gen_arg:tt $_($rem_gen_args:tt)*] [$_($prev_generics:tt)*] [$generic:tt $_($rem_generics:tt)*] $deleted_lt_ty_marker:tt [() $_($rem_cfg:tt)*] ) => { $crate::__::__pg_cfg_expansion!{ $fixed [$_($prev_gen_args)* $gen_arg] [ $_($rem_gen_args)*] [$_($prev_generics)* $generic] [ $_($rem_generics)*] $deleted_lt_ty_marker [$_($rem_cfg)*] } }; $( ( $fixed:tt [$_($prev_gen_args:tt)*] [$gen_arg:tt $_($rem_gen_args:tt)*] [$_($prev_generics:tt)*] [$generic:tt $_($rem_generics:tt)*] $_$deleted_lt_ty_marker_:tt [($($gp_rule)* $_($cfg:tt)+) $_($rem_cfg:tt)*] ) => { #[cfg($_($cfg)+)] $crate::__::__pg_cfg_expansion!{ $fixed [$_($prev_gen_args)* $gen_arg] [ $_($rem_gen_args)*] [$_($prev_generics)* $generic] [ $_($rem_generics)*] $_$deleted_lt_ty_marker_ [$_($rem_cfg)*] } #[cfg(not($_($cfg)+))] $crate::__::__pg_cfg_expansion!{ $fixed [$_($prev_gen_args)*] [ $_($rem_gen_args)*] [$_($prev_generics)*] [ $_($rem_generics)*] $($erase_marker_token)* [$_($rem_cfg)*] } }; )* ( ( $_($callback:ident)::* !($_($callback_args:tt)*) $_($rem:tt)*) $gen_args:tt [] $generics:tt [] $deleted_lt_ty_marker:tt [] // no cfgs left ) => { $_($callback)::* ! { $_($callback_args)* $gen_args $generics $deleted_lt_ty_marker $_($rem)* } }; } }} declare_pg_cfg_expansion!{ $ [(deleted_lt_ty_marker) (const) => {$deleted_lt_ty_marker}] [(deleted_lt_ty_marker) ($__gp:tt) => {[()]}] } pub use __pg_cfg_expansion_ as __pg_cfg_expansion; #[doc(hidden)] #[macro_export] macro_rules! __parse_generics { // angle bracket generics ( $fixed:tt [< $($generics:tt)*] ) => { $crate::__::__parse_in_generics!{ $fixed [] [] [$($generics)*] } }; // square bracket generic params // note: this is accepted so that simple_type_witness // can still parse square bracket generics. ( $fixed:tt [[$($generics:tt)*] $($rem:tt)*] ) => { $crate::__::__parse_in_generics!{ $fixed [] [] [$($generics)*> $($rem)*] } }; // no generics case ( ( $($callback:ident)::* !($($callback_args:tt)*) ) [$($rem:tt)*] ) => { $($callback)::* ! { $($callback_args)* [] [] [] $($rem)* } }; } #[doc(hidden)] #[macro_export] macro_rules! __trailing_comma_for_where_clause { // fallback case (($($macro:ident)::* !($($args:tt)*)) [$($prev:tt)*] [] ) => { $($macro)::* !{$($args)* [$($prev)*] } }; (($($macro:ident)::* !($($args:tt)*)) [$($($prev:tt)+)?] [$(,)? ; $($rem:tt)*] ) => { $($macro)::* !{$($args)* [$($($prev)+,)?] $($rem)* } }; ($fixed:tt [$($prev:tt)*] [$t0:tt $($rem:tt)*]) => { $crate::__trailing_comma_for_where_clause!{ $fixed [$($prev)* $t0] [$($rem)*] } }; } // parses a where clause for an item where the where clause ends at any of: // - `=` // - `{...}` // // The parsed tokens start with `where`, so that these can be parsed: // - there being no where clause // - having a normal where clause // - having a where clause delimited with brackets (e.g: `where[T: u32]`) #[doc(hidden)] #[macro_export] macro_rules! __parse_where_clause_for_item { ($fixed:tt where [$($in_brackets:tt)*]: $($rem:tt)*) => { $crate::__::__parse_where_clause_for_item_inner!{ $fixed [] [] [[$($in_brackets)*]: $($rem)*] } }; // parses the `where [$where_predicates]` syntax that // the simple_type_withness macro started with. ($fixed:tt where [$($in_brackets:tt)*] $($rem:tt)*) => { $crate::__trailing_comma_for_where_clause!{ $fixed [] [$($in_brackets)*; $($rem)*] } }; ($fixed:tt where $($rem:tt)*) => { $crate::__::__parse_where_clause_for_item_inner!{ $fixed [] [] [$($rem)*] } }; // no where clause (($($callback:ident)::* !($($callback_args:tt)*) ) $($rem:tt)*) => { $($callback)::* !{$($callback_args)* [] $($rem)*} }; } declare_generics_consuming_macro! { $ __parse_where_clause_for_item_inner_ = __parse_where_clause_for_item_inner "where clause"; // forward compatibility with `const { ... }` bounds, // dunno how likely const bounds are to be, but why not. ( $fixed:tt [] [$($prev:tt)*] [const {$($braced:tt)*} $($rem:tt)*] ) => { $crate::__::__parse_where_clause_for_item!{ $fixed [] [$($prev)* const {$($braced)*}] [$($rem)*] } }; ( ($($callback:ident)::* !($($callback_args:tt)*) ) [] [$($($prev:tt)+)?] [$(,)? = $($rem:tt)*] ) => { $($callback)::* !{$($callback_args)* [$($($prev)+,)?] = $($rem)*} }; ( ($($callback:ident)::* !($($callback_args:tt)*) ) [] [$($($prev:tt)+)?] [$(,)? {$($braced:tt)*} $($rem:tt)*] ) => { $($callback)::* !{$($callback_args)* [$($($prev)+,)?] {$($braced)*} $($rem)*} }; ($fixed:tt [] $prev:tt []) => { $crate::__::compile_error!{"unexpected end of where clause, expected rest of item"} }; } declare_generics_consuming_macro! { $ __parse_generic_args_with_defaults_ = __parse_generic_args_with_defaults "generic arguments"; ( ($fixed:tt [$($prev_args:tt)*] [$($curr_gen_param:tt $($gen_params_rem:tt)*)?]) [] [$($prev_tokens:tt)*] [, $($rem:tt)*] ) => { $crate::__::__parse_generic_args_with_defaults! { ($fixed [$($prev_args)* $($prev_tokens)*,] [$($($gen_params_rem)*)?]) [] [] [$($rem)*] } }; ( ($fixed:tt [$($prev_args:tt)*] [$($curr_gen_param:tt $($gen_params_rem:tt)*)?]) [] [$($prev_tokens:tt)+] [> $($rem:tt)*] ) => { $crate::__parse_generic_args_with_defaults__finish !{ ($fixed [$($prev_args)* $($prev_tokens)*,] [$($($gen_params_rem)*)?]) $($rem)* } }; ($fixed:tt [] [] [> $($rem:tt)*]) => { $crate::__parse_generic_args_with_defaults__finish !{ $fixed $($rem)* } }; ($fixed:tt [] $prev:tt []) => { $crate::__::compile_error!{"unexpected end of generic arguments"} }; } #[doc(hidden)] #[macro_export] macro_rules! __parse_generic_args_with_defaults__finish { ( ( ( ($($callback:ident)::* !($($callback_args:tt)*) ) $context:expr ) [$($gen_args:tt)*] [ $(( // gen_eff_def is either: // - the default (if the generic parameter has one) // - the name of the generic parameter (if it has no default) (($($gen_eff_def:tt)*) $($__0:tt)*) ( // defined if the generic parameter does not have a default $([$gen_param:tt])? // defined if the generic parameter has a default $(($($__1:tt)*) [$__gen_param:tt])? ) ))* ] ) $($rem:tt)* ) => { $crate::__parse_generic_args_with_defaults__assert_only_defaults! { $context, [$($($gen_param)?)*] } $($callback)::* !{ $($callback_args)* [$($gen_args)* $($($gen_eff_def)* ,)*] $($rem)* } } } #[doc(hidden)] #[macro_export] macro_rules! __parse_generic_args_with_defaults__assert_only_defaults { ( $context:expr, [$($($gen_param:tt)+)?] ) => { $( $crate::__::compile_error!{$crate::__::concat!{ "expected these generic argument(s) for ", $context, " to be passed: " $( , stringify!($gen_param), )", "+ }} )? }; } #[doc(hidden)] #[macro_export] macro_rules! __assert_valid_gen_attr { ( $prev:tt [#[cfg($($tt:tt)*)] $($rem:tt)*]) => { $crate::__assert_valid_gen_attr!{ $prev [$($rem)*] } }; ( [$($prev:tt)*] [#[$($tt:tt)*] $($rem:tt)*]) => { $crate::__assert_valid_gen_attr!{ [$($prev)* #[$($tt)*]] [$($rem)*] } }; ( [$(#[$attr:meta])*] []) => { $crate::__::compile_error!{$crate::__::concat!{ "unsupported attribute(s) on generic parameter(s): " $( ,"`#[", stringify!($attr), "]`", )", "* "\nonly the `#[cfg(...)]` attribute is supported" }} }; } typewit-1.12.1/src/macros/inj_type_fn_macro.rs000064400000000000000000000105621046102023000175250ustar 00000000000000 /// Declares an /// [injective type-level function](crate::type_fn::InjTypeFn) /// /// This macro takes in the exact same syntax as the [`type_fn`] macro. /// /// This macro generates the same items as the `type_fn` macro, /// in addition to implementing [`RevTypeFn`], /// so that the function implements [`InjTypeFn`]. /// /// /// # Example /// /// This macro is also demonstrated in /// `TypeNe::{`[`map`]`, `[`project`]`, `[`unmap`]`, `[`unproject`]`}`. /// /// [`map`]: crate::TypeNe::map /// [`project`]: crate::TypeNe::project /// [`unmap`]: crate::TypeNe::unmap /// [`unproject`]: crate::TypeNe::unproject /// /// ### Basic /// /// ```rust /// use typewit::{CallFn, UncallFn, inj_type_fn}; /// /// // Calls the `ToSigned` function with `u64` as the argument. /// let _: CallFn = 3i64; /// /// // Gets the argument of the `ToSigned` function from the `i8` return value. /// let _: UncallFn = 5u8; /// /// inj_type_fn!{ /// struct ToSigned; /// /// impl u128 => i128; /// impl u64 => i64; /// impl u32 => i32; /// impl u16 => i16; /// impl u8 => i8; /// } /// ``` /// ///
/// ///

/// /// the above `inj_type_fn` macro invocation roughly expands to this code ///

///
/// /// ```rust /// struct ToSigned; /// /// impl ToSigned { /// const NEW: Self = Self; /// } /// /// impl ::typewit::TypeFn for ToSigned { /// type Output = i128; /// } /// /// impl ::typewit::RevTypeFn for ToSigned { /// type Arg = u128; /// } /// /// impl ::typewit::TypeFn for ToSigned { /// type Output = i64; /// } /// /// impl ::typewit::RevTypeFn for ToSigned { /// type Arg = u64; /// } /// /// impl ::typewit::TypeFn for ToSigned { /// type Output = i32; /// } /// /// impl ::typewit::RevTypeFn for ToSigned { /// type Arg = u32; /// } /// /// impl ::typewit::TypeFn for ToSigned { /// type Output = i16; /// } /// /// impl ::typewit::RevTypeFn for ToSigned { /// type Arg = u16; /// } /// /// impl ::typewit::TypeFn for ToSigned { /// type Output = i8; /// } /// /// impl ::typewit::RevTypeFn for ToSigned { /// type Arg = u8; /// } /// ``` ///
/// /// [`type_fn`]: macro@crate::type_fn /// [`TypeFn`]: crate::type_fn::TypeFn /// [`InjTypeFn`]: crate::type_fn::InjTypeFn /// [`RevTypeFn`]: crate::type_fn::RevTypeFn #[macro_export] macro_rules! inj_type_fn { ($($args:tt)*) => { $crate::__type_fn!{ __tyfn_injtypefn_impl $($args)* } } } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_injtypefn_impl { ( ( $(#[$attrs:meta])* $impl:ident[$(($($fn_gen_param:tt)*))*] $ty_arg:ty => $ret_ty:ty where[ $($where_preds:tt)* ] ) $function_name:ident [$(($capt_gen_args:tt $($rem_0:tt)*))*] [ $(($capt_lt:lifetime $($capt_lt_rem:tt)*))* $(($capt_tcp:ident $($capt_tcp_rem:tt)*))* ] where [$($capt_where:tt)*] ) => { $crate::__impl_with_span! { $ty_arg // span ( $(#[$attrs])* #[allow(unused_parens)] ) ( < $($capt_lt $($capt_lt_rem)*,)* $($($fn_gen_param)*,)* $($capt_tcp $($capt_tcp_rem)*,)* > $crate::TypeFn<$ty_arg> ) // for ( $function_name<$($capt_gen_args),*> ) ( where $($capt_where)* $($where_preds)* ) ( type Output = $ret_ty; const TYPE_FN_ASSERTS: () = { let _: $crate::CallInjFn; }; ) } $crate::__impl_with_span! { $ret_ty // span ( $(#[$attrs])* #[allow(unused_parens)] ) ( < $($capt_lt $($capt_lt_rem)*,)* $($($fn_gen_param)*,)* $($capt_tcp $($capt_tcp_rem)*,)* > $crate::type_fn::RevTypeFn<$ret_ty> ) // for ( $function_name<$($capt_gen_args),*> ) ( where $($capt_where)* $($where_preds)* ) ( type Arg = $ty_arg; ) } }; }typewit-1.12.1/src/macros/polymatch.rs000064400000000000000000000124631046102023000160420ustar 00000000000000 /// Match which expands top-level `|` patterns to multiple match arms. /// /// [**examples below**](#examples) /// /// ### Clarification /// /// "top-level `|` patterns" means that the `|` is not inside some other pattern. ///
E.g.: the pattern in `Foo(x) | Bar(x) => ` is a top-level `|` pattern. ///
E.g.: the pattern in `(Foo(x) | Bar(x)) => ` is not a top-level `|` pattern, /// because the `|` is inside parentheses. /// /// # Syntax /// /// This uses a `macro_rules!`-like syntax for the parameters of this macro /// /// ```text /// $matched_expression:expr; /// $( $(|)? $($or_pattern:pat_param)|+ $(if $match_guard:expr)? => $arm_expr:expr ),* /// $(,)? /// ``` /// /// [**example demonstrating all of this syntax**](#full-syntax) /// /// # Examples /// /// ### Basic /// /// ```rust /// assert_eq!(debugify(Ok(3)), "3"); /// assert_eq!(debugify(Err("hello")), r#""hello""#); /// /// fn debugify(res: Result) -> String { /// typewit::polymatch! {res; /// Ok(x) | Err(x) => format!("{:?}", x) /// } /// } /// ``` /// /// The above invocation of `polymatch` expands to: /// /// ```rust /// # assert_eq!(debugify(Ok(3)), "3"); /// # assert_eq!(debugify(Err("hello")), r#""hello""#); /// # /// # fn debugify(res: Result) -> String { /// match res { /// Ok(x) => format!("{:?}", x), /// Err(x) => format!("{:?}", x), /// } /// # } /// ``` /// /// ### Full syntax /// /// Example that uses all of the syntax supported by this macro. /// /// ```rust /// assert_eq!(bar(Foo::Byte(3)), 6); /// assert_eq!(bar(Foo::Byte(9)), 18); /// assert_eq!(bar(Foo::Byte(10)), 10); /// /// assert_eq!(bar(Foo::U16(3)), 6); /// assert_eq!(bar(Foo::U16(9)), 18); /// assert_eq!(bar(Foo::U16(10)), 10); /// /// assert_eq!(bar(Foo::U32(3)), 0); /// /// assert_eq!(bar(Foo::Long(3)), 0); /// /// enum Foo { /// Byte(u8), /// U16(u16), /// U32(u32), /// Long(u64), /// } /// /// const fn bar(foo: Foo) -> u64 { /// typewit::polymatch! {foo; /// // top-level `|` patterns generate a match arm for every alternate pattern /// | Foo::Byte(x) /// | Foo::U16(x) /// if x < 10 /// => (x as u64) * 2, /// /// Foo::Byte(x) | Foo::U16(x) => { x as u64 } /// /// // `|` inside patterns behaves like in regular `match` expressions /// (Foo::U32(_) | Foo::Long(_)) => 0 /// } /// } /// ``` /// /// The above invocation of `polymatch` expands to: /// ```rust /// # assert_eq!(bar(Foo::Byte(3)), 6); /// # assert_eq!(bar(Foo::Byte(9)), 18); /// # assert_eq!(bar(Foo::Byte(10)), 10); /// # /// # assert_eq!(bar(Foo::U16(3)), 6); /// # assert_eq!(bar(Foo::U16(9)), 18); /// # assert_eq!(bar(Foo::U16(10)), 10); /// # /// # assert_eq!(bar(Foo::U32(3)), 0); /// # /// # assert_eq!(bar(Foo::Long(3)), 0); /// # enum Foo { /// # Byte(u8), /// # U16(u16), /// # U32(u32), /// # Long(u64), /// # } /// # /// # const fn bar(foo: Foo) -> u64 { /// match foo { /// Foo::Byte(x) if x < 10 => (x as u64) * 2, /// Foo::U16(x) if x < 10 => (x as u64) * 2, /// /// Foo::Byte(x) => { x as u64 } /// Foo::U16(x) => { x as u64 } /// /// (Foo::U32(_) | Foo::Long(_)) => 0 /// } /// # } /// ``` /// #[macro_export] macro_rules! polymatch { ($matching:expr; $($match_arms:tt)*) => { $crate::__polymatch!{($matching) () $($match_arms)*} }; ($($tt:tt)*) => { $crate::__::compile_error!{"expected arguments to be `matched expression; match arms`"} }; } #[doc(hidden)] #[macro_export] macro_rules! __polymatch { // Parsing match like syntax ( ($matching:expr) ( $( ($($pattern:tt)*) => ($expr:expr) )* ) // Nothing left to parse $(,)? ) => {{ #[allow(unused_parens)] match $matching { $($($pattern)* => $expr,)* } }}; ( $fixed:tt $prev_branch:tt $(|)? $($pattern:pat_param)|+ $( if $guard:expr )? => $expr:expr $(,$($rem:tt)*)? ) => {{ $crate::__polymatch__handle_guard!{ $fixed $prev_branch (($($pattern)+) => $expr) ($($guard)?) ($($($rem)*)?) } }}; ( $fixed:tt $prev_branch:tt $(|)? $($pattern:pat_param)|+ $( if $guard:expr )? => $expr:block $($rem:tt)* ) => {{ $crate::__polymatch__handle_guard!{ $fixed $prev_branch (($($pattern)+) => $expr) ($($guard)?) ($($rem)*) } }}; } #[doc(hidden)] #[macro_export] macro_rules! __polymatch__handle_guard { ( $fixed:tt ( $($prev_branch:tt)* ) (($($pattern:tt)+) => $expr:tt) () ($($rem:tt)*) ) => { $crate::__polymatch!{ $fixed ( $($prev_branch)* $(($pattern) => ($expr))* ) $($rem)* } }; ( $fixed:tt ( $($prev_branch:tt)* ) (($($pattern:tt)+) => $expr:tt) ($guard:expr) ($($rem:tt)*) ) => { $crate::__polymatch!{ $fixed ( $($prev_branch)* $(($pattern if $guard) => ($expr))* ) $($rem)* } }; } typewit-1.12.1/src/macros/simple_type_witness_macro.rs000064400000000000000000000710421046102023000213270ustar 00000000000000/// Declares a [type witness](crate#what-are-type-witnesses) enum. /// #[doc = explain_type_witness!()] /// /// [**examples below**](#examples) /// /// # Generated items /// /// This macro always generates: /// /// - An enum with tuple variants, each of which has a single [`TypeEq`] field. /// /// - Impls of [`Copy`] and [`Clone`] for the enum. /// /// - An impl of [`TypeWitnessTypeArg`] for the enum. /// /// - An impl of [`MakeTypeWitness`] for each variant of the enum. /// /// Additional trait impls are generated when the [`derive(...)`](#derive) syntax is used. /// /// ### Derivation /// /// These impls are generated if you opt into them with the [`derive(...)`](#derive) syntax: /// /// - `Debug` /// - `PartialEq` /// - `Eq` /// - `PartialOrd` /// - `Ord` /// - `Hash` /// /// As opposed to `#[derive(...))]`-generated implementations, /// these impls don't require type parameters to implement the derived trait. /// /// This macro always implements `Copy` and `Clone` for the declared type witness, /// `derive(Copy, Clone)` does nothing. /// /// # Syntax /// /// This macro takes an enum-like syntax: /// ```text /// $(#[$enum_meta:meta])* /// $(derive($($derive:ident),* $(,)?)))? /// $vis:vis enum $enum:ident $(<$($generics:generics_param),* $(,)?>)? /// $(where $($where:where_predicate),* $(,)? )? /// { /// $( /// $(#[$variant_meta:meta])* /// $variant:ident $(<$($var_gen_args:generic_arg)*>)? /// // additional bounds for the MakeTypeWitness impl that constructs this variant. /// $(where $($vari_where:where_predicate)*)? /// // the type that this variant requires the /// // implicit `__Wit` type parameter to be. /// = $witnessed_ty:ty /// ),* /// $(,)? /// } /// ``` /// /// `<$($var_gen_args:generic_arg)*>` /// (optional parameter)[(example usage)](#var_gen_args-example): /// this parameter overrides the generic arguments of the enum in its /// [`MakeTypeWitness`] implementation. /// /// /// `derive($($derive:ident),* $(,)?)`(optional parameter)[(example)](#derive-example): /// supports deriving the traits listed in the [derivation](#derivation) section /// /// `#[cfg(...)]` attributes on variants are copied to their respective /// [`MakeTypeWitness`] impls. /// /// Generic parameters support the `#[cfg(...)]` attribute, /// no other attribute is supported. /// /// Defaults for generic parameters are only used /// as the default value of [`$var_gen_args`](#var_gen_args-param) /// [(example usage)](#var_gen_args-example) . /// ///
/// /// Soft-deprecated older syntax /// /// /// This macro originally required the following syntax, /// which is soft-deprecated, and will be supported for the rest of `"1.*"` versions. /// /// ```text /// $(#[$enum_meta:meta])* /// // Allows deriving some traits without the bounds that /// // standard derives add to type parameters. /// $(derive($($derive:ident),* $(,)?)))? /// $vis:vis enum $enum:ident $([$($generics:tt)*])? /// // The where clause of the enum /// $(where[$($where:tt)*])? /// { /// $( /// $(#[$variant_meta:meta])* /// $variant:ident $([$($var_gen_args:tt)*])? /// // additional bounds for the MakeTypeWitness impl that constructs this variant. /// $(where[$($vari_where:tt)*])? /// // the type this variant requires the implicit `__Wit` type parameter to be. /// = $witnessed_ty:ty /// ),* /// $(,)? /// } /// ``` /// ///
/// /// ### Limitations /// /// /// When used in Rust versions prior to 1.59.0, /// type witnesses declared with this macro cannot have const parameters, /// because this macro always adds a `__Wit` type parameter after all generic parameters, /// and those old versions don't allow type parameters after const parameters. /// /// # Examples /// /// ### Basic /// /// This example demonstrates a basic usage of this macro /// /// ```rust /// use typewit::MakeTypeWitness; /// /// assert_eq!(do_it(1), 1); /// assert_eq!(do_it(2), 4); /// assert_eq!(do_it(3), 9); /// assert_eq!(do_it("foo"), 3); /// assert_eq!(do_it("hello"), 5); /// /// const fn do_it<'a, T>(arg: T) -> usize /// where /// Witness<'a, T>: MakeTypeWitness, /// { /// match MakeTypeWitness::MAKE { /// // `te` is a `TypeEq`, `te.to_right(arg)` goes from `T` to `u8.` /// Witness::U8(te) => (te.to_right(arg) as usize).pow(2), /// /// // `te` is a `TypeEq`, `te.to_right(arg)` goes from `T` to `&'a str.` /// Witness::Str(te) => te.to_right(arg).len(), /// } /// } /// /// typewit::simple_type_witness! { /// // Declares an `enum Witness<'a, __Wit>`, /// // the `__Wit` type parameter is added after all generics. /// enum Witness<'a> { /// // This variant requires `__Wit == u8` /// U8 = u8, /// // This variant requires `__Wit == &'a str` /// Str = &'a str, /// } /// } /// ``` /// the above invocation of `simple_type_witness` effectively generates this code: /// ```rust /// enum Witness<'a, __Wit> { /// U8(typewit::TypeEq<__Wit, u8>), /// Str(typewit::TypeEq<__Wit, &'a str>), /// } /// impl<'a, __Wit> typewit::TypeWitnessTypeArg for Witness<'a, __Wit> { /// type Arg = __Wit; /// } /// impl<'a> typewit::MakeTypeWitness for Witness<'a, u8> { /// const MAKE: Self = Self::U8(typewit::TypeEq::NEW); /// } /// impl<'a> typewit::MakeTypeWitness for Witness<'a, &'a str> { /// const MAKE: Self = Self::Str(typewit::TypeEq::NEW); /// } /// ``` /// (consult the [generated items] section for all the generated impls) /// /// ### where clauses /// /// This example demonstrates a variant with a where clause. /// ```rust /// # use std::fmt::Debug; /// typewit::simple_type_witness! { /// // Declares an `enum Witness<'a, T, __Wit>`, /// // the `__Wit` type parameter is added after all generics. /// #[non_exhaustive] /// enum Witness<'a, T: 'a> /// where /// T: 'a + Debug /// { /// // This variant requires `__Wit == T`. /// // The `MakeTypeWitness` impl for this variant also requires `T: Copy`. /// #[cfg(feature = "foo")] /// Value where T: Copy = T, /// /// // This variant requires `__Wit == &'a T` /// Ref = &'a T, /// } /// } /// ``` /// the above invocation of `simple_type_witness` effectively generates this code: /// ```rust /// # use core::fmt::Debug; /// # /// #[non_exhaustive] /// enum Witness<'a, T: 'a, __Wit: ?Sized> /// where /// T: 'a + Debug, /// { /// #[cfg(feature = "foo")] /// Value(typewit::TypeEq<__Wit, T>), /// /// Ref(typewit::TypeEq<__Wit, &'a T>), /// } /// /// impl<'a, T: 'a, __Wit: ?Sized> typewit::TypeWitnessTypeArg for Witness<'a, T, __Wit> /// where /// T: 'a + Debug, /// { /// type Arg = __Wit; /// } /// /// #[cfg(feature = "foo")] /// impl<'a, T: 'a> typewit::MakeTypeWitness for Witness<'a, T, T> /// where /// T: 'a + Debug + Copy, /// { /// const MAKE: Self = Self::Value(typewit::TypeEq::NEW); /// } /// /// impl<'a, T: 'a> typewit::MakeTypeWitness for Witness<'a, T, &'a T> /// where /// T: 'a + Debug, /// { /// const MAKE: Self = Self::Ref(typewit::TypeEq::NEW); /// } /// ``` /// (consult the [generated items] section for all the generated impls) /// /// /// ### `$var_gen_args` parameter /// /// This example shows what the `$var_gen_args` parameter does, /// as well as how generic parameter defaults relate to it. /// /// ([this example requires Rust 1.59.0](#const-parameter-limitation)) /// #[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")] #[cfg_attr(feature = "rust_1_61", doc = "```rust")] /// typewit::simple_type_witness! { /// // Declares an `enum Foo`, /// // the `__Wit` type parameter is added after all generics. /// // /// // The defaults for generic parameters are only used /// // as the default value of the generic arguments of variants. /// enum Foo { /// // This variant requires `__Wit == u64`. /// // /// // The `<(), 3>` here /// // replaces `impl MakeTypeWitness for Foo` /// // with `impl MakeTypeWitness for Foo<(), 3, u64>`. /// // Using `<(), 3>` allows the `T` and `N` type parameters to be inferred /// // when the `MakeTypeWitness` impl for `Foo<_, _, u64>` is used. /// U64<(), 3> = u64, /// // This variant requires `__Wit == bool`. /// // /// // The `<>` here uses the defaults for the generic arguments to /// // replace `impl MakeTypeWitness for Foo` /// // with `impl MakeTypeWitness for Foo`. /// Bool<> = bool, /// // This variant requires `__Wit == [T; N]`. /// Array = [T; N], /// } /// } /// ``` /// the above effectively expands to this: #[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")] #[cfg_attr(feature = "rust_1_61", doc = "```rust")] /// enum Foo { /// U64(typewit::TypeEq<__Wit, u64>), /// Bool(typewit::TypeEq<__Wit, bool>), /// Array(typewit::TypeEq<__Wit, [T; N]>), /// } /// impl typewit::TypeWitnessTypeArg for Foo { /// type Arg = __Wit; /// } /// impl typewit::MakeTypeWitness for Foo<(), 3, u64> { /// const MAKE: Self = Self::U64(typewit::TypeEq::NEW); /// } /// impl typewit::MakeTypeWitness for Foo { /// const MAKE: Self = Self::Bool(typewit::TypeEq::NEW); /// } /// impl typewit::MakeTypeWitness for Foo { /// const MAKE: Self = Self::Array(typewit::TypeEq::NEW); /// } /// ``` /// (consult the [generated items] section for all the generated impls) /// /// /// ### Derives /// /// This example demonstrates derivation of all the supported traits /// using the `derive(...)` syntax (as opposed to the `#[derive(...)]` attribute). /// /// ```rust /// use typewit::{MakeTypeWitness, TypeEq}; /// /// struct NoImpls; /// /// assert_eq!(Witness::::MAKE, Witness::::MAKE); /// /// // Witness doesn't require its type parameters to impl any traits in its derives. /// // The standard derives require that type parameters impl the derived trait, /// // so this comparison wouldn't work (because `NoImpls` doesn't impl `PartialEq`). /// assert_eq!(Witness::::MAKE, Witness::NoImp(TypeEq::NEW)); /// /// typewit::simple_type_witness! { /// // Declares an `enum Witness<__Wit>`, /// // the `__Wit` type parameter is added after all generics. /// derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash) /// enum Witness { /// U8 = u8, /// NoImp = NoImpls, /// } /// } /// ``` /// /// /// [`TypeEq`]: crate::TypeEq /// [`TypeWitnessTypeArg`]: crate::TypeWitnessTypeArg /// [`MakeTypeWitness`]: crate::MakeTypeWitness /// [generated items]: #generated-items #[macro_export] macro_rules! simple_type_witness { ( $(#[$enum_meta:meta])* $(derive($($derive:ident),* $(,)?))? $(pub $(($($pub:tt)*))?)? enum $enum:ident $($rem:tt)* ) => { $crate::__parse_generics!{ ($crate::__stw_with_parsed_generics!( ( $(#[$enum_meta])* derive($($($derive)*)?) $(pub $(($($pub)*))? )? enum $enum ) $enum )) [$($rem)*] } }; } #[doc(hidden)] #[macro_export] macro_rules! __stw_with_parsed_generics { ( ($($prev_args:tt)*) $enum:ident [$(($gen_arg:tt ($($gen_phantom:tt)*) $( = $($gen_def:tt)* )? ))*] [$(($($generics:tt)*))*] $deleted_markers:tt $($rem:tt)* ) => { $crate::__parse_where_clause_for_item! { ($crate::__stw_with_parsed_where ! ( ( $($prev_args)* [$($($generics)*,)*] [ $($gen_arg,)* ] ) [ $enum [ $(( ( $(($($gen_def)*))? ($gen_arg) ) ( $(($($gen_def)*))? [$gen_arg] ) ))* ] ] )) $($rem)* } }; } #[doc(hidden)] #[macro_export] macro_rules! __stw_with_parsed_where { ( ($($prev_args:tt)*) $vari_vars:tt $where_clause:tt {$($variants:tt)*} ) => { $crate::__::__stw_parse_variants!{ ($($prev_args)* where $where_clause) $vari_vars [] [$($variants)*] } } } macro_rules! declare__stw_parse_variants { ($_:tt ($($vari_params:tt)*) ($($vari_output:tt)*) $variant_:ident) => { #[doc(hidden)] #[macro_export] macro_rules! __stw_parse_variants_ { ( ($_($fixed:tt)*) $vari_vars:tt // fast path for enums with no attributes on variants other than docs [$_(($variant:ident ($_(#[doc $_($docs:tt)*])*) $_($rem_vari:tt)*))*] [$_(,)*] )=>{ $crate::__stw_with_parsed_args! { $_($fixed)* { $_(($variant ($_(#[doc $_($docs)*])*) $_($rem_vari)*))* } } }; ( $fixed:tt $vari_vars:tt [ ($pvariant:ident ($_($pattrs:tt)*) $_($prem:tt)*) $_($variants:tt)* ] [$_(,)*] )=>{ $crate::__stw_parse_variants_attrs!{ $fixed [/*prev variants*/] [ ($pvariant ($_($pattrs)*) $_($prem)*) $_($variants)*] [/*prev attrs of variant*/] [/*prev cfgs of variant*/] [$_($pattrs)*] } }; ( $fixed:tt $vari_vars:tt [$_($prev:tt)*] [$($vari_params)* = $var_type:ty $_(, $_($rem:tt)*)?] )=>{ $crate::__::__stw_parse_variants!{ $fixed $vari_vars // The four token trees in the parentheses here are: // ( // variant_name // ($($attributes:tt)*) // (replacement_for_Self) // [where_clause_for_variant] // withnessed_type // ) [$_($prev)* ($($vari_output)* () [] $var_type)] [$_($_($rem)*)?] } }; ( $fixed:tt [$enum:ident $gen_with_defs:tt] $prev:tt [$($vari_params)* < $_($rem:tt)*] )=>{ $crate::__::__parse_generic_args_with_defaults! { ( ( ($crate::__stw_parse_variant_Self_ty!( $fixed [$enum $gen_with_defs] $prev ($($vari_output)*) )) $crate::__::concat!( "`", $crate::__::stringify!($_ $variant_), "` variant", ) ) [] $gen_with_defs ) [] [] [$_($rem)*] } }; ( $fixed:tt [$enum:ident $gen_with_defs:tt] $prev:tt [$($vari_params)* [$_($SelfArgs:tt)*] $_($rem:tt)*] )=>{ $crate::__::__parse_generic_args_with_defaults! { ( ( ($crate::__stw_parse_variant_Self_ty!( $fixed [$enum $gen_with_defs] $prev ($($vari_output)*) )) $crate::__::concat!( "`", $crate::__::stringify!($_ $variant_), "` variant", ) ) [] $gen_with_defs ) [] [] [$_($SelfArgs)* > $_($rem)*] } }; ($fixed:tt $vari_vars:tt $prev:tt [$($vari_params)* where $_($rem:tt)*])=>{ $crate::__parse_where_clause_for_item!{ ($crate::__stw_parsed_variant_with_where_clause!( $fixed $vari_vars $prev [$($vari_output)* ()] )) where $_($rem)* } }; } }; } declare__stw_parse_variants!{ $ ($(#[$($vari_attr:tt)*])* $variant:ident) ($variant ($(#[$($vari_attr)*])*)) variant } pub use __stw_parse_variants_ as __stw_parse_variants; #[doc(hidden)] #[macro_export] macro_rules! __stw_parse_variants_attrs { ( ($($fixed:tt)*) [$($variants:tt)*] [] [] [] [] )=>{ $crate::__stw_with_parsed_args! { $($fixed)* { $($variants)* } } }; ( $fixed:tt $prev_vari:tt $next_vari:tt $prev_attrs:tt [$($prev_cfgs:tt)*] [#[cfg($($cfg:tt)*)] $($rest_attrs:tt)*] ) => { $crate::__stw_parse_variants_attrs! { $fixed $prev_vari $next_vari $prev_attrs [$($prev_cfgs)* ($($cfg)*)] [$($rest_attrs)*] } }; ( $fixed:tt $prev_vari:tt $next_vari:tt [$($prev_attrs:tt)*] $prev_cfgs:tt [#[$($attr:tt)*] $($rest_attrs:tt)*] ) => { $crate::__stw_parse_variants_attrs! { $fixed $prev_vari $next_vari [$($prev_attrs)* #[$($attr)*]] $prev_cfgs [$($rest_attrs)*] } }; // none of the attributes of the variant were cfg ( $fixed:tt [$($prev_vari:tt)*] [ $curr_vari:tt $( ($nvariant:ident ($($nattrs:tt)*) $($nrem:tt)*) $($rem_vari:tt)* )? ] $prev_attrs:tt [] [] ) => { $crate::__stw_parse_variants_attrs! { $fixed [$($prev_vari)* $curr_vari] [ $(($nvariant ($($nattrs)*) $($nrem)*) $($rem_vari)*)? ] [] [] [$($($nattrs)*)?] } }; // some of the attributes of the variant were cfg ( $fixed:tt [$($prev_vari:tt)*] [ ($cvariant:ident $__cattrs:tt $($crem:tt)*) $( ($nvariant:ident ($($nattrs:tt)*) $($nrem:tt)*) $($rem_vari:tt)* )? ] [$($prev_attrs:tt)*] [$(($($cfg:tt)*))+] [] ) => { #[cfg(all($($($cfg)*)+))] $crate::__stw_parse_variants_attrs! { $fixed [$($prev_vari)* ($cvariant ($($prev_attrs)*) $($crem)*) ] [ $(($nvariant ($($nattrs)*) $($nrem)*) $($rem_vari)*)? ] [] [] [$($($nattrs)*)?] } #[cfg(not(all($($($cfg)*)+)))] $crate::__stw_parse_variants_attrs! { $fixed [$($prev_vari)*] [ $(($nvariant ($($nattrs)*) $($nrem)*) $($rem_vari)*)? ] [] [] [$($($nattrs)*)?] } }; } #[doc(hidden)] #[macro_export] macro_rules! __stw_parse_variant_Self_ty { ( $fixed:tt [$enum:ident $($rem_vars:tt)*] $prev:tt ($($vari_prev:tt)*) [$($SelfTy:tt)*] where $($rem:tt)* )=>{ $crate::__parse_where_clause_for_item!{ ($crate::__stw_parsed_variant_with_where_clause!( $fixed [$enum $($rem_vars)*] $prev [$($vari_prev)* ($enum < $($SelfTy)*)] )) where $($rem)* } }; ( $fixed:tt [$enum:ident $($rem_vars:tt)*] [$($prev:tt)*] ($($vari_prev:tt)*) [$($SelfTy:tt)*] = $var_type:ty $(, $($rem:tt)*)? )=>{ $crate::__::__stw_parse_variants!{ $fixed [$enum $($rem_vars)*] [$($prev)* ($($vari_prev)* ($enum < $($SelfTy)*) [] $var_type)] [$($($rem)*)?] } }; } #[doc(hidden)] #[macro_export] macro_rules! __stw_parsed_variant_with_where_clause { ( $fixed:tt $vari_vars:tt [$($prev:tt)*] [$($vari_prev:tt)*] $where_clause:tt = $var_type:ty $(, $($rem:tt)*)? ) => { $crate::__::__stw_parse_variants!{ $fixed $vari_vars [$($prev)* ($($vari_prev)* $where_clause $var_type)] [$($($rem)*)?] } } } #[doc(hidden)] #[macro_export] macro_rules! __stw_with_parsed_args { ( $(# $enum_meta:tt)* derive $derive:tt $vis:vis enum $enum:ident $generics:tt $gen_args:tt where $where:tt { $($variant_args:tt)* } ) => { $crate::__stw_top_items!{ $(# $enum_meta)* $vis enum $enum $generics $gen_args where $where { $($variant_args)* } } $crate::__stw_derive_dispatcher!{ derive $derive enum $enum $generics $gen_args where $where { $($variant_args)* } } $( $crate::__stw_make_type_witness_impl!{ $enum $generics $gen_args where $where $variant_args } )* } } #[doc(hidden)] #[macro_export] macro_rules! __stw_top_items { ( $(# $enum_meta:tt)* $vis:vis enum $enum:ident[$($generics:tt)*] [$($gen_args:tt)*] where [$($where:tt)*] { $(( $variant:ident ($(#[$variant_meta:meta])*) ($($SelfTy:tt)*) $vari_where:tt $witnessed_ty:ty ))* } ) => { $(#$enum_meta)* $vis enum $enum <$($generics)* __Wit: ?Sized> where $($where)* { $( $(#[$variant_meta])* $variant($crate::TypeEq<__Wit, $witnessed_ty>), )* } impl<$($generics)* __Wit: ?Sized> $crate::__::Copy for $enum<$($gen_args)* __Wit> where $($where)* {} impl<$($generics)* __Wit: ?Sized> $crate::__::Clone for $enum<$($gen_args)* __Wit> where $($where)* { fn clone(&self) -> Self { *self } } impl<$($generics)* __Wit: ?Sized> $crate::TypeWitnessTypeArg for $enum<$($gen_args)* __Wit> where $($where)* { type Arg = __Wit; } }; } #[doc(hidden)] #[macro_export] macro_rules! __stw_derive_dispatcher { ( derive($($trait:ident)*) enum $enum:ident $generics:tt $gen_args:tt where $where:tt $variant_args:tt ) => { $( $crate::__stw_derive_dispatcher_inner!{ $trait $enum $generics $gen_args where $where $variant_args } )* } } #[doc(hidden)] #[macro_export] macro_rules! __stw_derive_dispatcher_inner { ( $trait:ident $enum:ident[$($generics:tt)*] [$($gen_args:tt)*] where [$($where:tt)*] {$(($variant:ident $($rem:tt)*))*} ) => { $crate::__stw_single_derive!{ ( impl<$($generics)* __Wit: ?Sized> $enum<$($gen_args)* __Wit> where $($where)* ) ( impl<$($generics)* __Wit: ?Sized> $crate::__::$trait for $enum<$($gen_args)* __Wit> where $($where)* ) $trait [$($variant)*] } } } #[doc(hidden)] #[macro_export] macro_rules! __stw_single_derive { ($inh_header:tt ($($impl_header:tt)*) Debug [$($variant:ident)*]) => { $($impl_header)* { fn fmt(&self, f: &mut $crate::__::Formatter<'_>) -> $crate::__::FmtResult { f.write_str(match self { $(Self::$variant{..} => stringify!($variant),)* }) } } }; ($inh_header:tt ($($impl_header:tt)*) PartialEq [$($variant:ident)*]) => { $($impl_header)* { fn eq(&self, other: &Self) -> $crate::__::bool { $crate::__::discriminant(self) == $crate::__::discriminant(other) } } }; (($($inh_header:tt)*) ($($impl_header:tt)*) PartialOrd [$($variant:ident)*]) => { $($inh_header)* { const fn __variant_number(&self) -> usize { mod number { enum __Number__ { $($variant,)* } $( pub const $variant: $crate::__::usize = __Number__::$variant as _; )* } match self { $(Self::$variant{..} => number::$variant,)* } } } $($impl_header)* { fn partial_cmp(&self, other: &Self) -> $crate::__::Option<$crate::__::Ordering> { $crate::__::PartialOrd::partial_cmp( &self.__variant_number(), &other.__variant_number(), ) } } }; ($inh_header:tt ($($impl_header:tt)*) Ord [$($variant:ident)*]) => { $($impl_header)* { fn cmp(&self, other: &Self) -> $crate::__::Ordering { $crate::__::Ord::cmp( &self.__variant_number(), &other.__variant_number(), ) } } }; ($inh_header:tt ($($impl_header:tt)*) Eq [$($variant:ident)*]) => { $($impl_header)* { } }; ($inh_header:tt ($($impl_header:tt)*) Hash [$($variant:ident)*]) => { $($impl_header)* { fn hash(&self, state: &mut H) { $crate::__::Hash::hash(&$crate::__::discriminant(self), state) } } }; // this is always implemented ($inh_header:tt $impl_header:tt Copy $variants:tt) => {}; // this is always implemented ($inh_header:tt $impl_header:tt Clone $variants:tt) => {}; ($inh_header:tt $impl_header:tt $derive:ident $variants:tt) => { $crate::__::compile_error!{$crate::__::concat!{ "The `simple_type_witness` macro does not support deriving `", $crate::__::stringify!($derive), "`.\n", "help: You could try using `#[derive(", $crate::__::stringify!($derive), ")]`.", }} }; } #[doc(hidden)] #[macro_export] macro_rules! __stw_make_type_witness_impl { ( $enum:ident[$($generics:tt)*] [$($gen_args:tt)*] where [$($where:tt)*] ( $variant:ident $attrs:tt ($( $($SelfTy:tt)+ )?) [$($vari_where:tt)*] $witnessed_ty:ty ) ) => { $crate::__impl_with_span! { $variant // span () // attributes on impl block ( <$($generics)* __Wit: ?Sized> $crate::MakeTypeWitness ) // for ( $crate::__first_ty!( $($($SelfTy)+ $witnessed_ty>,)? $enum<$($gen_args)* $witnessed_ty>, ) ) ( where Self: $crate::__::Identity>, $($where)* $($vari_where)* ) ( const MAKE: Self = Self::$variant($crate::TypeEq::NEW); ) } } } #[doc(hidden)] #[macro_export] macro_rules! __first_ty { ($first:ty, $($rem:tt)*) => { $first } } typewit-1.12.1/src/macros/type_fn_macro.rs000064400000000000000000000404041046102023000166630ustar 00000000000000/// Declares a type-level function (struct that implements [`TypeFn`](crate::TypeFn)) /// /// [**examples below**](#examples) /// /// # Syntax /// /// This section uses a `macro_rules!`-like syntax for /// the parameters that `type_fn` takes /// ```text /// $(#[$attrs:meta])* /// $vis:vis struct $struct_name:ident $(< $struct_generics:generic_params >)? /// $( where $struct_where_predicates:where_predicates )?; /// /// $( /// $(#[$impl_attrs:meta])* /// impl $(<$fn_generics:generic_params>)? $argument_type:ty => $return_type:ty /// $( where $fn_where_predicates:where_predicates )? /// );+ /// /// $(;)? /// ``` /// /// `:where_predicates` is a sequence of constraints. /// e.g: `T: Foo, 'a: 'b, U: 'b`. /// /// `:generic_params` is a list of generic parameter declarations. /// e.g: `'a, T, #[cfg(feature = "hi")] U, const N: usize`. /// /// Generic parameters support the `#[cfg(...)]` attribute, /// no other attribute is supported. /// /// # Generated code /// /// This macro generates: /// /// - The struct declaration passed to the macro /// /// - A `NEW` associated constant for constructing the struct /// /// - Impls of [`TypeFn`] for the generated struct corresponding to /// each `... => ...` argument. /// /// If the struct has any lifetime or type parameters /// (even if disabled by `#[cfg(...)]` attributes), /// it has a private field, /// and requires using its `NEW` associated constant to be instantiated. /// If it has no type or lifetime parameters, the struct is a unit struct. /// /// # Examples /// /// This macro is also demonstrated in [`TypeEq::project`], [`TypeEq::map`], /// and the [Indexing polymorphism](crate#example-uses-type-fn) root module example. /// /// ### Basic /// /// ```rust /// use typewit::CallFn; /// /// let item: CallFn> = "hello"; /// let _: &'static str = item; /// assert_eq!(item, "hello"); /// /// // Declares `struct FnIterItem`, /// // a type-level function from `I` to `::Item` /// typewit::type_fn!{ /// struct FnIterItem; /// /// impl I => I::Item /// } /// ``` /// /// ### All syntax /// /// Demonstrates all the syntax that this macro accepts and what it expands into: /// #[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")] #[cfg_attr(feature = "rust_1_61", doc = "```rust")] /// typewit::type_fn! { /// /// Hello /// pub struct Foo<'a, T: IntoIterator = Vec, #[cfg(any())] const N: usize = 3> /// where T: Clone; /// /// /// docs for impl /// #[cfg(all())] /// impl<'b: 'a, U, #[cfg(all())] const M: usize> /// [&'b U; M] => ([&'b U; M], T::IntoIter) /// where /// U: 'static, /// u32: From; /// /// /// docs for another impl /// impl () => T::Item /// } /// ``` /// the above macro invocation generates code equivalent to this: #[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")] #[cfg_attr(feature = "rust_1_61", doc = "```rust")] /// use typewit::TypeFn; /// /// use core::marker::PhantomData; /// /// /// Hello /// // The `const N: usize = 3` param is removed by the `#[cfg(any()))]` attribute /// pub struct Foo<'a, T: IntoIterator = Vec>( /// PhantomData<(&'a (), fn() -> T)> /// ) where T: Clone; /// /// impl<'a, T: IntoIterator> Foo<'a, T> /// where /// T: Clone, /// { /// pub const NEW: Self = Self(PhantomData); /// } /// /// /// docs for impl /// #[cfg(all())] /// impl<'a, 'b: 'a, U, T: IntoIterator, #[cfg(all())] const M: usize> /// TypeFn<[&'b U; M]> /// for Foo<'a, T> /// where /// T: Clone, /// U: 'static, /// u32: From /// { /// type Output = ([&'b U; M], T::IntoIter); /// } /// /// /// docs for another impl /// impl<'a, T: IntoIterator> TypeFn<()> for Foo<'a, T> /// where /// T: Clone, /// { /// type Output = T::Item; /// } /// /// ``` /// /// [`TypeFn`]: crate::TypeFn /// [`TypeEq::project`]: crate::TypeEq::project /// [`TypeEq::map`]: crate::TypeEq::map #[macro_export] macro_rules! type_fn { ($($args:tt)*) => { $crate::__type_fn!{ __tyfn_typefn_impl $($args)* } } } #[doc(hidden)] #[macro_export] macro_rules! __type_fn { ( $typefn_impl_callback:ident $(#[$attrs:meta])* $vis:vis struct $struct_name:ident < $($rem:tt)* ) => { $crate::__::__parse_in_generics! { ($crate::__tyfn_parsed_capture_generics !(( $typefn_impl_callback $(#[$attrs])* $vis struct $struct_name ))) [] [] [$($rem)*] } }; ( $typefn_impl_callback:ident $(#[$attrs:meta])* $vis:vis struct $struct_name:ident $($rem:tt)* ) => { $crate::__trailing_comma_for_where_clause!{ ($crate::__tyfn_parsed_capture_where! ( ( $typefn_impl_callback $(#[$attrs])* $vis struct $struct_name [] [] [] ) )) [] [$($rem)*] } }; ($($rem:tt)*) => { $crate::__::compile_error!{ "invalid argument for `type_fn` macro\n\ expected struct declaration followed by type-level function definitions" } }; } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_parsed_capture_generics { ( ($($struct_stuff:tt)*) $capture_gen_args:tt $capture_generics:tt $deleted_markers:tt where $($rem:tt)* ) => { $crate::__trailing_comma_for_where_clause!{ ($crate::__tyfn_parsed_capture_where! ( ( $($struct_stuff)* $capture_gen_args $capture_generics $deleted_markers ) )) [] [$($rem)*] } }; ( ($($struct_stuff:tt)*) $capture_gen_args:tt $capture_generics:tt $deleted_markers:tt ;$($rem:tt)* ) => { $crate::__tyfn_parsed_capture_where! { ( $($struct_stuff)* $capture_gen_args $capture_generics $deleted_markers ) [] $($rem)* } }; ( $struct_stuff:tt $capture_gen_args:tt $capture_generics:tt $deleted_markers:tt $($first_token:tt $($rem:tt)*)? ) => { $crate::__::compile_error!{$crate::__::concat!( "expected `;` after struct definition", $( ", found `" $crate::__::stringify!($first_token), "`")? )} }; } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_parsed_capture_where { ( ($($struct_stuff:tt)*) $captures_where:tt $($fns:tt)+ ) => { $crate::__tyfn_parse_fns! { ( $($struct_stuff)* captures_where $captures_where ) [] [$($fns)*] [$($fns)*] } }; ( ($($struct_stuff:tt)*) [impl $($fns:tt)*] ) => { $crate::__::compile_error!{"expected `;` after struct declaration, found `impl`"} }; ( $struct_stuff:tt $where_predicates:tt ) => { $crate::__::compile_error!{"expected at least one type-level function definition"} }; } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_parse_fns { ( ( $typefn_impl_callback:ident $(#[$attrs:meta])* $vis:vis struct $struct_name:ident $capture_gen_args:tt $capture_generics:tt $erased_lt_ty_marker:tt captures_where $captures_where:tt ) $fns:tt [] $rem_dup:tt // duplicate of the parsed tokens ) => { $crate::__tyfn_split_capture_generics! { $typefn_impl_callback $fns $(#[$attrs])* $vis struct $struct_name $capture_gen_args $capture_gen_args $capture_generics $erased_lt_ty_marker captures_where $captures_where } }; ( $fixed:tt $fns:tt [] []) => { $crate::__::compile_error!{$crate::__::concat!( "bug: unhandled syntax in `typewit` macro: ", stringify!($fixed), stringify!($fns), )} }; ( $fixed:tt $fns:tt [ $(#[$impl_attrs:meta])* impl < $($rem:tt)* ] [ $(#[$_attr:meta])* $impl:ident $($rem_dup:tt)* ] ) => { $crate::__::__parse_in_generics!{ ($crate::__tyfn_parsed_fn_generics!( $fixed $fns [$(#[$impl_attrs])* $impl] )) [] [] [$($rem)*] } }; ( $fixed:tt $fns:tt [ $(#[$impl_attrs:meta])* impl $($rem:tt)* ] [ $(#[$_attr:meta])* $impl:ident $($rem_dup:tt)* ] ) => { $crate::__tyfn_parsed_fn_generics!{ $fixed $fns [$(#[$impl_attrs])* $impl] [] [] [] $($rem)* } }; ( $fixed:tt $fns:tt [ $(#[$impl_attrs:meta])* impl $type_fn_arg:ty => $ret_ty:ty where $($rem:tt)* ] [ $(#[$_attr:meta])* $impl:ident $($rem_dup:tt)* ] ) => { $crate::__trailing_comma_for_where_clause!{ ($crate::__tyfn_parsed_fn_where!( $fixed $fns [ $(#[$impl_attrs])* $impl[] $type_fn_arg => $ret_ty ] )) [] [$($rem)*] } }; ( $fixed:tt [$($fns:tt)*] [ $(#[$impl_attrs:meta])* impl $type_fn_arg:ty => $ret_ty:ty $(; $($rem:tt)*)? ] [ $(#[$_attr:meta])* $impl:ident $($rem_dup:tt)* ] ) => { $crate::__tyfn_parse_fns!{ $fixed [ $($fns)* ( $(#[$impl_attrs])* $impl[] $type_fn_arg => $ret_ty where[] ) ] [$($($rem)*)?] [$($($rem)*)?] } }; ( $fixed:tt $fns:tt [ $(#[$impl_attrs:meta])* $type_fn_arg:ty => $($rem:tt)* ] $rem_dup:tt ) => { $crate::__::compile_error!{$crate::__::concat!( "expected `impl`, found `", $crate::__::stringify!($type_fn_arg =>), "`\n", "helo: `impl ", $crate::__::stringify!($type_fn_arg =>), "` is likely to work." )} }; ( $fixed:tt $fns:tt [ $(#[$attrs:meta])* impl $arg:ty where $($rem:tt)* ] $rem_dup:tt ) => { $crate::__::compile_error!{"where clauses for functions go after the return type"} }; ( $fixed:tt [] [] [] ) => { $crate::__::compile_error!{"expected type-level function definitions"} }; } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_parsed_fn_generics { ( $fixed:tt [$($fns:tt)*] [$($prev_impl_tts:tt)*] $__gen_args:tt $gen_params:tt $deleted_markers:tt $type_fn_arg:ty => $ret_ty:ty $(; $($rem:tt)*)? ) => { $crate::__tyfn_parse_fns!{ $fixed [ $($fns)* ( $($prev_impl_tts)* $gen_params $type_fn_arg => $ret_ty where[] ) ] [$($($rem)*)?] [$($($rem)*)?] } }; ( $fixed:tt $fns:tt [$($prev_impl_tts:tt)*] $__gen_args:tt $gen_params:tt $deleted_markers:tt $type_fn_arg:ty => $ret_ty:ty where $($rem:tt)* ) => { $crate::__trailing_comma_for_where_clause!{ ($crate::__tyfn_parsed_fn_where!( $fixed $fns [ $($prev_impl_tts)* $gen_params $type_fn_arg => $ret_ty ] )) [] [$($rem)*] } }; ( $fixed:tt $fns:tt $impl_attrs:tt $__gen_args:tt $gen_params:tt $type_fn_arg:ty where $($rem:tt)* ) => { $crate::__::compile_error!{"where clauses for functions go after the return type"} }; } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_parsed_fn_where { ( $fixed:tt [$($fns:tt)*] [ $($fn_decl:tt)* ] $where_preds:tt $($rem:tt)* ) => { $crate::__tyfn_parse_fns!{ $fixed [ $($fns)* ( $($fn_decl)* where $where_preds ) ] [$($rem)*] [$($rem)*] } }; } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_split_capture_generics { ( $typefn_impl_callback:ident $functions:tt $(#[$attrs:meta])* $vis:vis struct $struct_name:ident $capture_gen_args:tt [$(($gen_arg:tt ($($($gen_phantom:tt)+)?) $($gen_rem:tt)*))*] $capture_generics:tt [$($erased_lt_ty_marker:tt)*] captures_where $captures_where:tt ) => { $crate::__tyfn_parsed!{ $typefn_impl_callback $functions $(#[$attrs])* $vis struct $struct_name $capture_gen_args [$($(($($gen_phantom)+))?)* $(($erased_lt_ty_marker))*] $capture_generics $captures_where } } } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_parsed { ( $typefn_impl_callback:ident [$($functions:tt)+] $(#[$attrs:meta])* $vis:vis struct $function_name:ident $capt_gen_args:tt $capt_gen_phantom:tt $capt_generics:tt // where clause of the captures $captures_where:tt ) => { $crate::__tyfn_declare_struct!{ ( $(#[$attrs])* $vis struct $function_name ) $capt_gen_args $capt_gen_phantom $capt_generics where $captures_where } $( $crate::$typefn_impl_callback!{ $functions $function_name $capt_gen_args $capt_generics where $captures_where } )* } } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_declare_struct { ( ( $(#[$attrs:meta])* $vis:vis struct $function_name:ident ) [$(($gen_arg:tt $ignored:tt $(= $gen_default:tt)?))*] [$($(@$has_phantom:tt)? $( ($($gen_phantom:tt)+) )+ )?] [$(($($gen_params:tt)*))*] where [$($($where:tt)+)?] ) => { $(#[$attrs])* $vis struct $function_name<$($($gen_params)* $(= $gen_default)?,)*> $(( $($has_phantom)? $crate::__::PhantomData<($($($gen_phantom)*)*)> ))? $(where $($where)+)?; impl<$($($gen_params)*,)*> $function_name<$($gen_arg,)*> $(where $($where)+)? { #[doc = $crate::__::concat!( "Constructs a `", $crate::__::stringify!($function_name), "`" )] $vis const NEW: Self = Self $($($has_phantom)? ($crate::__::PhantomData))?; } } } #[doc(hidden)] #[macro_export] macro_rules! __tyfn_typefn_impl { ( ( $(#[$attrs:meta])* $impl:ident[$(($($fn_gen_param:tt)*))*] $ty_arg:ty => $ret_ty:ty where[ $($where_preds:tt)* ] ) $function_name:ident [$(($capt_gen_args:tt $($rem_0:tt)*))*] [ $(($capt_lt:lifetime $($capt_lt_rem:tt)*))* $(($capt_tcp:ident $($capt_tcp_rem:tt)*))* ] where [$($capt_where:tt)*] ) => { $crate::__impl_with_span! { $ty_arg // span ( $(#[$attrs])* #[allow(unused_parens)] ) ( < $($capt_lt $($capt_lt_rem)*,)* $($($fn_gen_param)*,)* $($capt_tcp $($capt_tcp_rem)*,)* > $crate::TypeFn<$ty_arg> ) // for ( $function_name<$($capt_gen_args),*> ) ( where $($capt_where)* $($where_preds)* ) ( type Output = $ret_ty; ) } }; }typewit-1.12.1/src/macros/type_ne_macro.rs000064400000000000000000000076221046102023000166670ustar 00000000000000 /// Constructs a [`TypeNe`](crate::TypeNe) /// of types that are statically known to be different. /// /// This macro is syntactic sugar for calling /// [`TypeNe::with_fn`](crate::TypeNe::with_fn) with a private /// [`InjTypeFn`](crate::InjTypeFn) implementor. /// /// # Syntax /// /// This macro takes this syntax: /// /// ```text /// $( < $($generic_param:generic_param),* $(,)? > )? $left_type:ty, $right_type:ty /// $(where $($where_cause:tt)*)? /// ``` /// /// # Limitations /// /// This macro can't use generic parameters from the surrounding scope, /// they must be redeclared within the macro to be used. /// /// # Example /// /// ```rust /// use typewit::TypeNe; /// /// const _: TypeNe = foo(); /// /// const fn foo() -> TypeNe /// where /// (T,): Copy, /// { /// typewit::type_ne!{ /// X, (X,) /// where (X,): Copy /// } /// } /// /// /// ``` #[macro_export] macro_rules! type_ne { (< $($generics:tt)* ) => { $crate::__::__parse_in_generics! { ($crate::__tyne_parsed_capture_generics !()) [] [] [$($generics)*] } }; ($left_ty:ty, $($rem:tt)*) => { $crate::__tyne_parsed_capture_generics! { [] [] [] $left_ty, $($rem)* } }; ($($rem:tt)*) => { $crate::__::compile_error!{"invalid arguments for `type_ne` macro"} } } #[doc(hidden)] #[macro_export] macro_rules! __tyne_parsed_capture_generics { ( [$(($gen_arg:tt ($($($gen_phantom:tt)+)?) $($gen_rem:tt)*))*] [$(($($gen_params:tt)*))*] $deleted_markers:tt $left_ty:ty, $right_ty:ty $(,)? $(where $($where:tt)*)? ) => ({ struct __TypeNeParameterizer<$($($gen_params)*,)*>( $crate::__::PhantomData<( $($($crate::__::PhantomData<$($gen_phantom)+>,)?)* )> )$( where $($where)* )?; impl<$($($gen_params)*,)*> __TypeNeParameterizer<$($gen_arg,)*> $( where $($where)* )? { const NEW: Self = Self($crate::__::PhantomData); } $crate::__impl_with_span! { $left_ty // span () // impl attrs ( <$($($gen_params)*,)*> $crate::TypeFn<$crate::type_ne::LeftArg> ) // for (__TypeNeParameterizer<$($gen_arg,)*>) ( $( where $($where)* )? ) ( type Output = $left_ty; const TYPE_FN_ASSERTS: () = { let _: $crate::CallInjFn; }; ) } $crate::__impl_with_span! { $left_ty // span () // impl attrs ( <$($($gen_params)*,)*> $crate::RevTypeFn<$left_ty> ) // for (__TypeNeParameterizer<$($gen_arg,)*>) ( $( where $($where)* )? ) ( type Arg = $crate::type_ne::LeftArg; ) } $crate::__impl_with_span! { $right_ty // span () // impl attrs ( <$($($gen_params)*,)*> $crate::TypeFn<$crate::type_ne::RightArg> ) // for (__TypeNeParameterizer<$($gen_arg,)*>) ( $( where $($where)* )? ) ( type Output = $right_ty; const TYPE_FN_ASSERTS: () = { let _: $crate::CallInjFn; }; ) } $crate::__impl_with_span! { $right_ty // span () // impl attrs ( <$($($gen_params)*,)*> $crate::RevTypeFn<$right_ty> ) // for (__TypeNeParameterizer<$($gen_arg,)*>) ( $( where $($where)* )? ) ( type Arg = $crate::type_ne::RightArg; ) } $crate::TypeNe::with_fn( __TypeNeParameterizer::NEW ) }); }typewit-1.12.1/src/macros.rs000064400000000000000000000011401046102023000140300ustar 00000000000000pub(crate) mod generics_parsing; pub(crate) mod simple_type_witness_macro; mod type_fn_macro; mod inj_type_fn_macro; mod polymatch; mod type_ne_macro; #[cfg(not(feature = "proc_macros"))] #[doc(hidden)] #[macro_export] macro_rules! __impl_with_span { ( $impl_span:tt ($($impl_attrs:tt)*) ($($impl_trait:tt)*) ($($impl_type:tt)*) ($($impl_where:tt)*) ($($impl_assoc_items:tt)*) ) => { $($impl_attrs)* impl $($impl_trait)* for $($impl_type)* $($impl_where)* { $($impl_assoc_items)* } }; }typewit-1.12.1/src/methods/zipping_.rs000064400000000000000000000363261046102023000160440ustar 00000000000000use crate::{ type_constructors::{ BaseTypeWitnessTc, BaseTypeWitnessReparam, MapBaseTypeWitness, TcToBaseTypeWitness, TcTypeCmp, TcTypeEq, TcTypeNe, }, const_marker::Usize, BaseTypeWitness, MetaBaseTypeWit, MetaBaseTypeWit as MBTW, HasTypeWitness, SomeTypeArgIsNe, TypeCmp, TypeEq, TypeNe }; ////////////////////////////////////////////////////////////////////// macro_rules! return_type_docs {() => {concat!( "# Return type\n", "\n", "The return type depends on the types of the arguments:\n", "- if all arguments are [`TypeEq`], this returns a `TypeEq` \n", "- if any argument is a [`TypeNe`], this returns a `TypeNe` \n", "- if any argument is a [`TypeCmp`] and no argument is a `TypeNe`,", " this returns a `TypeCmp` \n", )}} ////////////////////////////////////////////////////////////////////// #[doc(hidden)] pub trait ZipTc: 'static + Copy { type Output: BaseTypeWitnessTc; } #[doc(hidden)] pub type ZipTcOut = ::Output; impl ZipTc for (TcTypeEq, TcTypeEq) { type Output = TcTypeEq; } impl ZipTc for (TcTypeEq, TcTypeNe) { type Output = TcTypeNe; } impl ZipTc for (TcTypeEq, TcTypeCmp) { type Output = TcTypeCmp; } impl ZipTc for (TcTypeNe, B) { type Output = TcTypeNe; } impl ZipTc for (TcTypeCmp, TcTypeEq) { type Output = TcTypeCmp; } impl ZipTc for (TcTypeCmp, TcTypeNe) { type Output = TcTypeNe; } impl ZipTc for (TcTypeCmp, TcTypeCmp) { type Output = TcTypeCmp; } impl ZipTc for (A, B, C) where A: BaseTypeWitnessTc, B: BaseTypeWitnessTc, C: BaseTypeWitnessTc, (A, B): ZipTc, (ZipTcOut<(A, B)>, C): ZipTc, { type Output = ZipTcOut<(ZipTcOut<(A, B)>, C)>; } impl ZipTc<> for (A, B, C, D) where A: BaseTypeWitnessTc, B: BaseTypeWitnessTc, C: BaseTypeWitnessTc, D: BaseTypeWitnessTc, (A, B): ZipTc, (C, D): ZipTc, (ZipTcOut<(A, B)>, ZipTcOut<(C, D)>): ZipTc, { type Output = ZipTcOut<(ZipTcOut<(A, B)>, ZipTcOut<(C, D)>)>; } ////////////////////////////////////////////////////////////////////// macro_rules! declare_zip_items { ( [$first_typa:ident ($($middle_typa:ident)*) $end_typa:ident] $(#[$fn_attr:meta])* fn $fn_name:ident($fn_param0:ident $(, $fn_param_rem:ident)*); $($rem:tt)* ) => { __declare_zip_items!{ [$first_typa ($($middle_typa)*) $end_typa] [$first_typa $($middle_typa)* $end_typa] $(#[$fn_attr])* fn $fn_name ($fn_param0 $(, $fn_param_rem)*) ($fn_param0, $(, $fn_param_rem)*); $($rem)* } } } macro_rules! __declare_zip_items { ( [$first_typa:ident ($($middle_typa:ident)*) $end_typa:ident] [$($ty_params:ident)*] $(#[$fn_attr:meta])* fn $fn_name:ident($($fn_param:ident),*) ($fn_param0:ident, $(, $fn_param_rem:ident)*); $(#[$type_alias_attr:meta])* type $type_alias:ident; $(#[$trait_attr:meta])* trait $trait:ident; enum $ty_wit:ident ($($arg_wit:ident),*); zip_method = $zip_method:ident; count = $count:tt ) => { #[doc = concat!( "The type returned by zipping ", $count, " [`BaseTypeWitness`]es.", )] $(#[$type_alias_attr])* #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_65")))] pub type $type_alias<$($ty_params),*> = <$first_typa as $trait<$($middle_typa,)* $end_typa>>::Output; #[doc = concat!( "Computes the type that the [`", stringify!($fn_name), "`] function returns, ", )] $(#[$trait_attr])* #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_65")))] pub trait $trait< $($middle_typa: BaseTypeWitness,)* $end_typa: BaseTypeWitness, >: BaseTypeWitness where Self::L: Sized, Self::R: Sized, $( $middle_typa::L: Sized, $middle_typa::R: Sized, )* { #[doc = concat!( "The the type returned by zipping ", $count, " [`BaseTypeWitness`] types" )] type Output: BaseTypeWitness< L = (Self::L, $($middle_typa::L,)* $end_typa::L), R = (Self::R, $($middle_typa::R,)* $end_typa::R), >; } impl<$($ty_params,)*> $trait<$($middle_typa,)* $end_typa> for $first_typa where $($ty_params: BaseTypeWitness,)* ($($ty_params::TypeCtor,)*): ZipTc, Self::L: Sized, Self::R: Sized, $( $middle_typa::L: Sized, $middle_typa::R: Sized, )* { type Output = TcToBaseTypeWitness< ZipTcOut<($($ty_params::TypeCtor,)*)>, ($($ty_params::L,)*), ($($ty_params::R,)*), >; } enum $ty_wit<$($ty_params,)* Ret: BaseTypeWitness> where $( $ty_params: BaseTypeWitness, )* $first_typa::L: Sized, $first_typa::R: Sized, $( $middle_typa::L: Sized, $middle_typa::R: Sized, )* { Eq { $($arg_wit: TypeEq<$ty_params, TypeEq<$ty_params::L, $ty_params::R>>,)* ret: TypeEq< Ret, TypeEq<($($ty_params::L,)*), ($($ty_params::R,)*)> > }, Ne { #[allow(dead_code)] contains_ne: SomeTypeArgIsNe<$($ty_params,)*>, ret: TypeEq> }, Cmp { ret: TypeEq> }, } impl<$($ty_params,)*> $ty_wit<$($ty_params,)* $type_alias<$($ty_params,)*>> where $first_typa: $trait<$($middle_typa,)* $end_typa>, $first_typa::L: Sized, $first_typa::R: Sized, $( $middle_typa: BaseTypeWitness, $middle_typa::L: Sized, $middle_typa::R: Sized, )* $end_typa: BaseTypeWitness, { const NEW: Self = match ($($ty_params::WITNESS,)* $type_alias::<$($ty_params,)*>::WITNESS) { ($(MBTW::Eq($arg_wit),)* MBTW::Eq(ret)) => { Self::Eq { $($arg_wit,)* ret } } (.., MBTW::Ne(ret)) => { let contains_ne = SomeTypeArgIsNe::<$($ty_params,)*>::new(); Self::Ne { contains_ne, ret } } (.., MBTW::Cmp(ret)) => { Self::Cmp {ret} } _ => panic!("BUG: invalid permutation of $trait"), }; } $(#[$fn_attr])* #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_65")))] pub const fn $fn_name<$($ty_params,)*>( $($fn_param: $ty_params,)* ) -> $type_alias<$($ty_params,)*> where $first_typa: BaseTypeWitness, $first_typa::L: Sized, $first_typa::R: Sized, $( $middle_typa: BaseTypeWitness, $middle_typa::L: Sized, $middle_typa::R: Sized, )* $end_typa: BaseTypeWitness, $first_typa: $trait<$($middle_typa,)* $end_typa> { match $ty_wit::<$($ty_params,)* $type_alias<$($ty_params,)*>>::NEW { $ty_wit::Eq {$($arg_wit,)* ret} => ret.to_left(TypeEq::$zip_method($($arg_wit.to_right($fn_param),)*)), $ty_wit::Ne {contains_ne, ret} => ret.to_left(contains_ne.$fn_name($($fn_param,)*)), $ty_wit::Cmp {ret} => ret.to_left( MetaBaseTypeWit::to_cmp(A::WITNESS, $fn_param0) .$zip_method($($fn_param_rem,)*) ), } } }; } declare_zip_items!{ [A () B] /// Zips together two [`BaseTypeWitness`] types. /// #[doc = return_type_docs!()] /// /// # Example /// /// ### Basic /// /// This example shows all permutations of argument and return types. /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// use typewit::methods::zip2; /// /// with::( /// TypeEq::NEW, /// type_ne!(u8, bool), /// TypeCmp::Ne(type_ne!(u16, u32)), /// ); /// /// const fn with(eq: TypeEq, ne: TypeNe, cmp: TypeCmp) { /// let _: TypeEq<(A, B), (B, A)> = zip2(eq, eq.flip()); /// let _: TypeNe<(A, B), (B, C)> = zip2(eq, ne); /// let _: TypeCmp<(A, D), (B, E)> = zip2(eq, cmp); /// /// let _: TypeNe<(B, A), (C, B)> = zip2(ne, eq); /// let _: TypeNe<(B, C), (C, B)> = zip2(ne, ne.flip()); /// let _: TypeNe<(B, D), (C, E)> = zip2(ne, cmp); /// /// let _: TypeCmp<(D, A), (E, B)> = zip2(cmp, eq); /// let _: TypeNe<(D, B), (E, C)> = zip2(cmp, ne); /// let _: TypeCmp<(D, E), (E, D)> = zip2(cmp, cmp.flip()); /// /// } /// ``` fn zip2(wit0, wit1); type Zip2Out; trait Zip2; enum Zip2Wit (arg0, arg1); zip_method = zip; count = "two" } ////////////////////////////////////////////////////////////////////// declare_zip_items!{ [A (B) C] /// Zips together three [`BaseTypeWitness`] types. /// #[doc = return_type_docs!()] /// /// # Example /// /// ### Basic /// /// This example shows basic usage. /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_eq, type_ne}; /// use typewit::methods::zip3; /// /// with::( /// TypeEq::NEW, /// type_ne!(u8, bool), /// TypeCmp::Ne(type_ne!(u16, u32)), /// ); /// /// const fn with(eq: TypeEq, ne: TypeNe, cmp: TypeCmp) { /// let _: TypeEq<(A, B, i64), (B, A, i64)> = zip3(eq, eq.flip(), type_eq::()); /// /// let _: TypeNe<(A, B, B), (B, A, C)> = zip3(eq, eq.flip(), ne); /// /// let _: TypeCmp<(A, D, B), (B, E, A)> = zip3(eq, cmp, eq.flip()); /// } /// ``` fn zip3(wit0, wit1, wit2); type Zip3Out; trait Zip3; enum Zip3Wit (arg0, arg1, arg2); zip_method = zip3; count = "three" } ////////////////////////////////////////////////////////////////////// declare_zip_items!{ [A (B C) D] /// Zips together four [`BaseTypeWitness`] types. /// #[doc = return_type_docs!()] /// /// # Example /// /// ### Basic /// /// This example shows basic usage. /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_eq, type_ne}; /// use typewit::methods::zip4; /// /// with::( /// TypeEq::NEW, /// type_ne!(u8, bool), /// TypeCmp::Ne(type_ne!(u16, u32)), /// ); /// /// const fn with(eq: TypeEq, ne: TypeNe, cmp: TypeCmp) { /// let _: TypeEq<(A, u64, B, i64), (B, u64, A, i64)> = /// zip4(eq, type_eq(), eq.flip(), type_eq()); /// /// let _: TypeNe<(A, E, B, B), (B, D, A, C)> = zip4(eq, cmp.flip(), eq.flip(), ne); /// /// let _: TypeCmp<(D, A, B, A), (E, B, A, B)> = zip4(cmp, eq, eq.flip(), eq); /// } /// ``` fn zip4(wit0, wit1, wit2, wit3); type Zip4Out; trait Zip4; enum Zip4Wit (arg0, arg1, arg2, arg3); zip_method = zip4; count = "four" } ////////////////////////////////////////////////////////////////////// pub use with_const_marker::*; mod with_const_marker { use super::*; use crate::type_fn::PairToArrayFn; use core::marker::PhantomData; // maps the type arguments of a BaseTypeWitness with `F` struct MapWithFn(PhantomData); impl crate::TypeFn for MapWithFn where W: BaseTypeWitness, F: crate::TypeFn + crate::TypeFn, { type Output = MapBaseTypeWitness; } /// Combines a /// `impl BaseTypeWitness` ///
with an `impl BaseTypeWitness, R = Usize>` ///
returning an `impl BaseTypeWitness`. /// #[doc = return_type_docs!()] /// /// # Example /// /// ### Return types /// /// ```rust /// use typewit::{ /// methods::in_array, /// const_marker::Usize, /// TypeCmp, TypeEq, TypeNe, /// type_ne, /// }; /// /// let eq_ty: TypeEq = TypeEq::NEW; /// let ne_ty: TypeNe = type_ne!(i16, u16); /// let cmp_ty: TypeCmp = TypeCmp::Ne(type_ne!(i16, u16)); /// /// let eq_len: TypeEq, Usize<0>> = TypeEq::NEW; /// let ne_len: TypeNe, Usize<2>> = Usize.equals(Usize).unwrap_ne(); /// let cmp_len: TypeCmp, Usize<3>> = Usize.equals(Usize); /// /// /// // if both arguments are TypeEq, this returns a TypeEq /// let _: TypeEq<[i16; 0], [i16; 0]> = in_array(eq_ty, eq_len); /// /// // if either of the arguments is a TypeNe, this returns a TypeNe /// let _: TypeNe<[i16; 0], [u16; 0]> = in_array(ne_ty, eq_len); /// let _: TypeNe<[i16; 1], [i16; 2]> = in_array(eq_ty, ne_len); /// let _: TypeNe<[i16; 1], [u16; 2]> = in_array(ne_ty, ne_len); /// let _: TypeNe<[i16; 1], [u16; 2]> = in_array(cmp_ty, ne_len); /// /// // If there are TypeCmp args, and no TypeNe args, this returns a TypeCmp /// assert!(matches!(in_array(eq_ty, cmp_len), TypeCmp::<[i16; 3], [i16; 3]>::Eq(_))); /// assert!(matches!(in_array(cmp_ty, eq_len), TypeCmp::<[i16; 0], [u16; 0]>::Ne(_))); /// assert!(matches!(in_array(cmp_ty, cmp_len), TypeCmp::<[i16; 3], [u16; 3]>::Ne(_))); /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_65")))] pub const fn in_array( wit0: A, wit1: B, ) -> BaseTypeWitnessReparam, [LT; LN], [RT; RN]> where A: BaseTypeWitness, B: BaseTypeWitness, R = Usize>, A: Zip2 { match Zip2Wit::>::NEW { Zip2Wit::Eq {arg0, arg1, ret} => ret.project::>() .to_left(TypeEq::in_array(arg0.to_right(wit0), arg1.to_right(wit1))), Zip2Wit::Ne {contains_ne, ret} => ret.project::>() .to_left(contains_ne.zip2(wit0, wit1).project::()), Zip2Wit::Cmp {ret} => ret.project::>().to_left( MetaBaseTypeWit::to_cmp(A::WITNESS, wit0) .in_array(wit1) ), } } } typewit-1.12.1/src/methods.rs000064400000000000000000000007541046102023000142210ustar 00000000000000//! Generic versions of //! [`TypeEq`](crate::TypeEq)/[`TypeNe`](crate::TypeNe)/[`TypeCmp`](crate::TypeCmp) //! methods, //! which can take any permutation of them as arguments. mod zipping_; /// For getting the return type of the zipping functions #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_65")))] pub mod zipping { pub use super::zipping_::{ Zip2, Zip3, Zip4, Zip2Out, Zip3Out, Zip4Out, }; } pub use self::zipping_::{in_array, zip2, zip3, zip4};typewit-1.12.1/src/some_type_arg_is_ne.rs000064400000000000000000000062001046102023000165600ustar 00000000000000#[cfg(feature = "rust_1_65")] use crate::base_type_wit::MetaBaseTypeWit as MBTW; use crate::{ base_type_wit::BaseTypeWitness as BTW, TypeEq, TypeNe }; // A `TypeEq` that's used as padding for the trailing type arguments of SomeTypeArgIsNe. type PadTyEq = TypeEq<(), ()>; // The first TypeNe in the 4 `BaseTypeWitness` type parameters pub(crate) enum SomeTypeArgIsNe { A(TypeEq>), B(TypeEq>), C(TypeEq>), D(TypeEq>), } #[cfg(feature = "rust_1_65")] impl SomeTypeArgIsNe { pub(crate) const TRY_NEW: Option = { match (A::WITNESS, B::WITNESS, C::WITNESS, D::WITNESS) { (MBTW::Ne(ne), _, _, _) => Some(Self::A(ne)), (_, MBTW::Ne(ne), _, _) => Some(Self::B(ne)), (_, _, MBTW::Ne(ne), _) => Some(Self::C(ne)), (_, _, _, MBTW::Ne(ne)) => Some(Self::D(ne)), _ => None, } }; pub(crate) const fn new() -> Self { match Self::TRY_NEW { Some(x) => x, None => panic!("expected at least one type argument to be TypeNe"), } } } impl SomeTypeArgIsNe where A::L: Sized, A::R: Sized, { #[inline(always)] pub(crate) const fn zip2(self, _: A, _: B) -> TypeNe<(A::L, B::L), (A::R, B::R)> { // SAFETY: either `A` or `B` is a TypeNe (PadTyEq isn't a TypeNe), // therefore: `(A::L, B::L) != (A::R, B::R)`. // (the function parameters are needed for soundness, // since `TypeNe` guarantees type inequality at the value level) unsafe { TypeNe::new_unchecked() } } } impl SomeTypeArgIsNe where A::L: Sized, A::R: Sized, B::L: Sized, B::R: Sized, { #[inline(always)] pub(crate) const fn zip3( self, _: A, _: B, _: C, ) -> TypeNe<(A::L, B::L, C::L), (A::R, B::R, C::R)> { // SAFETY: either `A`, `B`, or `C is a TypeNe (PadTyEq isn't a TypeNe), // therefore: `(A::L, B::L, C::L) != (A::R, B::R, C::R)`. // (the function parameters are needed for soundness, // since `TypeNe` guarantees type inequality at the value level) unsafe { TypeNe::new_unchecked() } } } impl SomeTypeArgIsNe where A::L: Sized, A::R: Sized, B::L: Sized, B::R: Sized, C::L: Sized, C::R: Sized, { #[inline(always)] pub(crate) const fn zip4( self, _: A, _: B, _: C, _: D, ) -> TypeNe<(A::L, B::L, C::L, D::L), (A::R, B::R, C::R, D::R)> { // SAFETY: either `A`, `B`, `C`, or `D` is a TypeNe, // therefore: `(A::L, B::L, C::L, D::L) != (A::R, B::R, C::R, D::R)`. // (the function parameters are needed for soundness, // since `TypeNe` guarantees type inequality at the value level) unsafe { TypeNe::new_unchecked() } } } typewit-1.12.1/src/type_cmp/extra_type_cmp_methods.rs000064400000000000000000000252141046102023000211420ustar 00000000000000use crate::type_fn::{InjTypeFn, InvokeAlias, CallInjFn, UncallFn}; #[cfg(feature = "alloc")] use alloc::boxed::Box; /// /// # Why `InjTypeFn` /// /// Both [`map`](Self::map) and [`project`](Self::project) /// require that the function is [injective] /// so that `TypeCmp`'s arguments don't change from /// being equal to unequal or viceversa. /// /// [injective]: mod@crate::type_fn#injective /// impl TypeCmp { /// Maps the type arguments of this `TypeCmp` /// by using the `F` [injective type-level function](crate::InjTypeFn). /// /// Use this function over [`project`](Self::project) /// if you want the type of the passed in function to be inferred. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, inj_type_fn, type_ne}; /// /// use std::num::Wrapping; /// /// /// const EQ: TypeCmp = TypeEq::NEW.to_cmp(); /// assert!(matches!(EQ.map(WrappingFn), TypeCmp::, Wrapping>::Eq(_))); /// /// const NE: TypeCmp = type_ne!(i8, u8).to_cmp(); /// assert!(matches!(NE.map(WrappingFn), TypeCmp::, Wrapping>::Ne(_))); /// /// /// inj_type_fn!{ /// struct WrappingFn; /// /// impl T => Wrapping /// } /// ``` pub const fn map( self: TypeCmp, func: F, ) -> TypeCmp, L>, CallInjFn, R>> where InvokeAlias: InjTypeFn + InjTypeFn { match self { TypeCmp::Eq(te) => TypeCmp::Eq(te.map::(func)), TypeCmp::Ne(te) => TypeCmp::Ne(te.map::(func)), } } /// Maps the type arguments of this `TypeCmp` /// by using the `F` [injective type-level function](crate::InjTypeFn). /// /// Use this function over [`map`](Self::map) /// if you want to specify the type of the passed in function explicitly. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, inj_type_fn, type_ne}; /// /// use std::mem::ManuallyDrop as ManDrop; /// /// /// const EQ: TypeCmp = TypeEq::NEW.to_cmp(); /// assert!(matches!(EQ.project::(), TypeCmp::, ManDrop>::Eq(_))); /// /// const NE: TypeCmp = type_ne!(i8, u8).to_cmp(); /// assert!(matches!(NE.project::(), TypeCmp::, ManDrop>::Ne(_))); /// /// /// inj_type_fn!{ /// struct ManDropFn; /// /// impl T => ManDrop /// } /// ``` pub const fn project( self: TypeCmp, ) -> TypeCmp, L>, CallInjFn, R>> where InvokeAlias: InjTypeFn + InjTypeFn { match self { TypeCmp::Eq(te) => TypeCmp::Eq(te.project::()), TypeCmp::Ne(te) => TypeCmp::Ne(te.project::()), } } /// Maps the type arguments of this `TypeCmp` /// by using the [reversed](crate::RevTypeFn) /// version of the `F` type-level function. /// /// Use this function over [`unproject`](Self::unproject) /// if you want the type of the passed in function to be inferred. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, inj_type_fn, type_ne}; /// /// use std::num::Wrapping; /// /// /// const EQ: TypeCmp, Wrapping> = TypeEq::NEW.to_cmp(); /// /// assert!(matches!(EQ.unmap(WrappingFn), TypeCmp::::Eq(_))); /// /// const NE: TypeCmp, Wrapping> = /// type_ne!(Wrapping, Wrapping).to_cmp(); /// /// assert!(matches!(NE.unmap(WrappingFn), TypeCmp::::Ne(_))); /// /// /// inj_type_fn!{ /// struct WrappingFn; /// /// impl T => Wrapping /// } /// ``` pub const fn unmap( self, func: F, ) -> TypeCmp, L>, UncallFn, R>> where InvokeAlias: crate::RevTypeFn + crate::RevTypeFn { match self { TypeCmp::Eq(te) => TypeCmp::Eq(te.unmap::(func)), TypeCmp::Ne(te) => TypeCmp::Ne(te.unmap::(func)), } } /// Maps the type arguments of this `TypeCmp` /// by using the [reversed](crate::RevTypeFn) /// version of the `F` type-level function. /// /// Use this function over [`unmap`](Self::unmap) /// if you want to specify the type of the passed in function explicitly. /// /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, inj_type_fn, type_ne}; /// /// use std::mem::MaybeUninit as MaybeUn; /// /// /// const EQ: TypeCmp, MaybeUn> = TypeEq::NEW.to_cmp(); /// /// assert!(matches!(EQ.unproject::(), TypeCmp::::Eq(_))); /// /// const NE: TypeCmp, MaybeUn> = /// type_ne!(MaybeUn, MaybeUn).to_cmp(); /// /// assert!(matches!(NE.unproject::(), TypeCmp::::Ne(_))); /// /// /// inj_type_fn!{ /// struct MaybeUnFn; /// /// impl T => MaybeUn /// } /// ``` pub const fn unproject( self, ) -> TypeCmp, L>, UncallFn, R>> where InvokeAlias: crate::RevTypeFn + crate::RevTypeFn { match self { TypeCmp::Eq(te) => TypeCmp::Eq(te.unproject::()), TypeCmp::Ne(te) => TypeCmp::Ne(te.unproject::()), } } /// Converts a `TypeCmp` to `TypeCmp<&L, &R>` /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// /// const EQ: TypeCmp = TypeEq::NEW.to_cmp(); /// assert!(matches!(EQ.in_ref(), TypeCmp::<&u8, &u8>::Eq(_))); /// /// const NE: TypeCmp = type_ne!(i8, u8).to_cmp(); /// assert!(matches!(NE.in_ref(), TypeCmp::<&i8, &u8>::Ne(_))); /// /// ``` pub const fn in_ref<'a>(self) -> TypeCmp<&'a L, &'a R> { match self { TypeCmp::Eq(te) => TypeCmp::Eq(te.in_ref()), TypeCmp::Ne(te) => TypeCmp::Ne(te.in_ref()), } } crate::utils::conditionally_const!{ feature = "rust_1_83"; /// Converts a `TypeCmp` to `TypeCmp<&mut L, &mut R>` /// /// # Constness /// /// This requires the `"rust_1_83"` crate feature to be a `const fn`. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// /// const EQ: TypeCmp = TypeEq::NEW.to_cmp(); /// assert!(matches!(EQ.in_mut(), TypeCmp::<&mut u8, &mut u8>::Eq(_))); /// /// const NE: TypeCmp = type_ne!(i8, u8).to_cmp(); /// assert!(matches!(NE.in_mut(), TypeCmp::<&mut i8, &mut u8>::Ne(_))); /// /// ``` pub fn in_mut['a](self) -> TypeCmp<&'a mut L, &'a mut R> { match self { TypeCmp::Eq(te) => TypeCmp::Eq(te.in_mut()), TypeCmp::Ne(te) => TypeCmp::Ne(te.in_mut()), } } } /// Converts a `TypeCmp` to `TypeCmp, Box>` /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// /// const EQ: TypeCmp = TypeEq::NEW.to_cmp(); /// assert!(matches!(EQ.in_box(), TypeCmp::, Box>::Eq(_))); /// /// const NE: TypeCmp = type_ne!(i8, u8).to_cmp(); /// assert!(matches!(NE.in_box(), TypeCmp::, Box>::Ne(_))); /// /// ``` #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] pub const fn in_box(self) -> TypeCmp, Box> { match self { TypeCmp::Eq(te) => TypeCmp::Eq(te.in_box()), TypeCmp::Ne(te) => TypeCmp::Ne(te.in_box()), } } } #[cfg(feature = "rust_1_61")] use crate::const_marker::Usize; #[cfg(feature = "rust_1_61")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))] impl TypeCmp { /// Combines `TypeCmp` and a /// `O:`[`BaseTypeWitness`]`, R = Usize>` /// into `TypeCmp<[L; UL], [R; UR]>` /// /// [`BaseTypeWitness`]: crate::BaseTypeWitness /// #[doc = alternative_docs!("in_array")] /// /// # Example /// /// ### Basic /// /// ```rust /// use typewit::{ /// const_marker::Usize, /// TypeCmp, TypeEq, TypeNe, /// type_ne, /// }; /// /// let cmp_eq_ty: TypeCmp = TypeCmp::Eq(TypeEq::NEW); /// let cmp_ne_ty: TypeCmp = TypeCmp::Ne(type_ne!(i64, u64)); /// /// let eq_len: TypeEq, Usize<0>> = TypeEq::NEW; /// let ne_len: TypeNe, Usize<2>> = Usize.equals(Usize).unwrap_ne(); /// let cmp_eq_len: TypeCmp, Usize<3>> = Usize.equals(Usize); /// let cmp_ne_len: TypeCmp, Usize<8>> = Usize.equals(Usize); /// /// assert!(matches!(cmp_eq_ty.in_array(eq_len), TypeCmp::<[i32; 0], [i32; 0]>::Eq(_))); /// assert!(matches!(cmp_eq_ty.in_array(ne_len), TypeCmp::<[i32; 1], [i32; 2]>::Ne(_))); /// assert!(matches!(cmp_eq_ty.in_array(cmp_eq_len), TypeCmp::<[i32; 3], [i32; 3]>::Eq(_))); /// assert!(matches!(cmp_eq_ty.in_array(cmp_ne_len), TypeCmp::<[i32; 5], [i32; 8]>::Ne(_))); /// /// assert!(matches!(cmp_ne_ty.in_array(eq_len), TypeCmp::<[i64; 0], [u64; 0]>::Ne(_))); /// assert!(matches!(cmp_ne_ty.in_array(ne_len), TypeCmp::<[i64; 1], [u64; 2]>::Ne(_))); /// assert!(matches!(cmp_ne_ty.in_array(cmp_eq_len), TypeCmp::<[i64; 3], [u64; 3]>::Ne(_))); /// assert!(matches!(cmp_ne_ty.in_array(cmp_ne_len), TypeCmp::<[i64; 5], [u64; 8]>::Ne(_))); /// ``` pub const fn in_array( self, other: O, ) -> TypeCmp<[L; UL], [R; UR]> where O: BaseTypeWitness, R = Usize> { use crate::type_fn::PairToArrayFn as PTAF; let other = MetaBaseTypeWit::to_cmp(O::WITNESS, other); match (self, other) { (TypeCmp::Eq(tel), TypeCmp::Eq(ter)) => { TypeCmp::Eq(tel.in_array(ter)) } (TypeCmp::Ne(ne), _) => { TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip2(ne, other).project::()) } (_, TypeCmp::Ne(ne)) => { TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip2(self, ne).project::()) } } } }typewit-1.12.1/src/type_cmp.rs000064400000000000000000000411071046102023000143730ustar 00000000000000use crate::{TypeEq, TypeNe}; #[cfg(feature = "rust_1_61")] use crate::{BaseTypeWitness, MetaBaseTypeWit, SomeTypeArgIsNe}; use core::{ any::Any, cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}, hash::{Hash, Hasher}, fmt::{self, Debug}, }; /// The result of comparing two types for equality. /// /// # Example /// /// ### Custom array creation /// /// (this example requires Rust 1.63.0, because of [`core::array::from_fn`]). /// #[cfg_attr(not(feature = "rust_1_65"), doc = "```ignore")] #[cfg_attr(feature = "rust_1_65", doc = "```rust")] /// use typewit::{const_marker::Usize, TypeCmp, TypeEq, TypeNe}; /// /// let empty: [String; 0] = []; /// assert_eq!(ArrayMaker::::empty().make(), empty); /// /// assert_eq!(ArrayMaker::::defaulted().make(), [0u8, 0u8]); /// /// assert_eq!(ArrayMaker::with(|i| i.pow(2)).make(), [0usize, 1, 4, 9]); /// /// /// enum ArrayMaker { /// NonEmpty(fn(usize) -> T, TypeNe<[T; LEN], [T; 0]>), /// Empty(TypeEq<[T; LEN], [T; 0]>), /// } /// /// impl ArrayMaker { /// pub fn make(self) -> [T; LEN] { /// match self { /// ArrayMaker::NonEmpty(func, _) => std::array::from_fn(func), /// ArrayMaker::Empty(te) => te.to_left([]), /// } /// } /// /// pub const fn defaulted() -> Self /// where /// T: Default /// { /// Self::with(|_| Default::default()) /// } /// /// pub const fn with(func: fn(usize) -> T) -> Self { /// match Usize::.equals(Usize::<0>) // : TypeCmp, Usize<0>> /// .project::>() // : TypeCmp<[T; LEN], [T; 0]> /// { /// TypeCmp::Ne(ne) => ArrayMaker::NonEmpty(func, ne), /// TypeCmp::Eq(eq) => ArrayMaker::Empty(eq), /// } /// } /// } /// /// impl ArrayMaker { /// pub const fn empty() -> Self { /// Self::Empty(TypeEq::NEW) /// } /// } /// /// impl Copy for ArrayMaker {} /// /// impl Clone for ArrayMaker { /// fn clone(&self) -> Self { *self } /// } /// /// typewit::inj_type_fn! { /// // Declares `struct ArrayFn`, which implements `InjTypeFn>`: /// // an injective type-level function from `Usize` to `[T; LEN]` /// struct ArrayFn; /// impl Usize => [T; LEN] /// } /// ``` pub enum TypeCmp{ /// proof of `L == R` Eq(TypeEq), /// proof of `L != R` Ne(TypeNe), } impl TypeCmp { /// Constructs a `TypeCmp` by comparing the `L` and `R` types for equality. /// /// # Example /// /// ```rust /// use typewit::TypeCmp; /// /// let eq: TypeCmp = TypeCmp::with_any(); /// assert!(matches!(eq, TypeCmp::Eq(_))); /// /// let ne = TypeCmp::::with_any(); /// assert!(matches!(ne, TypeCmp::Ne(_))); /// ``` #[deprecated = concat!( "fallout of `https://github.com/rust-lang/rust/issues/97156`,", "`TypeId::of::() != TypeId::of::()` does not imply `L != R`" )] pub fn with_any() -> Self where L: Sized + Any, R: Sized + Any, { #[allow(deprecated)] if let Some(equal) = TypeEq::with_any() { TypeCmp::Eq(equal) } else if let Some(unequal) = TypeNe::with_any() { TypeCmp::Ne(unequal) } else { unreachable!() } } /// Swaps the type arguments of this `TypeCmp` /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, type_ne}; /// /// const TC: TypeCmp = TypeCmp::Ne(type_ne!(u8, i8)); /// /// const TK: TypeCmp = TC.flip(); /// /// ``` pub const fn flip(self) -> TypeCmp { match self { TypeCmp::Eq(te) => TypeCmp::Eq(te.flip()), TypeCmp::Ne(te) => TypeCmp::Ne(te.flip()), } } /// Joins this `TypeCmp` with a `TypeEq`, producing a `TypeCmp`. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, type_ne}; /// /// const TC: TypeCmp = type_ne!(str, [u8]).to_cmp(); /// /// const fn foo(eq: TypeEq) { /// let _tc: TypeCmp = TC.join_left(eq); /// } /// ``` pub const fn join_left(self, left: TypeEq) -> TypeCmp { match self { TypeCmp::Eq(te) => TypeCmp::Eq(left.join(te)), TypeCmp::Ne(te) => TypeCmp::Ne(te.join_left(left)), } } /// Joins this `TypeCmp` with a `TypeEq`, producing a `TypeCmp`. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, type_ne}; /// /// const NE: TypeCmp> = type_ne!(String, Vec).to_cmp(); /// /// const fn foo(eq: TypeEq, A>) { /// let _ne: TypeCmp = NE.join_right(eq); /// } /// ``` pub const fn join_right(self, right: TypeEq) -> TypeCmp { match self { TypeCmp::Eq(te) => TypeCmp::Eq(te.join(right)), TypeCmp::Ne(te) => TypeCmp::Ne(te.join_right(right)), } } /// Converts this `TypeCmp` into an `Option>`. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, type_ne}; /// /// let eq: TypeCmp = TypeCmp::Eq(TypeEq::NEW); /// assert!(matches!(eq.eq(), Some(TypeEq::{..}))); /// /// let ne = TypeCmp::Ne(type_ne!(u8, i8)); /// assert!(matches!(ne.eq(), None::>)); /// ``` pub const fn eq(self) -> Option> { match self { TypeCmp::Eq(te) => Some(te), TypeCmp::Ne(_) => None, } } /// Converts this `TypeCmp` into an `Option>`. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// /// let eq: TypeCmp = TypeCmp::Eq(TypeEq::NEW); /// assert!(matches!(eq.ne(), None::>)); /// /// let ne = TypeCmp::Ne(type_ne!(u8, i8)); /// assert!(matches!(ne.ne(), Some(TypeNe::{..}))); /// ``` pub const fn ne(self) -> Option> { match self { TypeCmp::Eq(_) => None, TypeCmp::Ne(te) => Some(te), } } /// Returns whether this `TypeCmp` is a `TypeCmp::Eq`. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// /// const EQ: TypeCmp = TypeEq::NEW.to_cmp(); /// assert_eq!(EQ.is_eq(), true); /// /// const NE: TypeCmp = type_ne!(i8, u8).to_cmp(); /// assert_eq!(NE.is_eq(), false); /// ``` pub const fn is_eq(self) -> bool { matches!(self, TypeCmp::Eq(_)) } /// Returns whether this `TypeCmp` is a `TypeCmp::Ne`. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// /// const EQ: TypeCmp = TypeEq::NEW.to_cmp(); /// assert_eq!(EQ.is_ne(), false); /// /// const NE: TypeCmp = type_ne!(i8, u8).to_cmp(); /// assert_eq!(NE.is_ne(), true); /// ``` pub const fn is_ne(self) -> bool { matches!(self, TypeCmp::Ne(_)) } /// Returns the contained `TypeEq` /// /// # Panic /// /// Panics if the contained value is a `TypeNe`. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq}; /// /// let eq: TypeCmp = TypeCmp::Eq(TypeEq::NEW); /// assert!(matches!(eq.unwrap_eq(), TypeEq::{..})); /// ``` #[track_caller] pub const fn unwrap_eq(self) -> TypeEq { match self { TypeCmp::Eq(te) => te, TypeCmp::Ne(_) => panic!("called `TypeCmp::unwrap_eq` on a `TypeNe` value"), } } /// Returns the contained `TypeNe` /// /// # Panic /// /// Panics if the contained value is a `TypeEq`. /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeNe, type_ne}; /// /// let ne = TypeCmp::Ne(type_ne!(u8, i8)); /// assert!(matches!(ne.unwrap_ne(), TypeNe::{..})); /// ``` #[track_caller] pub const fn unwrap_ne(self) -> TypeNe { match self { TypeCmp::Eq(_) => panic!("called `TypeCmp::unwrap_ne` on a `TypeEq` value"), TypeCmp::Ne(te) => te, } } } #[cfg(feature = "rust_1_61")] macro_rules! alternative_docs { ($func:expr) => {concat!( "# Alternative\n", "\n", "[`methods::", $func,"`](crate::methods::", $func, ") \n", "is an alternative to this function. \n", "\n", "This method always returns `TypeCmp`, \n", "while [that function](crate::methods::", $func, ")\n", "returns [`TypeNe`] when any argument is a `TypeNe`.\n", "\n", "# Returned variant\n", "\n", "This returns either [`TypeCmp::Eq`] or [`TypeCmp::Ne`]", " depending on the arguments:\n", "- if all arguments (including `self`)", " are [`TypeEq`] or [`TypeCmp::Eq`], this returns [`TypeCmp::Eq`] \n", "- if any argument (including `self`) ", "is a [`TypeNe`] or [`TypeCmp::Ne`], this returns [`TypeCmp::Ne`] \n", )}; } #[cfg(feature = "rust_1_61")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))] impl TypeCmp { /// Combines this `TypeCmp` with a [`BaseTypeWitness`] type to produce a /// `TypeCmp<(L, A::L), (R, A::R)>`. /// #[doc = alternative_docs!("zip2")] /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// /// /// const NE: TypeNe = type_ne!(u8, i8); /// const EQ: TypeEq = TypeEq::NEW; /// const TC_NE: TypeCmp = TypeCmp::Ne(type_ne!(u32, u64)); /// const TC_EQ: TypeCmp = TypeCmp::Eq(TypeEq::NEW); /// /// assert!(matches!( /// TC_EQ.zip(NE), /// TypeCmp::<(i64, u8), (i64, i8)>::Ne(_), /// )); /// /// assert!(matches!( /// TC_EQ.zip(EQ), /// TypeCmp::<(i64, u16), (i64, u16)>::Eq(_), /// )); /// /// assert!(matches!( /// TC_EQ.zip(TC_EQ), /// TypeCmp::<(i64, i64), (i64, i64)>::Eq(_), /// )); /// /// assert!(matches!( /// TC_EQ.zip(TC_NE), /// TypeCmp::<(i64, u32), (i64, u64)>::Ne(_), /// )); /// ``` pub const fn zip(self, other: A) -> TypeCmp<(L, A::L), (R, A::R)> where A: BaseTypeWitness, { let other = MetaBaseTypeWit::to_cmp(A::WITNESS, other); match (self, other) { (TypeCmp::Eq(tel), TypeCmp::Eq(ter)) => { TypeCmp::Eq(tel.zip(ter)) } (TypeCmp::Ne(ne), _) => { TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip2(ne, other)) } (_, TypeCmp::Ne(ne)) => { TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip2(self, ne)) } } } /// Combines this `TypeCmp` with two [`BaseTypeWitness`] types to produce a /// `TypeCmp<(L, A::L, B::L), (R, A::R, B::R)>`. /// #[doc = alternative_docs!("zip3")] /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// /// /// const NE: TypeNe = type_ne!(u8, i8); /// const EQ: TypeEq = TypeEq::NEW; /// const TC_NE: TypeCmp = TypeCmp::Ne(type_ne!(u32, u64)); /// const TC_EQ: TypeCmp = TypeCmp::Eq(TypeEq::NEW); /// /// assert!(matches!( /// TC_EQ.zip3(EQ, NE), /// TypeCmp::<(i64, u16, u8), (i64, u16, i8)>::Ne(_), /// )); /// /// assert!(matches!( /// TC_EQ.zip3(EQ, TC_EQ), /// TypeCmp::<(i64, u16, i64), (i64, u16, i64)>::Eq(_), /// )); /// /// assert!(matches!( /// TC_EQ.zip3(NE, TC_NE), /// TypeCmp::<(i64, u8, u32), (i64, i8, u64)>::Ne(_), /// )); /// ``` pub const fn zip3(self, arg0: A, arg1: B) -> TypeCmp<(L, A::L, B::L), (R, A::R, B::R)> where A: BaseTypeWitness, A::L: Sized, A::R: Sized, B: BaseTypeWitness, { let arg0 = MetaBaseTypeWit::to_cmp(A::WITNESS, arg0); let arg1 = MetaBaseTypeWit::to_cmp(B::WITNESS, arg1); match (self, arg0, arg1) { (TypeCmp::Eq(te0), TypeCmp::Eq(te1), TypeCmp::Eq(te2)) => { TypeCmp::Eq(te0.zip3(te1, te2)) } (TypeCmp::Ne(ne), _, _) => { TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip3(ne, arg0, arg1)) } (_, TypeCmp::Ne(ne), _) => { TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip3(self, ne, arg1)) } (_, _, TypeCmp::Ne(ne)) => { TypeCmp::Ne(SomeTypeArgIsNe::C(TypeEq::NEW).zip3(self, arg0, ne)) } } } /// Combines this `TypeCmp` with three [`BaseTypeWitness`] types to produce a /// `TypeCmp<(L, A::L, B::L, C::L), (R, A::R, B::R, C::R)>`. /// #[doc = alternative_docs!("zip4")] /// /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne}; /// /// /// const NE: TypeNe = type_ne!(u8, i8); /// const EQ: TypeEq = TypeEq::NEW; /// const TC_NE: TypeCmp = TypeCmp::Ne(type_ne!(u32, u64)); /// const TC_EQ: TypeCmp = TypeCmp::Eq(TypeEq::NEW); /// /// assert!(matches!( /// TC_EQ.zip4(EQ, NE, TC_NE), /// TypeCmp::<(i64, u16, u8, u32), (i64, u16, i8, u64)>::Ne(_), /// )); /// /// assert!(matches!( /// TC_EQ.zip4(EQ, TC_EQ, EQ), /// TypeCmp::<(i64, u16, i64, u16), (i64, u16, i64, u16)>::Eq(_), /// )); /// ``` pub const fn zip4( self, arg0: A, arg1: B, arg2: C, ) -> TypeCmp<(L, A::L, B::L, C::L), (R, A::R, B::R, C::R)> where A: BaseTypeWitness, A::L: Sized, A::R: Sized, B: BaseTypeWitness, B::L: Sized, B::R: Sized, C: BaseTypeWitness, { let arg0 = MetaBaseTypeWit::to_cmp(A::WITNESS, arg0); let arg1 = MetaBaseTypeWit::to_cmp(B::WITNESS, arg1); let arg2 = MetaBaseTypeWit::to_cmp(C::WITNESS, arg2); match (self, arg0, arg1, arg2) { (TypeCmp::Eq(te0), TypeCmp::Eq(te1), TypeCmp::Eq(te2), TypeCmp::Eq(te3)) => { TypeCmp::Eq(te0.zip4(te1, te2, te3)) } (TypeCmp::Ne(ne), _, _, _) => { TypeCmp::Ne(SomeTypeArgIsNe::A(TypeEq::NEW).zip4(ne, arg0, arg1, arg2)) } (_, TypeCmp::Ne(ne), _, _) => { TypeCmp::Ne(SomeTypeArgIsNe::B(TypeEq::NEW).zip4(self, ne, arg1, arg2)) } (_, _, TypeCmp::Ne(ne), _) => { TypeCmp::Ne(SomeTypeArgIsNe::C(TypeEq::NEW).zip4(self, arg0, ne, arg2)) } (_, _, _, TypeCmp::Ne(ne)) => { TypeCmp::Ne(SomeTypeArgIsNe::D(TypeEq::NEW).zip4(self, arg0, arg1, ne)) } } } } // using this instead of `mod extra_type_cmp_methods;` // to document the impls in the submodule below the constructors. include!{"./type_cmp/extra_type_cmp_methods.rs"} impl Copy for TypeCmp {} impl Clone for TypeCmp { fn clone(&self) -> Self { *self } } impl Debug for TypeCmp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { TypeCmp::Eq(x) => Debug::fmt(x, f), TypeCmp::Ne(x) => Debug::fmt(x, f), } } } impl PartialEq for TypeCmp { fn eq(&self, other: &Self) -> bool { self.is_eq() == other.is_eq() } } impl PartialOrd for TypeCmp { fn partial_cmp(&self, other: &Self) -> Option { self.is_eq().partial_cmp(&other.is_eq()) } } impl Ord for TypeCmp { fn cmp(&self, other: &Self) -> Ordering { self.is_eq().cmp(&other.is_eq()) } } impl Eq for TypeCmp {} impl Hash for TypeCmp { fn hash(&self, state: &mut H) where H: Hasher { match self { TypeCmp::Eq(x) => Hash::hash(x, state), TypeCmp::Ne(x) => Hash::hash(x, state), } } } typewit-1.12.1/src/type_constructors.rs000064400000000000000000000050021046102023000163560ustar 00000000000000//! Higher Kinded Types for [`BaseTypeWitness`]es #![cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_65")))] use crate::{BaseTypeWitness, TypeCmp, TypeEq, TypeNe}; use core::fmt::Debug; /// The type constructor for a [`BaseTypeWitness`], /// only implemented for [`TcTypeCmp`]/[`TcTypeEq`]/[`TcTypeNe`]. /// /// A type constructor is a "type" which needs to be provided /// generic arguments to produce a concrete type. /// /// This crate emulates type constructors for [`BaseTypeWitness`] types by using this trait, /// concrete types are produced with the [`Type`](Self::Type) associated constant. /// pub trait BaseTypeWitnessTc: 'static + Copy + Debug { /// The [`BaseTypeWitness`] type that corresponds to this type constructor. /// /// For [`TcTypeCmp`], this is [`TypeCmp`]`` ///
/// For [`TcTypeEq`], this is [`TypeEq`]`` ///
/// For [`TcTypeNe`], this is [`TypeNe`]`` /// type Type: BaseTypeWitness; } /// Computes a [`BaseTypeWitness`] type from a [`BaseTypeWitnessTc`] pub type TcToBaseTypeWitness = ::Type::; /// Queries the [`BaseTypeWitnessTc`] of a [`BaseTypeWitness`] pub type BaseTypeWitnessToTc = ::TypeCtor; /// Computes `W:`[`BaseTypeWitness`] with its type arguments replaced with `L` and `R` pub type BaseTypeWitnessReparam = as BaseTypeWitnessTc>::Type::< L, R, >; /// The type returned by `W::project::()`, /// where `W` is a [`BaseTypeWitness`] pub type MapBaseTypeWitness = as BaseTypeWitnessTc>::Type::< crate::CallFn::L>, crate::CallFn::R>, >; ///////////////////////////////////////////////////////////////////////////// /// The [*type constructor*](BaseTypeWitnessTc) for [`TypeCmp`]. #[derive(Debug, Copy, Clone)] pub struct TcTypeCmp; impl BaseTypeWitnessTc for TcTypeCmp { type Type = TypeCmp; } /// The [*type constructor*](BaseTypeWitnessTc) for [`TypeEq`]. #[derive(Debug, Copy, Clone)] pub struct TcTypeEq; impl BaseTypeWitnessTc for TcTypeEq { type Type = TypeEq; } /// The [*type constructor*](BaseTypeWitnessTc) for [`TypeNe`]. #[derive(Debug, Copy, Clone)] pub struct TcTypeNe; impl BaseTypeWitnessTc for TcTypeNe { type Type = TypeNe; } typewit-1.12.1/src/type_eq.rs000064400000000000000000001141221046102023000142170ustar 00000000000000use crate::{ type_fn::{self, CallFn, InvokeAlias, RevTypeFn, TypeFn, UncallFn}, MakeTypeWitness, TypeWitnessTypeArg, }; use crate::const_marker::Usize; use core::{ cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}, default::Default, hash::{Hash, Hasher}, fmt::{self, Debug}, }; #[cfg(feature = "alloc")] use alloc::boxed::Box; crate::type_eq_ne_guts::declare_helpers!{ $ TypeEq TypeFn CallFn } crate::type_eq_ne_guts::declare_zip_helper!{ $ TypeEq } // Equivalent to `type_eq.zip(other_type_eq).project::()`, // defined to ensure that methods which do zip+project have 0 overhead in debug builds. macro_rules! zip_project { // Since `$L0`, `$L1`,`$R0`, and `$R1` are all used only once, // it's safe to declare them as `:ty` (safe against malicious type macros). ( $left_type_eq:expr, $right_type_eq:expr, $F: ty, ($L0:ty, $R0:ty), ($L1:ty, $R1:ty), ) => ({ __ZipProjectVars::<$F, $L0, $R0, $L1, $R1> { left_te: $left_type_eq, right_te: $right_type_eq, projected_te: { // SAFETY: // `TypeEq<$L0, $R0>` and `TypeEq<$L1, $R1>` // implies `TypeEq<($L0, $L1), ($R0, $R1)>`, // // Using `$F` only once, as a type argument, // to protect against type-position macros that expand to // different types on each use. unsafe { TypeEq::new_unchecked() } } }.projected_te }); } struct __ZipProjectVars where F: TypeFn<(L0, L1)> + TypeFn<(R0, R1)> { #[allow(dead_code)] left_te: TypeEq, #[allow(dead_code)] right_te: TypeEq, // (TypeEq, TypeEq) // implies TypeEq<(L0, L1), (R0, R1)> // implies TypeEq, CallFn> projected_te: TypeEq, CallFn>, } /// Constructs a [`TypeEq`](TypeEq) /// /// # Example /// /// ```rust /// use typewit::{MakeTypeWitness, TypeWitnessTypeArg, TypeEq, type_eq}; /// /// assert_eq!(ascii_to_upper(b'a'), b'A'); /// assert_eq!(ascii_to_upper(b'f'), b'F'); /// assert_eq!(ascii_to_upper(b'B'), b'B'); /// assert_eq!(ascii_to_upper(b'0'), b'0'); /// /// assert_eq!(ascii_to_upper('c'), 'C'); /// assert_eq!(ascii_to_upper('e'), 'E'); /// assert_eq!(ascii_to_upper('H'), 'H'); /// assert_eq!(ascii_to_upper('@'), '@'); /// /// const fn ascii_to_upper(c: T) -> T /// where /// Wit: MakeTypeWitness, /// { /// match MakeTypeWitness::MAKE { /// Wit::U8(te) => { /// // `te` is a `TypeEq`, which allows casting between `T` and `u8`. /// // `te.to_right(...)` goes from `T` to `u8` /// // `te.to_left(...)` goes from `u8` to `T` /// te.to_left(te.to_right(c).to_ascii_uppercase()) /// } /// Wit::Char(te) => { /// // `te` is a `TypeEq`, which allows casting between `T` and `char`. /// // `te.to_right(...)` goes from `T` to `char` /// // `te.to_left(...)` goes from `char` to `T` /// te.to_left(te.to_right(c).to_ascii_uppercase()) /// } /// } /// } /// /// // This is a type witness /// enum Wit { /// // this variant requires `T == u8` /// U8(TypeEq), /// /// // this variant requires `T == char` /// Char(TypeEq), /// } /// impl TypeWitnessTypeArg for Wit { /// type Arg = T; /// } /// impl MakeTypeWitness for Wit { /// const MAKE: Self = Self::U8(type_eq()); /// } /// impl MakeTypeWitness for Wit { /// const MAKE: Self = Self::Char(type_eq()); /// } /// ``` /// The code above can be written more concisly using /// the [`polymatch`](crate::polymatch) and [`simple_type_witness`] macros: /// ```rust /// # use typewit::{MakeTypeWitness, TypeWitnessTypeArg, TypeEq, type_eq}; /// # /// # assert_eq!(ascii_to_upper(b'a'), b'A'); /// # assert_eq!(ascii_to_upper(b'f'), b'F'); /// # assert_eq!(ascii_to_upper(b'B'), b'B'); /// # assert_eq!(ascii_to_upper(b'0'), b'0'); /// # /// # assert_eq!(ascii_to_upper('c'), 'C'); /// # assert_eq!(ascii_to_upper('e'), 'E'); /// # assert_eq!(ascii_to_upper('H'), 'H'); /// # assert_eq!(ascii_to_upper('@'), '@'); /// # /// const fn ascii_to_upper(c: T) -> T /// where /// Wit: MakeTypeWitness, /// { /// // deduplicating identical match arms using the `polymatch` macro. /// typewit::polymatch!{MakeTypeWitness::MAKE; /// Wit::U8(te) | Wit::Char(te) => te.to_left(te.to_right(c).to_ascii_uppercase()) /// } /// } /// /// // This macro declares a type witness /// typewit::simple_type_witness! { /// // Declares `enum Wit<__Wit>` /// // The `__Wit` type parameter is implicit and always the last generic parameter. /// enum Wit { /// // this variant requires `__Wit == u8` /// U8 = u8, /// // this variant requires `__Wit == char` /// Char = char, /// } /// } /// ``` /// note that [`simple_type_witness`] can't replace enums whose /// witnessed type parameter is not the last, /// or have variants with anything but one `TypeEq` field each. /// /// [`simple_type_witness`]: crate::simple_type_witness #[inline(always)] pub const fn type_eq() -> TypeEq { TypeEq::NEW } // Declaring `TypeEq` in a submodule to prevent "safely" constructing `TypeEq` with // two different type arguments in the `crate::type_eq` module. mod type_eq_ { use core::{ any::{Any, TypeId}, marker::PhantomData, }; /// Value-level proof that `L` is the same type as `R` /// /// This type can be used to prove that `L` and `R` are the same type, /// because it can only be safely constructed with /// [`TypeEq::::NEW`](#associatedconstant.NEW)(or [`new`](#method.new)), /// where both type arguments are the same type. /// /// This type is not too useful by itself, it becomes useful /// [when put inside of an enum](#polymorphic-branching). /// /// /// `TypeEq` uses the `L` type parameter as the more generic type by convention /// (e.g: `TypeEq`). /// This only matters if you're using the type witness traits /// ([`HasTypeWitness`](crate::HasTypeWitness), /// [`MakeTypeWitness`](crate::MakeTypeWitness), /// [`TypeWitnessTypeArg`](crate::TypeWitnessTypeArg)) with `TypeEq`. /// /// # Soundness /// /// `TypeEq` requires both type arguments to be the same type so that /// [projecting](Self::project) the type arguments results in the same type for /// both arguments. /// /// Unsafely creating a `TypeEq` where `L != R` allows /// [transmuting between any two types](#arbitrary-transmute) /// (that is bad). /// /// # Examples /// /// ### Polymorphic branching /// /// This example demonstrates how type witnesses can be used to /// choose between expressions of different types with a constant. /// /// ```rust /// use typewit::TypeEq; /// /// const fn main() { /// assert!(matches!(choose!(0; b"a string", 2, panic!()), b"a string")); /// /// const UNO: u64 = 1; /// assert!(matches!(choose!(UNO; loop{}, [3, 5], true), [3, 5])); /// /// assert!(matches!(choose!(2 + 3; (), unreachable!(), ['5', '3']), ['5', '3'])); /// } /// /// /// Evaluates the argument at position `$chosen % 3`, other arguments aren't evaluated. /// /// /// /// The arguments can all be different types. /// /// /// /// `$chosen` must be a `u64` constant. /// #[macro_export] /// macro_rules! choose { /// ($chosen:expr; $arg_0: expr, $arg_1: expr, $arg_2: expr) => { /// match Choice::<{$chosen % 3}>::VAL { /// // `te` (a `TypeEq`) allows us to safely go between /// // the type that the match returns (its `T` type argument) /// // and the type of `$arg_0` (its `X` type argument). /// Branch3::A(te) => { /// // `to_left` goes from `X` to `T` /// te.to_left($arg_0) /// } /// // same as the `A` branch, with a different type for the argument /// Branch3::B(te) => te.to_left($arg_1), /// // same as the `A` branch, with a different type for the argument /// Branch3::C(te) => te.to_left($arg_2), /// } /// } /// } /// /// // This is a type witness /// pub enum Branch3 { /// // This variant requires `T == X` /// A(TypeEq), /// /// // This variant requires `T == Y` /// B(TypeEq), /// /// // This variant requires `T == Z` /// C(TypeEq), /// } /// /// // Used to get different values of `Branch3` depending on `N` /// pub trait Choice { /// const VAL: Self; /// } /// /// impl Choice<0> for Branch3 { /// // Because the first two type arguments of `Branch3` are `X` /// // (as required by the `TypeEq` field in Branch3's type definition), /// // we can use `TypeEq::NEW` here. /// const VAL: Self = Self::A(TypeEq::NEW); /// } /// /// impl Choice<1> for Branch3 { /// const VAL: Self = Self::B(TypeEq::NEW); /// } /// /// impl Choice<2> for Branch3 { /// const VAL: Self = Self::C(TypeEq::NEW); /// } /// /// ``` /// pub struct TypeEq(PhantomData>); // Declared to work around this error in old Rust versions: // > error[E0658]: function pointers cannot appear in constant functions struct TypeEqHelper( #[allow(dead_code)] fn(PhantomData) -> PhantomData, #[allow(dead_code)] fn(PhantomData) -> PhantomData, ); impl TypeEq { /// Constructs a `TypeEq`. /// /// # Example /// /// ```rust /// use typewit::TypeEq; /// /// assert_eq!(mutate(5, Wit::U32(TypeEq::NEW)), 25); /// /// assert_eq!(mutate(5, Wit::Other(TypeEq::NEW)), 5); /// assert_eq!(mutate("hello", Wit::Other(TypeEq::NEW)), "hello"); /// /// const fn mutate(val: W, wit: Wit) -> W { /// match wit { /// Wit::U32(te) => te.to_left(te.to_right(val) + 20), /// Wit::Other(_) => val, /// } /// } /// /// // This can't be written using the `simple_type_witness` macro because the /// // type in the `Other` variant overlaps with the other ones. /// enum Wit { /// U32(TypeEq), /// Other(TypeEq), /// } /// ``` /// pub const NEW: Self = TypeEq(PhantomData); } impl TypeEq<(), ()> { /// Constructs a `TypeEq`. #[inline(always)] pub const fn new() -> TypeEq { TypeEq::::NEW } } impl TypeEq { /// Constructs `TypeEq` if `L == R`, otherwise returns None. /// /// # Example /// /// ```rust /// use typewit::TypeEq; /// /// use std::any::Any; /// /// assert_eq!(sum_u32s(&[3u32, 5, 8]), Some(16)); /// assert_eq!(sum_u32s(&[3i32, 5, 8]), None); /// /// /// fn sum_u32s(foo: &[T]) -> Option { /// typecast_slice::(foo) /// .map(|foo: &[u32]| foo.iter().copied().sum()) /// } /// /// fn typecast_slice(foo: &[T]) -> Option<&[U]> { /// struct SliceFn; /// impl typewit::TypeFn for SliceFn { /// type Output = [T]; /// } /// /// TypeEq::::with_any().map(|te: TypeEq|{ /// te.map(SliceFn) // TypeEq<[T], [U]> /// .in_ref() // TypeEq<&[T]>, &[U]> /// .to_right(foo) // identity cast from `&[T]` to `&[U]` /// }) /// } /// ``` pub fn with_any() -> Option where L: Sized + Any, R: Sized + Any, { if TypeId::of::() == TypeId::of::() { // SAFETY: the two TypeIds compare equal, so L == R unsafe { Some(TypeEq::new_unchecked()) } } else { None } } /// Constructs a `TypeEq`. /// /// # Safety /// /// You must ensure that `L` is the same type as `R`. /// /// # Examples /// /// ### Unsound usage /// /// /// This example demonstrates why `L == R` is a strict requirement. /// /// ```rust /// use typewit::{TypeEq, TypeFn}; /// /// // SAFETY: WRONG! UNSOUND! /// let te: TypeEq = unsafe{ TypeEq::new_unchecked() }; /// /// // Because `TypeEq` is incorrect, /// // we get this absurd `TypeEq` from the `project` method. /// let absurd: TypeEq<(), Vec> = te.project::(); /// /// // This casts from `()` to `Vec` (which is UB). /// // Last time I tried uncommenting this, it killed the test runner. /// // absurd.to_right(()); /// /// struct Func; /// impl TypeFn for Func { type Output = (); } /// impl TypeFn for Func { type Output = Vec; } /// /// /// ``` /// #[inline(always)] pub const unsafe fn new_unchecked() -> TypeEq { TypeEq(PhantomData) } } } pub use type_eq_::TypeEq; impl Copy for TypeEq {} impl Clone for TypeEq { fn clone(&self) -> Self { *self } } impl TypeEq { /// Converts this `TypeEq` into a [`TypeCmp`](crate::TypeCmp) /// /// # Example /// /// ```rust /// use typewit::{TypeCmp, TypeEq}; /// /// const TC: TypeCmp = TypeEq::NEW.to_cmp(); /// /// assert!(matches!(TC, TypeCmp::Eq(_))); /// ``` #[inline(always)] pub const fn to_cmp(self) -> crate::TypeCmp { crate::TypeCmp::Eq(self) } /// Swaps the type parameters of this `TypeEq` /// /// # Example /// /// ```rust /// use typewit::TypeEq; /// /// assert_eq!(flip_bytes([3, 5], TypeEq::NEW), [5, 3]); /// /// const fn flip_bytes(val: T, te: TypeEq) -> T { /// bar(val, te.flip()) /// } /// const fn bar(val: T, te: TypeEq<[u8; 2], T>) -> T { /// let [l, r] = te.to_left(val); /// te.to_right([r, l]) /// } /// ``` /// #[inline(always)] pub const fn flip(self: TypeEq) -> TypeEq { // SAFETY: L == R implies R == L unsafe { TypeEq::new_unchecked() } } /// Joins this `TypeEq` with a `TypeEq`, producing a `TypeEq`. /// /// The returned `TypeEq` can then be used to coerce between `L` and `O`. /// /// # Example /// /// ```rust /// use typewit::TypeEq; /// /// assert_eq!(foo(TypeEq::NEW, TypeEq::NEW, Some(3)), Some(3)); /// assert_eq!(foo(TypeEq::NEW, TypeEq::NEW, None), None); /// /// /// fn foo( /// this: TypeEq>, /// that: TypeEq, Option>, /// value: Option, /// ) -> L { /// let te: TypeEq> = this.join(that); /// te.to_left(value) /// } /// /// ``` /// #[inline(always)] pub const fn join(self: TypeEq, _other: TypeEq) -> TypeEq { // SAFETY: (L == R, R == O) implies L == O unsafe { TypeEq::new_unchecked() } } } impl TypeEq { /// Combines this `TypeEq` with a `TypeEq`, /// producing a `TypeEq<(L0, L1), (R0, R1)>`. /// /// # Alternative /// /// For an alternative which allows zipping `TypeEq` with any /// [`BaseTypeWitness`](crate::BaseTypeWitness), /// you can use [`methods::zip2`](crate::methods::zip2) /// (requires the `"rust_1_65"` feature) /// /// # Example /// /// This example demonstrates how one can combine two `TypeEq`s to use /// with a multi-parameter type. /// /// ```rust /// use typewit::{const_marker::Usize, TypeEq, TypeFn}; /// /// assert_eq!(make_foo(TypeEq::NEW, TypeEq::NEW), Foo("hello", [3, 5, 8])); /// /// const fn make_foo( /// te_ty: TypeEq, /// te_len: TypeEq, Usize<3>>, /// ) -> Foo { /// // the type annotations are just for the reader, they can be inferred. /// let te_pair: TypeEq<(T, Usize), (&str, Usize<3>)> = te_ty.zip(te_len); /// /// let te: TypeEq, Foo<&str, 3>> = te_pair.project::(); /// /// // `te.to_left(...)` here goes from `Foo<&str, 3>` to `Foo` /// te.to_left(Foo("hello", [3, 5, 8])) /// } /// /// #[derive(Debug, PartialEq)] /// struct Foo(T, [u8; N]); /// /// typewit::type_fn!{ /// // Type-level function from `(T, Usize)` to `Foo` /// struct GFoo; /// /// impl (T, Usize) => Foo /// } /// ``` /// #[inline(always)] pub const fn zip( self: TypeEq, other: TypeEq, ) -> TypeEq<(L0, L1), (R0, R1)> { zip_impl!{self[L0, R0], other[L1, R1]} } /// Combines three `TypeEq` to produce a /// `TypeEq<(L0, L1, L2), (R0, R1, R2)>`. /// /// # Alternative /// /// For an alternative which allows zipping `TypeEq` with two of any /// [`BaseTypeWitness`](crate::BaseTypeWitness), /// you can use [`methods::zip3`](crate::methods::zip3) /// (requires the `"rust_1_65"` feature) /// /// # Example /// /// ```rust /// use typewit::{TypeEq, type_eq}; /// /// use std::cmp::Ordering::{self, Less}; /// /// assert_eq!(make_tuple(type_eq(), type_eq(), type_eq()), (3, "foo", Less)); /// /// fn make_tuple( /// te0: TypeEq, /// te1: TypeEq, /// te2: TypeEq, /// ) -> (A, B, C) { /// te0.zip3(te1, te2) // returns `TypeEq<(A, B, C), (u8, &str, Ordering)>` /// .to_left((3, "foo", Less)) /// } /// /// ``` pub const fn zip3( self: TypeEq, other1: TypeEq, other2: TypeEq, ) -> TypeEq<(L0, L1, L2), (R0, R1, R2)> { zip_impl!{ self[L0, R0], other1[L1, R1], other2[L2, R2], } } /// Combines four `TypeEq` to produce a /// `TypeEq<(L0, L1, L2, L3), (R0, R1, R2, L3)>`. /// /// # Alternative /// /// For an alternative which allows zipping `TypeEq` with three of any /// [`BaseTypeWitness`](crate::BaseTypeWitness), /// you can use [`methods::zip4`](crate::methods::zip4) /// (requires the `"rust_1_65"` feature) /// /// # Example /// /// ```rust /// use typewit::{TypeEq, type_eq}; /// /// use std::cmp::Ordering::{self, Less}; /// /// assert_eq!( /// make_tuple(type_eq(), type_eq(), type_eq(), type_eq()), /// (3, "foo", Less, true), /// ); /// /// fn make_tuple( /// te0: TypeEq, /// te1: TypeEq, /// te2: TypeEq, /// te3: TypeEq, /// ) -> (A, B, C, D) { /// let te: TypeEq<(A, B, C, D), (u8, &str, Ordering, bool)> = te0.zip4(te1, te2, te3); /// te.to_left((3, "foo", Less, true)) /// } /// /// ``` pub const fn zip4( self: TypeEq, other1: TypeEq, other2: TypeEq, other3: TypeEq, ) -> TypeEq<(L0, L1, L2, L3), (R0, R1, R2, R3)> { zip_impl!{ self[L0, R0], other1[L1, R1], other2[L2, R2], other3[L3, R3], } } } impl TypeEq { /// Whether `L` is the same type as `R`. /// /// False positive equality is fine for this associated constant, /// since it's used to optimize out definitely unequal types. const ARE_SAME_TYPE: Amb = { // hacky way to emulate a lifetime-unaware // `TypeId::of() == TypeId::of()` let approx_same_type = { core::mem::size_of::() == core::mem::size_of::() && core::mem::align_of::() == core::mem::align_of::() && core::mem::size_of::>() == core::mem::size_of::>() && core::mem::align_of::>() == core::mem::align_of::>() }; if approx_same_type { Amb::Indefinite } else { Amb::No } }; /// Hints to the compiler that a `TypeEq` /// can only be constructed if `L == R`. /// /// This function takes and returns `val` unmodified. /// This allows returning some value from an expression /// while hinting that `L == R`. /// #[inline(always)] pub const fn reachability_hint(self, val: T) -> T { if let Amb::No = Self::ARE_SAME_TYPE { // safety: `TypeEq` requires `L == R` to be constructed unsafe { core::hint::unreachable_unchecked() } } val } /// A no-op cast from `L` to `R`. /// /// This cast is a no-op because having a `TypeEq` value /// proves that `L` and `R` are the same type. /// /// # Example /// /// ```rust /// use typewit::{TypeEq, type_eq}; /// /// use std::cmp::Ordering::{self, *}; /// /// assert_eq!(mutated(Less, Wit::Ord(type_eq())), Greater); /// assert_eq!(mutated(Equal, Wit::Ord(type_eq())), Equal); /// assert_eq!(mutated(Greater, Wit::Ord(type_eq())), Less); /// /// assert_eq!(mutated(false, Wit::Bool(type_eq())), true); /// assert_eq!(mutated(true, Wit::Bool(type_eq())), false); /// /// const fn mutated(arg: R, w: Wit) -> R { /// match w { /// Wit::Ord(te) => te.to_left(te.to_right(arg).reverse()), /// Wit::Bool(te) => te.to_left(!te.to_right(arg)), /// } /// } /// /// enum Wit { /// Ord(TypeEq), /// Bool(TypeEq), /// } /// ``` /// #[inline(always)] pub const fn to_right(self, from: L) -> R { self.reachability_hint(()); // safety: `TypeEq` requires `L == R` to be constructed unsafe { crate::__priv_transmute!(L, R, from) } } /// A no-op cast from `R` to `L`. /// /// This cast is a no-op because having a `TypeEq` value /// proves that `L` and `R` are the same type. /// /// # Example /// /// ```rust /// use typewit::{TypeEq, type_eq}; /// /// assert_eq!(stuff(Wit::OptSlice(type_eq())), Some(&[3, 5, 8][..])); /// assert_eq!(stuff(Wit::Bool(type_eq())), true); /// /// const fn stuff(te: Wit) -> R { /// match te { /// Wit::OptSlice(te) => te.to_left(Some(&[3, 5, 8])), /// Wit::Bool(te) => te.to_left(true), /// } /// } /// /// enum Wit { /// OptSlice(TypeEq>), /// Bool(TypeEq), /// } /// ``` /// #[inline(always)] pub const fn to_left(self, from: R) -> L { self.reachability_hint(()); // safety: `TypeEq` requires `L == R` to be constructed unsafe { crate::__priv_transmute!(R, L, from) } } } impl TypeWitnessTypeArg for TypeEq { type Arg = L; } impl MakeTypeWitness for TypeEq { const MAKE: Self = Self::NEW; } impl TypeEq { /// Maps the type arguments of this `TypeEq` /// by using the `F` [type-level function](crate::type_fn::TypeFn). /// /// Use this function over [`project`](Self::project) /// if you want the type of the passed in function to be inferred. /// /// # Example /// /// ```rust /// use typewit::{TypeEq, TypeFn}; /// /// assert_eq!(foo(TypeEq::NEW), (false, 5)); /// /// const fn foo<'a, T>(te: TypeEq) -> (bool, T) { /// // `GPair` maps `u32` to `(bool, u32)` /// // and maps `T` to `(bool, T)` /// let map_te: TypeEq<(bool, u32), (bool, T)> = te.map(GPair::::NEW); /// /// // same as the above, but inferring `GPair`'s generic arguments. /// let _: TypeEq<(bool, u32), (bool, T)> = te.map(GPair::NEW); /// /// map_te.to_right((false, 5u32)) /// } /// /// // Declares `struct GPair
`, a type-level function from `B` to `(A, B)` /// typewit::type_fn! { /// struct GPair; /// /// impl B => (A, B) /// } /// ``` /// // #[cfg(feature = "project")] // #[cfg_attr(feature = "docsrs", doc(cfg(feature = "project")))] pub const fn map( self, func: F, ) -> TypeEq, L>, CallFn, R>> where InvokeAlias: crate::TypeFn + crate::TypeFn { core::mem::forget(func); projected_type_cmp!{self, L, R, F} } /// Maps the type arguments of this `TypeEq` /// by using the `F` [type-level function](crate::type_fn::TypeFn). /// /// Use this function over [`map`](Self::map) /// if you want to specify the type of the passed in function explicitly. /// /// # Example /// /// ```rust /// use typewit::{TypeEq, TypeFn}; /// /// assert_eq!(foo(TypeEq::NEW), vec![3u32, 5, 8]); /// /// fn foo(te: TypeEq) -> Vec { /// let vec_te: TypeEq, Vec> = te.project::(); /// vec_te.to_right(vec![3, 5, 8]) /// } /// /// // Declares `GVec`, a type-level function from `T` to `Vec` /// typewit::type_fn!{ /// struct GVec; /// /// impl T => Vec /// } /// /// ``` /// pub const fn project(self) -> TypeEq, L>, CallFn, R>> where InvokeAlias: crate::TypeFn + crate::TypeFn { projected_type_cmp!{self, L, R, F} } } impl TypeEq { /// Maps the type arguments of this `TypeEq` /// by using the [reversed](crate::RevTypeFn) /// version of the `F` type-level function. /// /// Use this function over [`unproject`](Self::unproject) /// if you want the type of the passed in function to be inferred. /// /// # Example /// /// ```rust /// use typewit::{TypeEq, UncallFn}; /// /// assert_eq!(first_int(&[3, 5, 8, 13], TypeEq::NEW), 3); /// /// const fn first_int( /// array: &[T; N], /// te_slice: TypeEq<[T], [u8]>, /// ) -> u8 { /// let te: TypeEq = te_slice.unmap(SliceFn); /// /// let te_ref: TypeEq<&T, &u8> = te.in_ref(); /// /// *te_ref.to_right(&array[0]) /// } /// /// typewit::inj_type_fn! { /// struct SliceFn; /// /// impl T => [T] /// } /// ``` pub const fn unmap( self, func: F, ) -> TypeEq, L>, UncallFn, R>> where InvokeAlias: RevTypeFn + RevTypeFn { core::mem::forget(func); unprojected_type_cmp!{self, L, R, F} } /// Maps the type arguments of this `TypeEq` /// by using the [reversed](crate::RevTypeFn) /// version of the `F` type-level function. /// /// Use this function over [`unmap`](Self::unmap) /// if you want to specify the type of the passed in function explicitly. /// /// # Example /// /// ```rust /// use typewit::TypeEq; /// use std::ops::{Range, RangeInclusive as RangeInc}; /// /// assert_eq!(usize_bounds(3..=5, TypeEq::NEW), (3, 5)); /// /// const fn usize_bounds( /// range: RangeInc, /// te_range: TypeEq, Range>, /// ) -> (usize, usize) { /// let te: TypeEq = te_range.unproject::(); /// /// let te_range_inc: TypeEq, RangeInc> = te.project::(); /// /// let range: RangeInc = te_range_inc.to_right(range); /// /// (*range.start(), *range.end()) /// } /// /// typewit::inj_type_fn! { /// struct RangeFn; /// /// impl T => Range /// } /// typewit::inj_type_fn! { /// struct RangeIncFn; /// /// impl T => RangeInc /// } /// ``` pub const fn unproject( self, ) -> TypeEq, L>, UncallFn, R>> where InvokeAlias: crate::RevTypeFn + crate::RevTypeFn { unprojected_type_cmp!{self, L, R, F} } } impl TypeEq { /// Converts a `TypeEq` to `TypeEq<&L, &R>` /// /// # Example /// /// ```rust /// use typewit::{MakeTypeWitness, TypeEq}; /// /// assert_eq!(get::(), &3); /// assert_eq!(get::(), "hello"); /// /// /// const fn get() -> &'static R /// where /// Returned: MakeTypeWitness /// { /// match MakeTypeWitness::MAKE { /// // `te` is a `TypeEq` /// Returned::U8(te) => te.in_ref().to_left(&3), /// /// // `te` is a `TypeEq` /// Returned::Str(te) => te.in_ref().to_left("hello"), /// } /// } /// /// typewit::simple_type_witness! { /// // declares the `enum Returned {` type witness /// enum Returned { /// // this variant requires `R == u8` /// U8 = u8, /// // this variant requires `R == str` /// Str = str, /// } /// } /// ``` /// pub const fn in_ref<'a>(self) -> TypeEq<&'a L, &'a R> { projected_type_cmp!{self, L, R, type_fn::GRef<'a>} } crate::utils::conditionally_const!{ feature = "rust_1_83"; /// Converts a `TypeEq` to `TypeEq<&mut L, &mut R>` /// /// # Constness /// /// This requires the `"rust_1_83"` feature to be a `const fn`. /// /// # Example /// /// Because this example calls `in_mut` inside a `const fn`, /// it requires the `"rust_1_83"` crate feature. #[cfg_attr(not(feature = "rust_1_83"), doc = "```ignore")] #[cfg_attr(feature = "rust_1_83", doc = "```rust")] /// /// use typewit::{TypeEq, type_eq}; /// /// let foo = &mut Foo { bar: 10, baz: ['W', 'H', 'O'] }; /// /// *get_mut(foo, Field::Bar(type_eq())) *= 2; /// assert_eq!(foo.bar, 20); /// /// assert_eq!(*get_mut(foo, Field::Baz(type_eq())), ['W', 'H', 'O']); /// /// /// const fn get_mut(foo: &mut Foo, te: Field) -> &mut R { /// match te { /// Field::Bar(te) => te.in_mut().to_left(&mut foo.bar), /// Field::Baz(te) => te.in_mut().to_left(&mut foo.baz), /// } /// } /// /// struct Foo { /// bar: u8, /// baz: [char; 3], /// } /// /// enum Field { /// Bar(TypeEq), /// Baz(TypeEq), /// } /// ``` /// pub fn in_mut['a](self) -> TypeEq<&'a mut L, &'a mut R> { projected_type_cmp!{self, L, R, type_fn::GRefMut<'a>} } } /// Converts a `TypeEq` to `TypeEq, Box>` /// /// # Example /// /// ```rust /// use typewit::{MakeTypeWitness, TypeEq, type_eq}; /// /// use std::any::Any; /// use std::fmt::Display; /// /// assert_eq!(factory::().downcast::().unwrap(), Box::new(1337)); /// assert_eq!(factory::().to_string(), "hello bob"); /// /// fn factory() -> Box /// where /// Dyn: MakeTypeWitness /// { /// match MakeTypeWitness::MAKE { /// // `te` is a `TypeEq` /// Dyn::Any(te) => te.in_box().to_left(Box::new(1337u16)), /// /// // `te` is a `TypeEq` /// Dyn::Display(te) => te.in_box().to_left(Box::new("hello bob")), /// } /// } /// /// typewit::simple_type_witness! { /// // declares the `enum Dyn {` type witness /// enum Dyn { /// // this variant requires `R == dyn Any` /// Any = dyn Any, /// // this variant requires `R == dyn Display` /// Display = dyn Display, /// } /// } /// /// ``` /// #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] pub const fn in_box(self) -> TypeEq, Box> { projected_type_cmp!{self, L, R, type_fn::GBox} } } impl TypeEq { /// Combines `TypeEq` and `TypeEq, Usize>` /// into `TypeEq<[L; UL], [R; UR]>` /// /// # Alternative /// /// For an alternative which allows passing any /// [`BaseTypeWitness`](crate::BaseTypeWitness) for the length, /// you can use [`methods::in_array`](crate::methods::in_array) /// (requires the `"rust_1_65"` feature) /// /// /// # Example /// ///
/// motivation ///

/// The safe way to map an array in const fns(on stable Rust in 2023) /// is to create an array of the returned type with some dummy value, /// and then fill it in with the desired values. /// /// Because the function in this example takes a `[T; LEN]` where the `T` is generic, /// it copies the first element of the input array to initialize the returned array, /// so we must handle empty arrays, /// but trying to return an empty array the naive way /// ```compile_fail /// # use std::num::Wrapping; /// # const fn map_wrapping(arr: [T; LEN]) -> [Wrapping; LEN] { /// if LEN == 0 { /// return []; /// } /// # unimplemented!() /// # } /// ``` /// does not work /// ```text /// error[E0308]: mismatched types /// --> src/type_eq.rs:827:16 /// | /// 4 | const fn map_wrapping(arr: [T; LEN]) -> [Wrapping; LEN] { /// | ------------------ expected `[Wrapping; LEN]` because of return type /// 5 | if LEN == 0 { /// 6 | return []; /// | ^^ expected `LEN`, found `0` /// | /// = note: expected array `[Wrapping; LEN]` /// found array `[_; 0]` /// /// ``` ///

///
/// /// This example demonstrates how `in_array` allows one to return an empty array: /// (this example requires Rust 1.61.0, because it uses trait bounds in const fns) #[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")] #[cfg_attr(feature = "rust_1_61", doc = "```rust")] /// use typewit::{const_marker::Usize, TypeCmp, TypeEq}; /// /// use std::num::Wrapping; /// /// assert_eq!(map_wrapping([""; 0]), []); /// assert_eq!(map_wrapping([3, 5, 8]), [Wrapping(3), Wrapping(5), Wrapping(8)]); /// /// const fn map_wrapping(arr: [T; LEN]) -> [Wrapping; LEN] { /// // `teq` is a `TypeEq, Usize<0>>` /// if let TypeCmp::Eq(teq) = Usize::.equals(Usize::<0>) { /// return TypeEq::new::>() /// .in_array(teq) // `TypeEq<[Wrapping; LEN], [Wrapping; 0]>` /// .to_left([]); /// } /// /// let mut ret = [Wrapping(arr[0]); LEN]; /// let mut i = 1; /// /// while i < LEN { /// ret[i] = Wrapping(arr[i]); /// i += 1; /// } /// /// ret /// } /// ``` #[inline(always)] pub const fn in_array( self, other: TypeEq, Usize>, ) -> TypeEq<[L; UL], [R; UR]> { zip_project!{ self, other, crate::type_fn::PairToArrayFn, (L, R), (Usize