fp_library/
macros.rs

1//! Macros.
2
3/// Generates a [`KindN` trait][crate::hkt::kinds] of a specific arity and its corresponding blanket implementation.
4#[macro_export]
5macro_rules! make_trait_kind {
6	(
7		// Kind trait name (e.g., Kind2).
8		$KindN:ident,
9		// Apply type alias name (e.g., Apply2).
10		$ApplyN:ident,
11		// String representation of the kind (e.g., "* -> * -> *").
12		$kind_string:literal,
13		// List of generic type parameters (e.g., (A, B)).
14		($($Generics:ident),+)
15	) => {
16		#[doc = concat!(
17			"Trait for [brands][crate::brands] of [types][crate::types] of kind `",
18			$kind_string,
19			"`."
20		)]
21		pub trait $KindN<$($Generics),+> {
22			type Output;
23		}
24
25		impl<Brand, $($Generics),+> Kind<($($Generics,)+)> for Brand
26		where
27			Brand: $KindN<$($Generics),+>,
28		{
29			type Output = $ApplyN<Brand, $($Generics),+>;
30		}
31	};
32}
33
34/// Generates an [`ApplyN` type alias][crate::hkt::apply] of a specific arity.
35#[macro_export]
36macro_rules! make_type_apply {
37	(
38		// Kind trait name (e.g., Kind2).
39		$KindN:ident,
40		// Apply type alias name (e.g., Apply2).
41		$ApplyN:ident,
42		// String representation of the kind (e.g., "* -> * -> *").
43		$kind_string:literal,
44		// List of generic type parameters (e.g., (A, B)).
45		($($Generics:ident),+)
46	) => {
47		#[doc = concat!(
48			"Alias for [types][crate::types] of kind `",
49			$kind_string,
50			"`."
51		)]
52		pub type $ApplyN<Brand, $($Generics),+> = <Brand as $KindN<$($Generics),+>>::Output;
53	};
54}
55
56/// Generates a [`BrandN` trait][crate::hkt::brands] of a specific arity and its corresponding blanket implementation.
57#[macro_export]
58macro_rules! make_trait_brand {
59	(
60		// Brand trait name (e.g., Brand2).
61		$BrandN:ident,
62		// String representation of the kind (e.g., "* -> * -> *").
63		$kind_string:literal,
64		// List of generic type parameters (e.g., (A, B)).
65		($($Generics:ident),+)
66	) => {
67		#[doc = concat!(
68			"[`BrandN` trait][crate::hkt::brands] for [types][crate::types] with kind `",
69			$kind_string,
70			"`."
71		)]
72		pub trait $BrandN<Concrete, $($Generics),+>
73		where
74			Self: Kind<($($Generics,)+)>,
75		{
76			fn inject(a: Concrete) -> Apply<Self, ($($Generics,)+)>;
77			fn project(a: Apply<Self, ($($Generics,)+)>) -> Concrete;
78		}
79
80		impl<Me, Concrete, $($Generics),+> Brand<Concrete, ($($Generics,)+)> for Me
81		where
82			Me: Kind<($($Generics,)+)> + $BrandN<Concrete, $($Generics),+>,
83		{
84			fn inject(a: Concrete) -> Apply<Self, ($($Generics,)+)> {
85				<Me as $BrandN<Concrete, $($Generics),+>>::inject(a)
86			}
87
88			fn project(a: Apply<Self, ($($Generics,)+)>) -> Concrete {
89				<Me as $BrandN<Concrete, $($Generics),+>>::project(a)
90			}
91		}
92	};
93}
94
95/// Generates a [brand type][crate::brands] and its [`BrandN` trait][crate::hkt::brands] implementation.
96#[macro_export]
97macro_rules! impl_brand {
98	(
99		// Brand type name (e.g., PairBrand).
100		$Brand:ident,
101		// Concrete type name (e.g., Pair).
102		$Concrete:ident,
103		// Kind trait name (e.g., Kind2).
104		$KindN:ident,
105		// Brand trait name (e.g., Brand2).
106		$BrandN:ident,
107		// List of generic type parameters (e.g., (A, B)).
108		($($Generics:ident),+)
109	) => {
110		#[doc = concat!(
111			"[Brand][crate::brands] for [`",
112			stringify!($Concrete),
113			"`]."
114		)]
115		pub struct $Brand;
116
117		impl<$($Generics),+> $KindN<$($Generics),+> for $Brand {
118			type Output = $Concrete<$($Generics),+>;
119		}
120
121		impl<$($Generics),+> $BrandN<$Concrete<$($Generics),+>, $($Generics,)+> for $Brand {
122			fn inject(a: $Concrete<$($Generics),+>) -> Apply<Self, ($($Generics,)+)> {
123				a
124			}
125
126			fn project(a: Apply<Self, ($($Generics,)+)>) -> $Concrete<$($Generics),+> {
127				a
128			}
129		}
130	}
131}