typewit/macros/
generics_parsing.rs

1// Generates a macro that takes a sequence of tokens with balanced `<` and `>` tokens
2// and collects it until one of the additional rules decides
3macro_rules! declare_generics_consuming_macro {(
4    $_:tt $gen_consuming_macro_:ident = $gen_consuming_macro:ident
5    $parsing_where:expr;
6
7
8    $($additional_rules:tt)*
9) => {
10
11    #[doc(hidden)]
12    #[macro_export]
13    macro_rules! $gen_consuming_macro_ {
14        (
15            $fixed:tt
16            [$_($counter:tt)*]
17            [$_($prev:tt)*]
18            [< $_($rem:tt)*]
19        ) => {
20            $crate::__::$gen_consuming_macro!{
21                $fixed
22                [1 $_($counter)*]
23                [$_($prev)* <]
24                [$_($rem)*]
25            }
26        };
27        (
28            $fixed:tt
29            [$_($counter:tt)*]
30            [$_($prev:tt)*]
31            [<< $_($rem:tt)*]
32        ) => {
33            $crate::__::$gen_consuming_macro!{
34                $fixed
35                [1 1 $_($counter)*]
36                [$_($prev)* <<]
37                [$_($rem)*]
38            }
39        };
40        (
41            $fixed:tt
42            [$counter0:tt $_($counter:tt)*]
43            [$_($prev:tt)*]
44            [> $_($rem:tt)*]
45        ) => {
46            $crate::__::$gen_consuming_macro!{
47                $fixed
48                [$_($counter)*]
49                [$_($prev)* >]
50                [$_($rem)*]
51            }
52        };
53        (
54            $fixed:tt
55            [$counter0:tt $_($counter:tt)*]
56            [$_($prev:tt)*]
57            [>> $_($rem:tt)*]
58        ) => {
59            $crate::__::$gen_consuming_macro!{
60                $fixed
61                [$_($counter)*]
62                [$_($prev)* >]
63                [> $_($rem)*]
64            }
65        };
66        (
67            $fixed:tt
68            [$counter0:tt $_($counter:tt)*]
69            [$_($prev:tt)*]
70            [>== $_($rem:tt)*]
71        ) => {
72            $crate::__::$gen_consuming_macro!{
73                $fixed
74                [$_($counter)*]
75                [$_($prev)* >]
76                [== $_($rem)*]
77            }
78        };
79        (
80            $fixed:tt
81            [$counter0:tt $_($counter:tt)*]
82            [$_($prev:tt)*]
83            [>= $_($rem:tt)*]
84        ) => {
85            $crate::__::$gen_consuming_macro!{
86                $fixed
87                [$_($counter)*]
88                [$_($prev)* >]
89                [= $_($rem)*]
90            }
91        };
92
93        $($additional_rules)*
94
95        (
96            $fixed:tt
97            $counter:tt
98            [$_($prev:tt)*]
99            [$token:tt $_($rem:tt)*]
100        ) => {
101            $crate::__::$gen_consuming_macro!{
102                $fixed
103                $counter
104                [$_($prev)* $token]
105                [$_($rem)*]
106            }
107        };
108        ( $fixed:tt $counter:tt [$_($prev:tt)*] [$_($token0:tt $_($other:tt)*)?]) => {
109            $crate::__::compile_error!{$crate::__::concat!(
110                "unexpected end of ", $parsing_where,": `",
111                stringify!($_($prev)* $_($token0)?),
112                "`",
113            )}
114        };
115        ( $_($other:tt)* ) => {
116            $crate::__::compile_error!{$crate::__::concat!(
117                "bug: unhandled syntax in `typewit` macro: ",
118                stringify!($_($other)*),
119            )}
120        };
121    }
122
123    pub use $gen_consuming_macro_ as $gen_consuming_macro;
124
125}}
126
127macro_rules! declare_parse_generics_macros {($_:tt [$($sep:tt)*] [$($err_token:tt)*]) => {
128    #[doc(hidden)]
129    #[macro_export]
130    macro_rules! __parse_in_generics_ {
131        $(
132            ($fixed:tt $gen_args:tt $gen:tt [$_(,)? $err_token $_($rem:tt)*]) => {
133                $crate::__::compile_error!{$crate::__::concat!(
134                    "unexpected `",
135                    $crate::__::stringify!($err_token),
136                    "` in generic parameter list",
137                )}
138            };
139        )*
140        (
141            ( $_($callback:ident)::* !($_($callback_args:tt)*) )
142            // [$( (($($attrs)*) $generic_arg $phantom_arg = $default_val) )*]
143            // Example of a single parameter list:
144            // (() 'a (fn() -> &'a (),)) 
145            // (() T (fn() -> $crate::__::PhantomData<T>,)) 
146            // ((#[foo]) U (fn() -> $crate::__::PhantomData<U>,) = u32)
147            // (() N ()) 
148            // (() M () = 10)
149            $gen_args:tt
150            [$_(((/* no attributes */) $_($generics:tt)*))*]
151            [$_(,)* $_(> $_($rem:tt)*)?]
152        ) => {
153            $_($callback)::* ! {
154                $_($callback_args)*
155                $gen_args
156                [$_(($_($generics)*))*]
157                []
158                $_($_($rem)*)?
159            }
160        };
161        // if there is at least one generic param with cfg attributes
162        (
163            ($_($fixed:tt)*)
164            $gen_args:tt
165            [$_((($_( $_(#[cfg($_($cfg:tt)+)])+ )?) $generics_first:tt $_($generics:tt)*))+]
166            [$_(,)* $_(> $_($rem:tt)*)?]
167        ) => {
168            $crate::__::__pg_cfg_expansion!{
169                ($_($fixed)* $_($_($rem)+)?)
170                [] $gen_args
171                [] [$_(($generics_first $_($generics)*))*]
172                []
173                [$_( ($_($generics_first all( $_( $_($cfg)+ ),* ))?) )+]
174            }
175        };
176        (
177            ($_($fixed:tt)*)
178            $gen_args:tt
179            [$_((($_(#[$_($attr:tt)*])*) $_($generics:tt)*))+]
180            [$_(,)* $_(> $_($rem:tt)*)?]
181        ) => {
182            $_(
183                $crate::__assert_valid_gen_attr!{ [] [$_(#[$_($attr)*])*] }
184            )*
185        };
186        $(
187            (
188                $fixed:tt
189                [$_($prev_gen_args:tt)*]
190                [$_($prev_gen:tt)*]
191                [
192                    $_(,)?
193                    $_(#[$_($attr:tt)*])*
194                    $lt:lifetime $_(:
195                        $_($lt_bound0:lifetime $_( + $lt_bound1:lifetime)*)?
196                    )?
197                    $_($sep $_($rem:tt)*)?
198                ]
199            ) => {
200                $crate::__::__parse_in_generics!{
201                    $fixed 
202                    [$_($prev_gen_args)* ($lt (fn() -> &$lt (),) )]
203                    [
204                        $_($prev_gen)* 
205                        (($_(#[$_($attr)*])*) $lt $_(: $_($lt_bound0 $_( + $lt_bound1 )* )?)?)
206                    ]
207                    [$_($sep  $_($rem)*)?]
208                }
209            };
210            (
211                $fixed:tt
212                [$_($prev_gen_args:tt)*]
213                [$_($prev_gen:tt)*]
214                [
215                    $_(,)? 
216                    $_(#[$_($attr:tt)*])*
217                    const $const:ident: $const_ty:ty $_(= $default:tt)?
218                    $_($sep $_($rem:tt)*)?
219                ]
220            ) => {
221                $crate::__::__parse_in_generics!{
222                    $fixed 
223                    [$_($prev_gen_args)* ($const () $_(= $default)?)]
224                    [$_($prev_gen)* (($_(#[$_($attr)*])*) const $const: $const_ty)]
225                    [$_($sep $_($rem)*)?]
226                }
227            };
228        )*
229        (
230            $fixed:tt
231            $prev_gen_args:tt
232            $prev_gen:tt
233            [
234                $_(,)? $_(#[$_($attr:tt)*])* $ty:ident: $_($rem:tt)*
235            ]
236        ) => {
237            $crate::__::__parse_ty_bounds!{
238                (
239                    $fixed 
240                    $prev_gen_args
241                    $prev_gen
242                    ($_(#[$_($attr)*])*)
243                    $ty
244                )
245                [] // counter for depth between < > pairs
246                []
247                [$_($rem)*]
248            }
249        };
250        (
251            $fixed:tt
252            $prev_gen_args:tt
253            $prev_gen:tt
254            [
255                $_(,)? $_(#[$_($attr:tt)*])* $ty:ident $_($rem:tt)*
256            ]
257        ) => {
258            $crate::__::__pg_parsed_ty_bounds!{
259                $fixed 
260                $prev_gen_args
261                $prev_gen
262                ($_(#[$_($attr)*])*)
263                $ty
264                []
265                $_($rem)*
266            }
267        };
268        ($fixed:tt $gen_args:tt $gen:tt []) => {
269            $crate::__::compile_error!{"unexpected end of generic parameter list"}
270        };
271        ($fixed:tt $gen_args:tt $gen:tt [$token0:tt $_($token1:tt $_($other:tt)*)?]) => {
272            $crate::__::compile_error!{$crate::__::concat!(
273                "unexpected token(s) in generic parameter list: `",
274                stringify!($token0 $_($token1)?)
275                "`"
276            )}
277        };
278    }
279
280    #[doc(hidden)]
281    #[macro_export]
282    macro_rules! __pg_parsed_ty_bounds_ {
283        $(
284            (
285                $fixed:tt $gen_args:tt $gen:tt $attrs:tt $ty:tt $bound:tt
286                [$err_token $_($rem:tt)*]
287            ) => {
288                $crate::__::compile_error!{$crate::__::concat!(
289                    "unexpected `",
290                    $crate::__::stringify!($err_token),
291                    "` in type parameter declaration",
292                )}
293            };
294        )*
295
296        $(
297            (
298                $fixed:tt
299                [$_($prev_gen_args:tt)*]
300                [$_($prev_gen:tt)*]
301                $attrs:tt
302                $ty:ident 
303                [$_($_($bound:tt)+)?]
304                $_(= $default:ty)? $sep $_($rem:tt)*
305            ) => {
306                $crate::__::__parse_in_generics!{
307                    $fixed 
308                    [
309                        $_($prev_gen_args)* 
310                        ($ty (fn() -> $crate::__::PhantomData<$ty>,) $_(= $default)?)
311                    ]
312                    [$_($prev_gen)* ($attrs $ty $_(: $_($bound)+)?)]
313                    [$sep $_($rem)*]
314                }
315            };
316        )*
317    }
318
319    declare_generics_consuming_macro! {
320        $ __parse_ty_bounds_ = __parse_ty_bounds
321        "bound";
322
323        ( ($_($fixed:tt)*) [] $prev:tt [$_(= $_($rem:tt)*)?] ) => {
324            $crate::__::__pg_parsed_ty_bounds!{ $_($fixed)* $prev $_(= $_($rem)*)? }
325        };
326
327        $(
328            ( ($_($fixed:tt)*) [] $prev:tt [$sep $_($rem:tt)*] ) => {
329                $crate::__::__pg_parsed_ty_bounds!{ $_($fixed)* $prev $sep $_($rem)* }
330            };
331        )*
332
333        $(
334            ($fixed:tt $count:tt [$_($prev:tt)*] [$err_token $_($rem:tt)*]) => {
335                $crate::__::compile_error!{$crate::__::concat!(
336                    "unexpected end of bound: `",
337                    stringify!($_($prev)* $err_token),
338                    "`",
339                )}
340            };
341        )*
342    }
343}} 
344
345declare_parse_generics_macros!{$ [, >] [; where impl]}
346
347
348pub use {
349    __parse_in_generics_ as __parse_in_generics,
350    __pg_parsed_ty_bounds_ as __pg_parsed_ty_bounds,
351};
352
353macro_rules! declare_pg_cfg_expansion {
354($_:tt 
355    $(
356        [($deleted_lt_ty_marker_:ident) ($($gp_rule:tt)*) => {$($erase_marker_token:tt)*}]
357    )*
358) => {
359
360    #[doc(hidden)]
361    #[macro_export]
362    macro_rules! __pg_cfg_expansion_ {
363
364        (
365            $fixed:tt
366            [$_($prev_gen_args:tt)*] [$gen_arg:tt $_($rem_gen_args:tt)*]
367            [$_($prev_generics:tt)*] [$generic:tt $_($rem_generics:tt)*]
368            $deleted_lt_ty_marker:tt
369            [() $_($rem_cfg:tt)*]
370        ) => {
371            $crate::__::__pg_cfg_expansion!{
372                $fixed
373                [$_($prev_gen_args)* $gen_arg] [ $_($rem_gen_args)*]
374                [$_($prev_generics)* $generic] [ $_($rem_generics)*]
375                $deleted_lt_ty_marker
376                [$_($rem_cfg)*]
377            }
378        };
379        $(
380            (
381                $fixed:tt
382                [$_($prev_gen_args:tt)*] [$gen_arg:tt $_($rem_gen_args:tt)*]
383                [$_($prev_generics:tt)*] [$generic:tt $_($rem_generics:tt)*]
384                $_$deleted_lt_ty_marker_:tt
385                [($($gp_rule)* $_($cfg:tt)+) $_($rem_cfg:tt)*]
386            ) => {
387                #[cfg($_($cfg)+)]
388                $crate::__::__pg_cfg_expansion!{
389                    $fixed
390                    [$_($prev_gen_args)* $gen_arg] [ $_($rem_gen_args)*]
391                    [$_($prev_generics)* $generic] [ $_($rem_generics)*]
392                    $_$deleted_lt_ty_marker_
393                    [$_($rem_cfg)*]
394                }
395
396                #[cfg(not($_($cfg)+))]
397                $crate::__::__pg_cfg_expansion!{
398                    $fixed
399                    [$_($prev_gen_args)*] [ $_($rem_gen_args)*]
400                    [$_($prev_generics)*] [ $_($rem_generics)*]
401                    $($erase_marker_token)*
402                    [$_($rem_cfg)*]
403                }
404            };
405        )*
406
407        (
408            ( $_($callback:ident)::* !($_($callback_args:tt)*) $_($rem:tt)*)
409            $gen_args:tt []
410            $generics:tt []
411            $deleted_lt_ty_marker:tt
412            [] // no cfgs left
413        ) => {
414            $_($callback)::* ! {
415                $_($callback_args)*
416                $gen_args
417                $generics
418                $deleted_lt_ty_marker
419                $_($rem)*
420            }
421        };
422    }
423
424}}
425
426declare_pg_cfg_expansion!{
427    $
428    [(deleted_lt_ty_marker) (const) => {$deleted_lt_ty_marker}]
429    [(deleted_lt_ty_marker) ($__gp:tt) => {[()]}]
430}
431
432pub use __pg_cfg_expansion_ as __pg_cfg_expansion;
433
434
435
436#[doc(hidden)]
437#[macro_export]
438macro_rules! __parse_generics {
439    // angle bracket generics
440    (
441        $fixed:tt
442        [< $($generics:tt)*]
443    ) => {
444        $crate::__::__parse_in_generics!{
445            $fixed
446            []
447            []
448            [$($generics)*]
449        }
450    };
451    // square bracket generic params
452    // note: this is accepted so that simple_type_witness 
453    // can still parse square bracket generics.
454    (
455        $fixed:tt
456        [[$($generics:tt)*] $($rem:tt)*]
457    ) => {
458        $crate::__::__parse_in_generics!{
459            $fixed
460            []
461            []
462            [$($generics)*> $($rem)*]
463        }
464    };
465    // no generics case
466    (
467        (
468            $($callback:ident)::* !($($callback_args:tt)*)
469        )
470        [$($rem:tt)*]
471    ) => {
472        $($callback)::* ! {
473            $($callback_args)*
474            []
475            []
476            []
477            $($rem)*
478        }
479    };
480}
481
482#[doc(hidden)]
483#[macro_export]
484macro_rules! __trailing_comma_for_where_clause {
485    // fallback case
486    (($($macro:ident)::* !($($args:tt)*)) [$($prev:tt)*] [] ) => {
487        $($macro)::* !{$($args)* [$($prev)*] }
488    };
489    (($($macro:ident)::* !($($args:tt)*)) [$($($prev:tt)+)?] [$(,)? ; $($rem:tt)*] ) => {
490        $($macro)::* !{$($args)* [$($($prev)+,)?] $($rem)* }
491    };
492    ($fixed:tt [$($prev:tt)*] [$t0:tt $($rem:tt)*]) => {
493        $crate::__trailing_comma_for_where_clause!{
494            $fixed [$($prev)* $t0] [$($rem)*]
495        }
496    };
497}
498
499
500// parses a where clause for an item where the where clause ends at any of:
501// - `=`
502// - `{...}`
503// 
504// The parsed tokens start with `where`, so that these can be parsed: 
505// - there being no where clause
506// - having a normal where clause
507// - having a where clause delimited with brackets (e.g: `where[T: u32]`)
508#[doc(hidden)]
509#[macro_export]
510macro_rules! __parse_where_clause_for_item {
511    ($fixed:tt where [$($in_brackets:tt)*]: $($rem:tt)*) => {
512        $crate::__::__parse_where_clause_for_item_inner!{
513            $fixed [] [] [[$($in_brackets)*]: $($rem)*]
514        }
515    };
516    // parses the `where [$where_predicates]` syntax that 
517    // the simple_type_withness macro started with.
518    ($fixed:tt where [$($in_brackets:tt)*] $($rem:tt)*) => {
519        $crate::__trailing_comma_for_where_clause!{
520            $fixed [] [$($in_brackets)*; $($rem)*]
521        }
522    };
523    ($fixed:tt where $($rem:tt)*) => {
524        $crate::__::__parse_where_clause_for_item_inner!{
525            $fixed [] [] [$($rem)*]
526        }
527    };
528    // no where clause
529    (($($callback:ident)::* !($($callback_args:tt)*) ) $($rem:tt)*) => {
530        $($callback)::* !{$($callback_args)* [] $($rem)*}
531    };
532}
533
534
535
536declare_generics_consuming_macro! {
537    $ __parse_where_clause_for_item_inner_ = __parse_where_clause_for_item_inner
538    "where clause";
539
540    // forward compatibility with `const { ... }` bounds,
541    // dunno how likely const bounds are to be, but why not.
542    ( $fixed:tt [] [$($prev:tt)*] [const {$($braced:tt)*} $($rem:tt)*] ) => {
543        $crate::__::__parse_where_clause_for_item!{
544            $fixed
545            []
546            [$($prev)* const {$($braced)*}]
547            [$($rem)*]
548        }
549    };
550    ( 
551        ($($callback:ident)::* !($($callback_args:tt)*) )
552        []
553        [$($($prev:tt)+)?]
554        [$(,)? = $($rem:tt)*] 
555    ) => {
556        $($callback)::* !{$($callback_args)* [$($($prev)+,)?] = $($rem)*}
557    };
558    (
559        ($($callback:ident)::* !($($callback_args:tt)*) )
560        []
561        [$($($prev:tt)+)?]
562        [$(,)? {$($braced:tt)*} $($rem:tt)*]
563    ) => {
564        $($callback)::* !{$($callback_args)* [$($($prev)+,)?] {$($braced)*} $($rem)*}
565    };
566    ($fixed:tt [] $prev:tt []) => {
567        $crate::__::compile_error!{"unexpected end of where clause, expected rest of item"}
568    };
569}
570
571
572declare_generics_consuming_macro! {
573    $ __parse_generic_args_with_defaults_ = __parse_generic_args_with_defaults
574    "generic arguments";
575
576    (
577        ($fixed:tt [$($prev_args:tt)*] [$($curr_gen_param:tt $($gen_params_rem:tt)*)?])
578        []
579        [$($prev_tokens:tt)*]
580        [, $($rem:tt)*]
581    ) => {
582        $crate::__::__parse_generic_args_with_defaults! {
583            ($fixed [$($prev_args)* $($prev_tokens)*,] [$($($gen_params_rem)*)?])
584            []
585            []
586            [$($rem)*]
587        }
588    };
589
590    (
591        ($fixed:tt [$($prev_args:tt)*] [$($curr_gen_param:tt $($gen_params_rem:tt)*)?])
592        []
593        [$($prev_tokens:tt)+]
594        [> $($rem:tt)*]
595    ) => {
596        $crate::__parse_generic_args_with_defaults__finish !{
597            ($fixed [$($prev_args)* $($prev_tokens)*,] [$($($gen_params_rem)*)?])
598            $($rem)*
599        }
600    };
601
602    ($fixed:tt [] [] [> $($rem:tt)*]) => {
603        $crate::__parse_generic_args_with_defaults__finish !{
604            $fixed $($rem)*
605        }
606    };
607
608    ($fixed:tt [] $prev:tt []) => {
609        $crate::__::compile_error!{"unexpected end of generic arguments"}
610    };
611}
612
613
614
615
616#[doc(hidden)]
617#[macro_export]
618macro_rules! __parse_generic_args_with_defaults__finish {
619    (
620        (
621            (
622                ($($callback:ident)::* !($($callback_args:tt)*) )
623                $context:expr
624            )
625
626            [$($gen_args:tt)*]
627
628            [
629                $((
630                    // gen_eff_def is either:
631                    // - the default (if the generic parameter has one)
632                    // - the name of the generic parameter (if it has no default)
633                    (($($gen_eff_def:tt)*) $($__0:tt)*) 
634
635                    (
636                        // defined if the generic parameter does not have a default 
637                        $([$gen_param:tt])? 
638                        // defined if the generic parameter has a default
639                        $(($($__1:tt)*) [$__gen_param:tt])?
640                    )
641                ))*
642            ]
643        )
644        $($rem:tt)*
645    ) => {
646        $crate::__parse_generic_args_with_defaults__assert_only_defaults! {
647            $context,
648            [$($($gen_param)?)*]
649        }
650
651        $($callback)::* !{
652            $($callback_args)* 
653            [$($gen_args)* $($($gen_eff_def)* ,)*] 
654            $($rem)*
655        }
656    }
657}
658
659#[doc(hidden)]
660#[macro_export]
661macro_rules! __parse_generic_args_with_defaults__assert_only_defaults {
662    (
663        $context:expr,
664        [$($($gen_param:tt)+)?]
665    ) => {
666        $(
667            $crate::__::compile_error!{$crate::__::concat!{
668                "expected these generic argument(s) for ", $context, " to be passed: "
669                $( , stringify!($gen_param), )", "+
670            }}
671        )?
672    };
673}
674
675
676
677#[doc(hidden)]
678#[macro_export]
679macro_rules! __assert_valid_gen_attr {
680    ( $prev:tt [#[cfg($($tt:tt)*)] $($rem:tt)*]) => {
681        $crate::__assert_valid_gen_attr!{ $prev [$($rem)*] }
682    };
683    ( [$($prev:tt)*] [#[$($tt:tt)*] $($rem:tt)*]) => {
684        $crate::__assert_valid_gen_attr!{
685            [$($prev)* #[$($tt)*]]
686            [$($rem)*]
687        }
688    };
689    ( [$(#[$attr:meta])*] []) => {
690        $crate::__::compile_error!{$crate::__::concat!{
691            "unsupported attribute(s) on generic parameter(s): "
692            $( ,"`#[", stringify!($attr), "]`", )", "*
693            "\nonly the `#[cfg(...)]` attribute is supported"
694        }}
695    };
696}