commit ef8f15a2e07cb784d5db796c147361bd1968ece0 Author: TudbuT Date: Tue Nov 14 20:34:07 2023 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ec9f865 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "type-fn" +version = "0.1.0" +edition = "2021" +description = "Allows for simpler coding of type-level logic, e.g. for type-number systems." +license = "MIT" +repository = "https://github.com/tudbut/type-fn" + +[dependencies] diff --git a/README.md b/README.md new file mode 100644 index 0000000..5cfa58d --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# type-fn + +type-fn allows you to more simply create logic at the type level. + +## Example + +Unsigned addition, subtraction, and multiplication: + +```rs +struct Zero; +struct Succ(PhantomData); +type_fn! { + fn Add; + fn Sub; + fn Mul; +} +type_fn_impl! { + fn Add< => Zero, Rhs> => Rhs; + fn Add Succ, Rhs> + where + Add: + TypeFn, + => Succ< as TypeFn>::Ret>; + + fn Sub Zero> => Lhs; + fn Sub Succ, Rhs => Succ> + where + Sub : + TypeFn, + => as TypeFn>::Ret; + + fn Mul< => Zero, Rhs> => Zero; + fn Mul Succ, Rhs> + where + Mul: + TypeFn, + Add as TypeFn>::Ret>: + TypeFn, + => as TypeFn>::Ret> as TypeFn>::Ret; +} +``` diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..6ccda22 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,117 @@ +#![no_std] + +/// Default trait for returning something from a type-fn +pub trait TypeFn { + type Ret; +} + +/// Verifies equality between two types at compile-time. +#[macro_export] +macro_rules! assert_types_eq { + ($a:ty, $b:ty) => {{ + let _: ::core::marker::PhantomData<$a> = ::core::marker::PhantomData::<$b>; + }}; +} + +/// Generates type-fn implementations. +/// Syntax: +/// `fn<$FnType$> $name$<$args$> $[$where-clause$]$ => $return-type$;` +/// +/// FnType should simply be a trait containing `type Ret`, e.g. [`TypeFn`]. +/// +/// args is a type-arg list. To pattern-match types, use `T => Successor` to +/// implement something like like `Add, Rhs>`. +/// When implementing something for a specific type, use ` => TypeHere` (leave out +/// the type arg name). +/// If you need an extra type arg that wont be in the resulting type anywhere, +/// add a bar `|` and write type args there as normal. +/// +/// The where clause is just like rust's, except you need to put a plus before the first +/// trait bound as well. Trailing commas are also mandatory. +/// Trait bounds can only be set using the where-clause. +/// +/// The return type can use any of the type arguments. +/// +/// You can define an arbitrary amount of functions in one macro invocation. +#[macro_export] +macro_rules! type_fn_impl { + (@a_or_else_b => ) => {compiler_error!()}; + (@a_or_else_b => $($b:ident)+) => {$($b)*}; + (@a_or_else_b $($a:ty)+ => $($b:ident)*) => { $($a)+ }; + ($(fn < $sup:ty > $name:ident <$($($arg:ident)? $(=> $($argv:ty)+)?),* $(| $($targ:ident),+)?> + $(where $($tv:ty : $( + $( ?$tcqm:ident )? $( $tc:ident )? )+ ,)+)? => $ret:ty;)+) + => { + $( + impl<$($($arg, )?)* $($($targ, )*)?> + $sup for $name <$($crate::type_fn_impl!(@a_or_else_b $($($argv)*)? => $($arg)?)),*> + $(where $($tv : $($(?$tcqm)? $($tc)? + )+ ),+)? + { + type Ret = $ret; + } + )+ + }; +} + +/// Creates type functions. You will still need to implement them yourself, e.g. using +/// [`type_fn_impl!`]. +/// Syntax: +/// `$[$visibility$]$ fn $name$ <$args$>;` +/// +/// visibility is just like rust's normal visibility modifier. +/// +/// args is a list of type arguments. They can not have constraints at this time. +#[macro_export] +macro_rules! type_fn { + ($($vis:vis fn $name:ident <$($arg:ident),*>;)*) => { + $( + $vis struct $name <$($arg),*> ($(::core::marker::PhantomData<$arg>, )*); + )* + }; +} + +#[cfg(test)] +mod tests { + use core::marker::PhantomData; + + use crate::TypeFn; + + #[test] + fn test_compile() { + struct Zero; + struct Succ(PhantomData); + type_fn! { + fn Add; + fn Sub; + fn Mul; + } + type_fn_impl! { + fn Add< => Zero, Rhs> => Rhs; + fn Add Succ, Rhs> + where + Add: + TypeFn, + => Succ< as TypeFn>::Ret>; + + fn Sub Zero> => Lhs; + fn Sub Succ, Rhs => Succ> + where + Sub : + TypeFn, + => as TypeFn>::Ret; + + fn Mul< => Zero, Rhs> => Zero; + fn Mul Succ, Rhs> + where + Mul: + TypeFn, + Add as TypeFn>::Ret>: + TypeFn, + => as TypeFn>::Ret> as TypeFn>::Ret; + } + + type TwoMinusOne = >, Succ> as TypeFn>::Ret; + assert_types_eq!(TwoMinusOne, Succ); + assert_types_eq!(> as TypeFn>::Ret, Zero); + assert_types_eq!( + Succ>>>, + >, Succ>> as TypeFn>::Ret + ); + assert_types_eq!(Zero, >, Zero> as TypeFn>::Ret); + } +}