typewit/macros/
type_fn_macro.rs

1/// Declares a type-level function (struct that implements [`TypeFn`](crate::TypeFn))
2/// 
3/// [**examples below**](#examples)
4/// 
5/// # Syntax
6/// 
7/// This section uses a `macro_rules!`-like syntax for 
8/// the parameters that `type_fn` takes
9/// ```text
10/// $(#[$attrs:meta])*
11/// $vis:vis struct $struct_name:ident $(< $struct_generics:generic_params >)?
12/// $( where $struct_where_predicates:where_predicates  )?;
13/// 
14/// $(
15///     $(#[$impl_attrs:meta])*
16///     impl $(<$fn_generics:generic_params>)? $argument_type:ty => $return_type:ty
17///     $( where $fn_where_predicates:where_predicates  )?
18/// );+
19/// 
20/// $(;)?
21/// ```
22/// 
23/// `:where_predicates` is a sequence of constraints.
24/// e.g: `T: Foo, 'a: 'b, U: 'b`.
25/// 
26/// `:generic_params` is a list of generic parameter declarations.
27/// e.g: `'a, T, #[cfg(feature = "hi")] U, const N: usize`.
28/// 
29/// Generic parameters support the `#[cfg(...)]` attribute, 
30/// no other attribute is supported.
31/// 
32/// # Generated code 
33/// 
34/// This macro generates:
35/// 
36/// - The struct declaration passed to the macro
37/// 
38/// - A `NEW` associated constant for constructing the struct
39/// 
40/// - Impls of [`TypeFn`] for the generated struct corresponding to 
41/// each `... => ...` argument.
42/// 
43/// If the struct has any lifetime or type parameters
44/// (even if disabled by `#[cfg(...)]` attributes), 
45/// it has a private field,
46/// and requires using its `NEW` associated constant to be instantiated.
47/// If it has no type or lifetime parameters, the struct is a unit struct.
48/// 
49/// # Examples
50/// 
51/// This macro is also demonstrated in [`TypeEq::project`], [`TypeEq::map`],
52/// and the [Indexing polymorphism](crate#example-uses-type-fn) root module example.
53/// 
54/// ### Basic
55/// 
56/// ```rust
57/// use typewit::CallFn;
58/// 
59/// let item: CallFn<FnIterItem, Vec<&'static str>> = "hello";
60/// let _: &'static str = item;
61/// assert_eq!(item, "hello");
62/// 
63/// // Declares `struct FnIterItem`,
64/// // a type-level function from `I` to `<I as IntoIterator>::Item`
65/// typewit::type_fn!{
66///     struct FnIterItem;
67/// 
68///     impl<I: IntoIterator> I => I::Item
69/// }
70/// ```
71/// 
72/// ### All syntax
73/// 
74/// Demonstrates all the syntax that this macro accepts and what it expands into:
75/// 
76#[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")]
77#[cfg_attr(feature = "rust_1_61", doc = "```rust")]
78/// typewit::type_fn! {
79///     /// Hello
80///     pub struct Foo<'a, T: IntoIterator = Vec<u8>, #[cfg(any())] const N: usize = 3>
81///     where T: Clone;
82///     
83///     /// docs for impl
84///     #[cfg(all())]
85///     impl<'b: 'a, U, #[cfg(all())] const M: usize> 
86///         [&'b U; M] => ([&'b U; M], T::IntoIter)
87///     where 
88///         U: 'static,
89///         u32: From<U>;
90/// 
91///     /// docs for another impl
92///     impl () => T::Item
93/// }
94/// ```
95/// the above macro invocation generates code equivalent to this:
96#[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")]
97#[cfg_attr(feature = "rust_1_61", doc = "```rust")]
98/// use typewit::TypeFn;
99/// 
100/// use core::marker::PhantomData;
101/// 
102/// /// Hello
103/// // The `const N: usize = 3` param is removed by the `#[cfg(any()))]` attribute
104/// pub struct Foo<'a, T: IntoIterator = Vec<u8>>(
105///     PhantomData<(&'a (), fn() -> T)>
106/// ) where T: Clone;
107/// 
108/// impl<'a, T: IntoIterator> Foo<'a, T>
109/// where
110///     T: Clone,
111/// {
112///     pub const NEW: Self = Self(PhantomData);
113/// }
114/// 
115/// /// docs for impl
116/// #[cfg(all())]
117/// impl<'a, 'b: 'a, U, T: IntoIterator, #[cfg(all())] const M: usize> 
118///     TypeFn<[&'b U; M]> 
119/// for Foo<'a, T>
120/// where
121///     T: Clone,
122///     U: 'static,
123///     u32: From<U>
124/// {
125///     type Output = ([&'b U; M], T::IntoIter);
126/// }
127/// 
128/// /// docs for another impl
129/// impl<'a, T: IntoIterator> TypeFn<()> for Foo<'a, T>
130/// where
131///     T: Clone,
132/// {
133///     type Output = T::Item;
134/// }
135/// 
136/// ```
137/// 
138/// [`TypeFn`]: crate::TypeFn
139/// [`TypeEq::project`]: crate::TypeEq::project
140/// [`TypeEq::map`]: crate::TypeEq::map
141#[macro_export]
142macro_rules! type_fn {
143    ($($args:tt)*) => {
144        $crate::__type_fn!{
145            __tyfn_typefn_impl
146            $($args)*
147        }
148    }
149}
150
151#[doc(hidden)]
152#[macro_export]
153macro_rules! __type_fn {
154    (
155        $typefn_impl_callback:ident
156
157        $(#[$attrs:meta])*
158        $vis:vis struct $struct_name:ident < $($rem:tt)*
159    ) => {
160        $crate::__::__parse_in_generics! {
161            ($crate::__tyfn_parsed_capture_generics !((
162                $typefn_impl_callback
163
164                $(#[$attrs])*
165                $vis struct $struct_name
166            )))
167            [] [] [$($rem)*]
168        }
169    };
170    (
171        $typefn_impl_callback:ident
172
173        $(#[$attrs:meta])*
174        $vis:vis struct $struct_name:ident
175        $($rem:tt)*
176    ) => {
177        $crate::__trailing_comma_for_where_clause!{
178            ($crate::__tyfn_parsed_capture_where! (
179                (
180                    $typefn_impl_callback
181
182                    $(#[$attrs])*
183                    $vis struct $struct_name [] [] []
184                )
185            ))
186            []
187            [$($rem)*]
188        }
189    };
190    ($($rem:tt)*) => {
191        $crate::__::compile_error!{
192            "invalid argument for `type_fn` macro\n\
193             expected struct declaration followed by type-level function definitions"
194        }
195    };
196}
197
198#[doc(hidden)]
199#[macro_export]
200macro_rules! __tyfn_parsed_capture_generics {
201    (
202        ($($struct_stuff:tt)*)
203        $capture_gen_args:tt
204        $capture_generics:tt
205        $deleted_markers:tt
206        where $($rem:tt)*
207    ) => {
208        $crate::__trailing_comma_for_where_clause!{
209            ($crate::__tyfn_parsed_capture_where! (
210                ( $($struct_stuff)* $capture_gen_args $capture_generics $deleted_markers )
211            ))
212            []
213            [$($rem)*]
214        }
215    };
216    (
217        ($($struct_stuff:tt)*)
218        $capture_gen_args:tt
219        $capture_generics:tt
220        $deleted_markers:tt
221        ;$($rem:tt)*
222    ) => {
223        $crate::__tyfn_parsed_capture_where! {
224            ( $($struct_stuff)* $capture_gen_args $capture_generics $deleted_markers )
225            []
226            $($rem)*
227        }
228    };
229    (
230        $struct_stuff:tt
231        $capture_gen_args:tt
232        $capture_generics:tt
233        $deleted_markers:tt
234        $($first_token:tt $($rem:tt)*)?
235    ) => {
236        $crate::__::compile_error!{$crate::__::concat!(
237            "expected `;` after struct definition",
238            $( ", found `" $crate::__::stringify!($first_token), "`")?
239        )}
240    };
241}
242
243#[doc(hidden)]
244#[macro_export]
245macro_rules! __tyfn_parsed_capture_where {
246    (
247        ($($struct_stuff:tt)*)
248        $captures_where:tt
249        $($fns:tt)+
250    ) => {
251        $crate::__tyfn_parse_fns! {
252            ( $($struct_stuff)* captures_where $captures_where )
253            []
254            [$($fns)*]
255            [$($fns)*]
256        }
257    };
258    (
259        ($($struct_stuff:tt)*)
260        [impl $($fns:tt)*]
261    ) => {
262        $crate::__::compile_error!{"expected `;` after struct declaration, found `impl`"}
263    };
264    (
265        $struct_stuff:tt
266        $where_predicates:tt
267    ) => {
268        $crate::__::compile_error!{"expected at least one type-level function definition"}
269    };
270}
271
272
273#[doc(hidden)]
274#[macro_export]
275macro_rules! __tyfn_parse_fns {
276    (
277        (
278            $typefn_impl_callback:ident
279
280            $(#[$attrs:meta])*
281            $vis:vis struct $struct_name:ident 
282
283            $capture_gen_args:tt
284            $capture_generics:tt
285            $erased_lt_ty_marker:tt
286            captures_where $captures_where:tt
287        )
288
289        $fns:tt
290        []
291        $rem_dup:tt // duplicate of the parsed tokens
292    ) => {
293        $crate::__tyfn_split_capture_generics! {
294            $typefn_impl_callback
295
296            $fns
297
298            $(#[$attrs])*
299            $vis struct $struct_name 
300
301            $capture_gen_args
302            $capture_gen_args
303            $capture_generics
304            $erased_lt_ty_marker
305            captures_where $captures_where
306        }
307    };
308    ( $fixed:tt $fns:tt [] []) => {
309        $crate::__::compile_error!{$crate::__::concat!(
310            "bug: unhandled syntax in `typewit` macro: ",
311            stringify!($fixed),
312            stringify!($fns),
313        )}
314    };
315    (
316        $fixed:tt
317        $fns:tt
318        [
319            $(#[$impl_attrs:meta])*
320            impl < $($rem:tt)*
321        ]
322        [ $(#[$_attr:meta])* $impl:ident $($rem_dup:tt)* ]
323    ) => {
324        $crate::__::__parse_in_generics!{
325            ($crate::__tyfn_parsed_fn_generics!(
326                $fixed
327                $fns
328                [$(#[$impl_attrs])* $impl]
329            ))
330            [] [] [$($rem)*]
331        }
332    };
333    (
334        $fixed:tt
335        $fns:tt
336        [
337            $(#[$impl_attrs:meta])*
338            impl $($rem:tt)*
339        ]
340        [ $(#[$_attr:meta])* $impl:ident $($rem_dup:tt)* ]
341    ) => {
342        $crate::__tyfn_parsed_fn_generics!{
343            $fixed
344            $fns
345            [$(#[$impl_attrs])* $impl]
346            [] [] [] $($rem)*
347        }
348    };
349    (
350        $fixed:tt
351        $fns:tt
352        [
353            $(#[$impl_attrs:meta])*
354            impl $type_fn_arg:ty => $ret_ty:ty
355            where $($rem:tt)*
356        ]
357        [ $(#[$_attr:meta])* $impl:ident $($rem_dup:tt)* ]
358    ) => {
359        $crate::__trailing_comma_for_where_clause!{
360            ($crate::__tyfn_parsed_fn_where!(
361                $fixed
362                $fns
363                [
364                    $(#[$impl_attrs])*
365                    $impl[] $type_fn_arg => $ret_ty
366                ]
367            ))
368            []
369            [$($rem)*]
370        }
371    };
372    (
373        $fixed:tt
374        [$($fns:tt)*]
375        [
376            $(#[$impl_attrs:meta])*
377            impl $type_fn_arg:ty => $ret_ty:ty
378            $(; $($rem:tt)*)?
379        ]
380        [ $(#[$_attr:meta])* $impl:ident $($rem_dup:tt)* ]
381    ) => {
382        $crate::__tyfn_parse_fns!{
383            $fixed
384            [
385                $($fns)*
386                (
387                    $(#[$impl_attrs])*
388                    $impl[] $type_fn_arg => $ret_ty
389                    where[]
390                )
391            ]
392            [$($($rem)*)?]
393            [$($($rem)*)?]
394        }
395    };
396    (
397        $fixed:tt
398        $fns:tt
399        [
400            $(#[$impl_attrs:meta])*
401            $type_fn_arg:ty => $($rem:tt)*
402        ]
403        $rem_dup:tt
404    ) => {
405        $crate::__::compile_error!{$crate::__::concat!(
406            "expected `impl`, found `",
407            $crate::__::stringify!($type_fn_arg =>),
408            "`\n",
409            "helo: `impl ",
410            $crate::__::stringify!($type_fn_arg =>),
411            "` is likely to work."
412        )}
413    };
414    (
415        $fixed:tt
416        $fns:tt
417        [ $(#[$attrs:meta])* impl $arg:ty where $($rem:tt)* ]
418        $rem_dup:tt
419    ) => {
420        $crate::__::compile_error!{"where clauses for functions go after the return type"}
421    };
422    ( $fixed:tt [] [] [] ) => {
423        $crate::__::compile_error!{"expected type-level function definitions"}
424    };
425}
426
427
428#[doc(hidden)]
429#[macro_export]
430macro_rules! __tyfn_parsed_fn_generics {
431    (
432        $fixed:tt
433        [$($fns:tt)*]
434        [$($prev_impl_tts:tt)*]
435        $__gen_args:tt
436        $gen_params:tt
437        $deleted_markers:tt
438        $type_fn_arg:ty => $ret_ty:ty
439        $(; $($rem:tt)*)?
440    ) => {
441        $crate::__tyfn_parse_fns!{
442            $fixed
443            [
444                $($fns)*
445                (
446                    $($prev_impl_tts)* $gen_params $type_fn_arg => $ret_ty
447                    where[]
448                )
449            ]
450            [$($($rem)*)?]
451            [$($($rem)*)?]
452        }
453    };
454    (
455        $fixed:tt
456        $fns:tt
457        [$($prev_impl_tts:tt)*]
458        $__gen_args:tt
459        $gen_params:tt
460        $deleted_markers:tt
461        $type_fn_arg:ty => $ret_ty:ty
462        where $($rem:tt)*
463    ) => {
464        $crate::__trailing_comma_for_where_clause!{
465            ($crate::__tyfn_parsed_fn_where!(
466                $fixed
467                $fns
468                [
469                    $($prev_impl_tts)* $gen_params $type_fn_arg => $ret_ty
470                ]
471            ))
472            []
473            [$($rem)*]
474        }
475    };
476    (
477        $fixed:tt
478        $fns:tt
479        $impl_attrs:tt
480        $__gen_args:tt
481        $gen_params:tt
482        $type_fn_arg:ty where $($rem:tt)*
483    ) => {
484        $crate::__::compile_error!{"where clauses for functions go after the return type"}
485    };
486}
487
488#[doc(hidden)]
489#[macro_export]
490macro_rules! __tyfn_parsed_fn_where {
491    (
492        $fixed:tt
493        [$($fns:tt)*]
494        [ $($fn_decl:tt)* ]
495        $where_preds:tt
496
497        $($rem:tt)*
498    ) => {
499        $crate::__tyfn_parse_fns!{
500            $fixed
501            [ $($fns)* ( $($fn_decl)* where $where_preds ) ]
502            [$($rem)*]
503            [$($rem)*]
504        }
505    };
506}
507
508
509
510#[doc(hidden)]
511#[macro_export]
512macro_rules! __tyfn_split_capture_generics {
513    (
514        $typefn_impl_callback:ident
515        $functions:tt
516        
517        $(#[$attrs:meta])*
518        $vis:vis struct $struct_name:ident 
519
520        $capture_gen_args:tt
521        [$(($gen_arg:tt ($($($gen_phantom:tt)+)?) $($gen_rem:tt)*))*]
522        $capture_generics:tt
523        [$($erased_lt_ty_marker:tt)*]
524        captures_where $captures_where:tt
525    ) => {
526        $crate::__tyfn_parsed!{
527            $typefn_impl_callback
528            $functions
529            
530            $(#[$attrs])*
531            $vis struct $struct_name
532            $capture_gen_args
533            [$($(($($gen_phantom)+))?)* $(($erased_lt_ty_marker))*]
534            $capture_generics
535            $captures_where
536        }
537    }
538}
539
540
541#[doc(hidden)]
542#[macro_export]
543macro_rules! __tyfn_parsed {
544    (
545        $typefn_impl_callback:ident
546        [$($functions:tt)+]
547        
548        $(#[$attrs:meta])*
549        $vis:vis struct $function_name:ident
550        $capt_gen_args:tt
551        $capt_gen_phantom:tt
552        $capt_generics:tt
553        // where clause of the captures
554        $captures_where:tt 
555    ) => {
556        $crate::__tyfn_declare_struct!{
557            (
558                $(#[$attrs])*
559                $vis struct $function_name
560            )
561            $capt_gen_args
562            $capt_gen_phantom
563            $capt_generics
564            where $captures_where
565        }
566
567        $(
568            $crate::$typefn_impl_callback!{
569                $functions
570
571                $function_name
572
573                $capt_gen_args
574                $capt_generics
575                where $captures_where 
576            }
577        )*
578    }
579}
580
581#[doc(hidden)]
582#[macro_export]
583macro_rules! __tyfn_declare_struct {
584    (
585        (
586            $(#[$attrs:meta])*
587            $vis:vis struct $function_name:ident
588        )
589        [$(($gen_arg:tt $ignored:tt $(= $gen_default:tt)?))*]
590        [$($(@$has_phantom:tt)? $( ($($gen_phantom:tt)+) )+ )?]
591        [$(($($gen_params:tt)*))*]
592        where [$($($where:tt)+)?]
593    ) => {
594        $(#[$attrs])*
595        $vis struct $function_name<$($($gen_params)* $(= $gen_default)?,)*> $((
596            $($has_phantom)?
597            $crate::__::PhantomData<($($($gen_phantom)*)*)>
598        ))?
599        $(where $($where)+)?;
600
601        impl<$($($gen_params)*,)*> $function_name<$($gen_arg,)*> 
602        $(where $($where)+)?
603        {
604            #[doc = $crate::__::concat!(
605                "Constructs a `", $crate::__::stringify!($function_name), "`"
606            )]
607            $vis const NEW: Self = Self $($($has_phantom)? ($crate::__::PhantomData))?;
608        }
609    }
610}
611
612#[doc(hidden)]
613#[macro_export]
614macro_rules! __tyfn_typefn_impl {
615    (
616        (
617            $(#[$attrs:meta])*
618            $impl:ident[$(($($fn_gen_param:tt)*))*] $ty_arg:ty => $ret_ty:ty
619            where[ $($where_preds:tt)* ] 
620        )
621
622        $function_name:ident
623
624        [$(($capt_gen_args:tt $($rem_0:tt)*))*]
625        [
626            $(($capt_lt:lifetime $($capt_lt_rem:tt)*))*
627            $(($capt_tcp:ident $($capt_tcp_rem:tt)*))*
628        ]
629        where [$($capt_where:tt)*]
630        
631    ) => {
632        $crate::__impl_with_span! {
633            $ty_arg // span
634            ( $(#[$attrs])* #[allow(unused_parens)] )
635            (
636                <
637                    $($capt_lt $($capt_lt_rem)*,)*
638                    $($($fn_gen_param)*,)*
639                    $($capt_tcp $($capt_tcp_rem)*,)*
640                > $crate::TypeFn<$ty_arg>
641            )
642            // for
643            ( $function_name<$($capt_gen_args),*> )
644            (
645                where
646                    $($capt_where)*
647                    $($where_preds)*
648            )
649            (
650                type Output = $ret_ty;
651            )
652        }
653    };
654}