Skip to main content

ctor/macros/
features.rs

1//! A set of macros to declare features for another macro.
2
3/// A macro that generates the appropriate feature extraction macros.
4#[macro_export]
5#[doc(hidden)]
6macro_rules! __declare_features {
7    ( $($input:tt)* ) => {
8        $crate::__perform!(
9            ($($input)*),
10            $crate::__chain[
11                $crate::__parse_feature_input,
12                $crate::__parallel[
13                    // (params)
14                    $crate::__chain[
15                        $crate::__pick[0],
16                    ],
17                    // (features)
18                    $crate::__chain[
19                        $crate::__pick[1],
20                        $crate::__unbrace,
21                        $crate::__for_each[$crate::__fix_docs],
22                        $crate::__for_each[$crate::__process_defaults],
23                        $crate::__for_each[$crate::__evaluate_defaults],
24                        $crate::__brace[()],
25                    ],
26                    // (features)
27                    $crate::__chain[
28                        $crate::__pick[1],
29                        $crate::__feature_square,
30                    ],
31                ],
32                // (params) (features) (feature_square)
33                $crate::__pick[0 1 2 1],
34                $crate::__make_macros[$],
35            ]
36        );
37    };
38}
39
40#[macro_export]
41#[doc(hidden)]
42macro_rules! __generate_docs {
43    ( $macro_parse:path ) => {
44        $crate::__perform!(
45            (),
46            $crate::__chain[
47                $macro_parse[$macro_parse => @raw],
48                $crate::__make_docs,
49            ]
50        );
51    };
52}
53
54/// Parses a single, generic item decorated with an attribute macro into the
55/// main attribute features, other meta items, and the original item.
56#[macro_export]
57#[doc(hidden)]
58macro_rules! __parse_item {
59    ( @entry next=$next:path[$next_args:tt], input=($($item:tt)*), args=[$macro_name:path]) => {
60        $crate::__chain!(@entry next=$next[$next_args], input=($($item)*), args=[
61            $crate::__parallel[
62                // Split meta from item and process them separately
63                $crate::__chain[
64                    $crate::__split_meta,
65                    // (meta) (item)
66                    $crate::__separate[
67                        // (meta)
68                        $crate::__parallel[
69                            // Extract meta items
70                            $crate::__chain[
71                                // (meta)
72                                $crate::__call[$macro_name[$macro_name => @self]],
73                                // (self)(other)
74                                $crate::__separate[
75                                    // (self)
76                                    $crate::__extract_meta[$macro_name],
77                                    // (other)
78                                    $crate::__brace[()],
79                                ],
80                            ],
81                        ],
82                        // (item)
83                        $crate::__identity,
84                    ],
85                ],
86            ],
87            // Assembles the final parsed item
88            // input: features #[other_meta] item
89            $crate::__finish_item,
90        ]);
91    };
92}
93
94/// Finishes the item parsing by collecting the features, meta, and item.
95#[macro_export]
96#[doc(hidden)]
97macro_rules! __finish_item {
98    ( @entry next=$next:path[$next_args:tt], input=(
99        $($feature:ident = $feature_value:tt,)*
100        ($(#[$other_meta:meta])*)
101        $($item:tt)*
102    ) ) => {
103        $next ! ( $next_args, (
104            features = ($($feature = $feature_value,)*),
105            meta = ($(#[$other_meta])*),
106            item = ($($item)*)
107        ) );
108    };
109}
110
111/// Splits the item input into meta and item.
112#[macro_export]
113#[doc(hidden)]
114macro_rules! __split_meta {
115    ( @entry next=$next:path[$next_args:tt], input=($($item:tt)*) ) => {
116        $crate::__split_meta!(@loop meta=(), rest=($($item)*), item_check=($($item)*), next=[$next[$next_args]]);
117    };
118
119    ( @loop meta=($($metas:tt)*), rest=(#$meta:tt $($item:tt)*), item_check=($item_check:item), next=$next:tt ) => {
120        $crate::__split_meta!(@loop meta=($($metas)* #$meta), rest=($($item)*), item_check=($item_check), next=$next);
121    };
122
123    ( @loop meta=($($meta:tt)*), rest=($($item:tt)*), item_check=($item_check:item), next=[$next:path[$next_args:tt]]) => {
124        $next ! ( $next_args, (($($meta)*) ($($item)*)) );
125    };
126
127    ( @loop meta=($($metas:tt)*), rest=$rest:tt, item_check=not_an_item:tt, next=$next:tt ) => {
128        const _: () = { compile_error!(concat!("Expected an item, got: ", stringify!($($input)*))); };
129    };
130
131    ( $($input:tt)* ) => {
132        const _: () = { compile_error!(concat!("Unexpected input: ", stringify!($($input)*))); };
133    };
134}
135
136/// Extracts the unsafe flag from an item extracted via `__parse_item`.
137#[macro_export]
138#[doc(hidden)]
139macro_rules! __extract_unsafe {
140    ( @entry next=$next:path[$next_args:tt], input=(
141        features = $features:tt,
142        meta = $meta:tt,
143        item = ($vis:vis unsafe $($rest:tt)*)
144    ) ) => {
145        $next ! ( $next_args, (
146            features = $features,
147            meta = $meta,
148            unsafe = (unsafe),
149            item = ($vis unsafe $($rest)*)
150        ));
151    };
152
153    ( @entry next=$next:path[$next_args:tt], input=(
154        features = $features:tt,
155        meta = $meta:tt,
156        item = ($vis:vis static $ident:ident : $ty:ty = unsafe $($rest:tt)*)
157    ) ) => {
158        $next ! ( $next_args, (
159            features = $features,
160            meta = $meta,
161            unsafe = (unsafe),
162            item = ($vis static $ident : $ty = unsafe $($rest)*)
163        ));
164    };
165
166    ( @entry next=$next:path[$next_args:tt], input=(
167        features = $features:tt,
168        meta = $meta:tt,
169        item = $item:tt
170    ) ) => {
171        $next ! ( $next_args, (
172            features = $features,
173            meta = $meta,
174            unsafe = (),
175            item = $item
176        ));
177    };
178}
179
180/// Parses a "pretty" feature specification into something easier to work with.
181#[macro_export]
182#[doc(hidden)]
183macro_rules! __parse_feature_input {
184    ( @entry next=$next:path[$next_args:tt], input=(
185        $macro_name:ident: $macro_parse:ident;
186
187        $(
188            $( #[doc = $doc:literal] )*
189            $feature:ident {
190                $(
191                    $( #[doc = r" crate"] $( #[doc = $doc_crate:literal] )* )?
192                    feature: $feature_name:literal;
193                )?
194                $(
195                    $( #[doc = r" attr"] $( #[doc = $doc_attr:literal] )* )?
196                    attr: $attr:tt;
197                    $(
198                        example: $example:literal;
199                    )?
200                    $(
201                        validate: $validate:tt;
202                    )?
203                )?
204                $( default {
205                    $( ($default_expr:meta) => $default_value:tt, )*
206                    _ => $default_fallback:tt $(,)?
207                } )?
208            };
209        )*
210    )) => {
211        $next ! ( $next_args, (
212            (
213                $macro_name
214                $macro_parse
215            )
216            (
217                $(
218                    (
219                        feature = $feature;
220                        docs = [$( $doc )*];
221                        $(
222                            name = $feature_name;
223                            crate_docs = [$( $( $doc_crate )* )?];
224                        )?
225                        $(
226                            attr = $attr;
227                            attr_docs = [$( $( $doc_attr )* )?];
228                        )?
229                        default = [
230                            $(
231                                ((feature = $feature_name) => $feature)
232                            )?
233                            $(
234                                $( (($default_expr) => $default_value) )*
235                                (_ => $default_fallback)
236                            )?
237                            (_ => ())
238                        ]
239                    )
240                )*
241            )
242        ) );
243    };
244}
245
246/// Concatenate the global docs with the crate/attr docs.
247#[macro_export]
248#[doc(hidden)]
249macro_rules! __fix_docs {
250    ( @entry next=$next:path[$next_args:tt], input=(
251        (
252            feature = $feature:ident;
253            docs = [$($docs:tt)*];
254            name = $crate_name:literal;
255            crate_docs = [$($crate_docs:tt)*];
256            attr = $attr:tt;
257            attr_docs = [$($attr_docs:tt)*];
258            default = $default:tt
259        )
260    ) ) => {
261        $next ! ( $next_args, ((
262            feature = $feature;
263            name = $crate_name;
264            crate_docs = [$($docs)* $($crate_docs)*];
265            attr = $attr;
266            attr_docs = [$($docs)* $($attr_docs)*];
267            default = $default
268        )) );
269    };
270
271    ( @entry next=$next:path[$next_args:tt], input=(
272        (
273            feature = $feature:ident;
274            docs = [$($docs:tt)*];
275            attr = $attr:tt;
276            attr_docs = [$($attr_docs:tt)*];
277            default = $default:tt
278        )
279    ) ) => {
280        $next ! ( $next_args, ((
281            feature = $feature;
282            attr = $attr;
283            attr_docs = [$($docs)* $($attr_docs)*];
284            default = $default
285        )) );
286    };
287
288    ( @entry next=$next:path[$next_args:tt], input=(
289        (
290            feature = $feature:ident;
291            docs = [$($docs:tt)*];
292            name = $crate_name:literal;
293            crate_docs = [$($crate_docs:tt)*];
294            default = $default:tt
295        )
296    ) ) => {
297        $next ! ( $next_args, ((
298            feature = $feature;
299            name = $crate_name;
300            crate_docs = [$($docs)* $($crate_docs)*];
301            default = $default
302        )) );
303    };
304
305    ( @entry next=$next:path[$next_args:tt], input=(
306        (
307            feature = $feature:ident;
308            docs = [$($docs:tt)*];
309            default = $default:tt
310        )
311    ) ) => {
312        $next ! ( $next_args, ((
313            feature = $feature;
314            default = $default
315        )) );
316    }
317}
318
319/// Process the defaults into full cfg chains.
320#[macro_export]
321#[doc(hidden)]
322macro_rules! __process_defaults {
323    ( @entry next=$next:path[$next_args:tt], input=(
324        (
325            feature = $feature:ident;
326            $(
327                name = $name_both:literal;
328                crate_docs = $crate_docs:tt;
329            )?
330            $(
331                attr = $attr:tt;
332                attr_docs = $attr_docs:tt;
333            )?
334            default = [$($default:tt)*]
335        )
336    ) ) => {
337        $crate::__process_defaults!( @process accum=(), negative=(), defaults=
338            [
339                $($default)*
340            ],
341            next=[$next[$next_args]],
342            rest=(
343                feature = $feature;
344                $(
345                    feature_crate = $feature;
346                    name = $name_both;
347                    crate_docs = $crate_docs;
348                )?
349                $(
350                    feature_attr = $feature;
351                    attr = $attr;
352                    attr_docs = $attr_docs;
353                )?
354                original_defaults = {$($default)*};
355            )
356        );
357    };
358
359    // Stop when we hit the final default.
360    (@process accum=($($accum:tt)*), negative=$negative:tt, defaults=[(_ => $default_value:tt) $($ignored:tt)*], next=[$next:path[$next_args:tt]], rest=($($rest:tt)*)) => {
361        $next ! ( $next_args, (($($rest)* default = [
362            $($accum)*
363            ((not(any $negative)) => $default_value)
364        ])) );
365    };
366
367    // Accumulate the expression + negative and add to the negative.
368    (@process accum=($($accum:tt)*), negative=($($negative:tt)*), defaults=[(($default_expr:meta) => $default_value:tt) $($default_rest:tt)*], $($rest:tt)*) => {
369        $crate::__process_defaults!(@process
370            accum=($($accum)* ((all($default_expr, not(any ($($negative)*)))) => $default_value) ),
371            negative=($($negative)* $default_expr ,),
372            defaults=[$($default_rest)*], $($rest)*);
373    };
374}
375
376#[macro_export]
377#[doc(hidden)]
378macro_rules! __evaluate_defaults {
379    ( @entry next=$next:path[$next_args:tt], input=((
380        feature = $feature:ident;
381        $(
382            feature_crate = $feature_crate:ident;
383            name = $name:literal;
384            crate_docs = $crate_docs:tt;
385        )?
386        $(
387            feature_attr = $feature_attr:ident;
388            attr = $attr:tt;
389            attr_docs = $attr_docs:tt;
390        )?
391        original_defaults = $original_defaults:tt;
392        default = [
393            $( ($default_expr:tt => $default_value:tt) )*
394        ]
395    ))) => {
396        $crate::__evaluate_defaults!(@process next=[$next[$next_args]], input=($( ($default_expr => $default_value) )*), rest=(
397            feature = $feature;
398            $(
399                feature_crate = $feature_crate;
400                name = $name;
401                crate_docs = $crate_docs;
402            )?
403            $(
404                feature_attr = $feature_attr;
405                attr = $attr;
406                attr_docs = $attr_docs;
407            )?
408            original_defaults = $original_defaults;
409        ));
410    };
411
412    (@process next=$next:tt, input=($( ($default_expr:tt => $default_value:tt) )*), rest=$rest:tt) => {
413        $(
414            #[cfg $default_expr]
415            $crate::__evaluate_defaults!(@final $next, $rest, default = $default_value);
416        )*
417    };
418
419    (@final [$next:path[$next_args:tt]], ($($rest:tt)*), default = (compile_error! $args:tt)) => {
420        compile_error! $args;
421    };
422
423    (@final [$next:path[$next_args:tt]], ($($rest:tt)*), default = $default_value:tt) => {
424        $next ! ( $next_args, (($($rest)* default = $default_value;)) );
425    };
426}
427
428#[macro_export]
429#[doc(hidden)]
430macro_rules! __feature_square {
431    ( @entry next=$next:path[$next_args:tt], input=(
432        ($((
433            feature = $all:ident;
434            $($ignored:tt)*
435        ))*)
436    ) ) => {
437        $crate::__feature_square!( @loop queue=[$($all)*], mult=[$($all)*], next=$next[$next_args] );
438    };
439    ( @loop queue=[$($all:ident)*], mult=$mult:tt, next=$next:path[$next_args:tt] ) => {
440        $next ! ( $next_args, (
441            ($( ($all $mult) )*)
442        ) );
443    };
444    ( $($input:tt)* ) => {
445        const _: () = { compile_error!(concat!("Unexpected input: ", stringify!($($input)*))); };
446    };
447}
448
449#[macro_export]
450#[doc(hidden)]
451macro_rules! __extract_features {
452    ( @entry macro=$macro_parse:path, next=$next:tt, features=$features:tt, all_features=$all_features:tt) => {
453        $crate::__extract_features!(@loop accum=(), macro=$macro_parse, next=$next, features=$features, all_features=$all_features);
454    };
455    ( @loop accum=$accum:tt, macro=$macro_parse:path, next=($next:path[$next_args:tt]), features=(), all_features=$all_features:tt) => {
456        $next ! ( $next_args, $accum );
457    };
458    ( @loop accum=$accum:tt, macro=$macro_parse:path, next=$next:tt, features=($feature:ident $($feature_rest:tt)*), all_features=$all_features:tt) => {
459        $macro_parse!(@extract next=__extract_features[(@cont accum=$accum, macro=$macro_parse, next=$next, features=($($feature_rest)*), all_features=$all_features)] $feature $all_features);
460    };
461    ( (@cont accum=($($accum:tt)*), $($args:tt)*), ($name:ident = $output:tt $($extra:tt)+) ) => {
462        $crate::__extract_features!((@cont accum=($($accum)*), $($args)*), ($name = $($extra)+));
463    };
464    ( (@cont accum=($($accum:tt)*), $($args:tt)*), ($name:ident = $output:tt) ) => {
465        $crate::__extract_features!(@loop accum=($($accum)* $name = $output ,), $($args)*);
466    };
467    ( (@cont accum=($($accum:tt)*), $($args:tt)*), ($name:ident = ) ) => {
468        $crate::__extract_features!(@loop accum=($($accum)* $name = () ,), $($args)*);
469    };
470}
471
472#[macro_export]
473#[doc(hidden)]
474macro_rules! __extract_meta {
475    ( @entry next=$next:path[$next_args:tt], input=(
476        (
477            $(
478                $name:ident $( ($($args:tt)*) )? $( = $value:tt $( $value_ident:ident )? $( :: $value_path:ident )* )?
479            ),*
480        )
481    ), args=[$macro_path:path]) => {
482        $macro_path!(@meta macro=$macro_path, next=$crate::__extract_meta[[@finish next=$next[$next_args]]] $(
483            $name $( ($( $args )*) )? $( = $value $( $value_ident )? $( :: $value_path )* )? , , ;
484        )*);
485    };
486    ( @entry next=$next:path[$next_args:tt], input=(
487        (
488            $($input:tt)*
489        )
490    ), args=[$macro_path:path]) => {
491        const _: () = {
492            compile_error!(concat!("Unexpected type of meta argument: ",
493            stringify!($($input)*),
494            "\n\n... expected 'attr', 'attr = value', 'attr(arg)', 'attr(arg) = value'"));
495        };
496    };
497    ( [@finish next=$next:path[$next_args:tt]],
498        ($(
499            ( $name:ident = $value:tt $( , $def_value:tt )? )
500        )*)
501    ) => {
502        $next ! ( $next_args, (
503            $(
504                $name = $value,
505            )*
506        ) );
507    };
508    ( [@finish next=$next:path[$next_args:tt]],
509        (
510            $(( $name:ident = $value:tt $( , $def_value:tt $( $comma:tt $($rest:tt)* )? )? ))*
511        )
512    ) => {
513        // TODO: This should show the underlying attribute rather than the internal name.
514        const _: () = { compile_error!(concat!("Duplicate meta attribute: '", stringify!(
515            $( $($($name = ...$comma)?)?  )*
516        ))) };
517    };
518    ( @error rest=(
519        $name:ident $( ($( $args:tt)*) )? $( = $value:tt )? , , ; $($rest:tt)*
520    ) attrs=($($attr:tt)*)) => {
521        const _: () = { compile_error!(concat!("Unexpected meta attribute: '", stringify!(
522            $name $( ($( $args )*) )? $( = $value )?
523        ),
524        "'\n...expected one of:\n",
525        stringify!($($attr)*))); };
526    };
527    ( $($input:tt)* ) => {
528        const _: () = { compile_error!(concat!("Unexpected input in __extract_meta: ", stringify!($($input)*))); };
529    };
530}
531
532#[macro_export]
533#[doc(hidden)]
534macro_rules! __extract_self {
535    ( @entry macro=$macro_parse:path, next=$next:tt, input=$input:tt) => {
536        $crate::__extract_self!(@loop self=(), other=(), input=$input, macro=$macro_parse, next=$next);
537    };
538    ( @loop self=$self:tt, other=$other:tt, input=(), macro=$macro_parse:path, next=($next:path[$next_args:tt])) => {
539        $next ! ( $next_args, ( $self $other ) );
540    };
541    ( @loop self=$self:tt, other=$other:tt, input=(# $meta:tt $($rest:tt)*), macro=$macro_parse:path, next=$next:tt) => {
542        $macro_parse!(@self next=$crate::__extract_self[(@cont self=$self, other=$other, input=($($rest)*), macro=$macro_parse, next=$next)], input=(# $meta));
543    };
544    ( (@cont self=$self:tt, other=$other:tt, $($args:tt)*), (self = ($($output:tt)*)) ) => {
545        $crate::__extract_self!(@loop self=($($output)*), other=$other, $($args)*);
546    };
547    ( (@cont self=$self:tt, other=($($other:tt)*), $($args:tt)*), (other = ($($output:tt)*)) ) => {
548        $crate::__extract_self!(@loop self=$self, other=($($other)* $($output)*), $($args)*);
549    };
550}
551
552/// Generates the various utility macros used to parse the actual macro under
553/// the hood.
554#[macro_export]
555#[doc(hidden)]
556macro_rules! __make_macros {
557    ( @entry next=$next:path[$next_args:tt], input=(
558        (
559            $macro_name:ident
560            $macro_parse:ident
561        )
562        (
563            $(
564                (
565                    feature = $feature:ident;
566                    $(
567                        feature_crate = $feature_crate:ident;
568                        name = $name:literal;
569                        crate_docs = $crate_docs:tt;
570                    )?
571                    $(
572                        feature_attr = $feature_attr:ident;
573                        attr = [($($attr:tt)*) => ($($attr_output:tt)*)];
574                        attr_docs = $attr_docs:tt;
575                    )?
576                    original_defaults = $original_defaults:tt;
577                    default = $default_value:tt;
578                )
579            )*
580        )
581        (
582            $(
583                ($feature_sq_1:ident [$($feature_sq_2:ident)*])
584            )*
585        )
586        $raw_features:tt
587    ), args=[$dollar:tt]) => {
588        #[doc(hidden)]
589        #[macro_export]
590        macro_rules! $macro_parse {
591            // @extract takes the full or partial feature tuple and extracts one
592            // feature at a time. If present, the next macro receives
593            // (name = $feature_value:tt), otherwise ().
594            $(
595                (@extract next=$next_macro:path[$next_macro_args:tt] $feature_sq_1
596                    (
597                        $dollar (
598                        $(
599                            $dollar ( $feature_sq_2 = $dollar $feature_sq_2:tt)?
600                        )* ,
601                        )*
602                    )) => {
603                    $next_macro ! ( $next_macro_args, (
604                        $feature_sq_1 = $dollar ( $dollar ( $dollar $feature_sq_1 )? )*
605                    ) );
606                };
607            )*
608
609            (@extract next=$next_macro:path[$next_macro_args:tt] $dollar feature:ident $dollar ($dollar rest:tt)*) => {
610                const _: () = { compile_error!(concat!("Unexpected input: ", stringify!($dollar feature))); };
611            };
612
613            // @meta extracts the meta items from the proc-macro attribute. The
614            // items need to be pre-processed to ensure that each one ends with
615            // a comma and a semicolon to disambiguate.
616            (@meta macro=$macro_path:path, next=$next_macro:path[$next_macro_args:tt]
617                $dollar (
618                    $($(
619                        $dollar(
620                            $($attr)*
621                            ,
622                            $dollar $feature:tt // comma
623                        )?
624                    )?)*
625                    ;
626                )*
627            ) => {
628                $next_macro ! ( $next_macro_args, ( $(($feature = $(
629                    $dollar ( $dollar( $($attr_output)* $dollar $feature )? )*
630                )? $default_value))* ) );
631            };
632
633            // Unrecognized, munch until end of recognized input.
634            (@meta macro=$macro_path:path, next=$next_macro:path[$next_macro_args:tt]
635                $dollar ($dollar rest:tt)*) => {
636                $macro_path!(@metaerror macro=$macro_path, next=$next_macro[$next_macro_args] $dollar($dollar rest)*);
637            };
638
639            (@metaerror macro=$macro_path:path, next=$next_macro:path[$next_macro_args:tt]
640                $($(
641                    $dollar(
642                        $($attr)*
643                        ,
644                        $dollar $feature:tt // comma
645                    )?
646                )?)*
647                ;
648                $dollar ($dollar rest:tt)*) => {
649                $macro_path!(@metaerror macro=$macro_path, next=$next_macro[$next_macro_args] $dollar($dollar rest)*);
650            };
651
652            (@metaerror macro=$macro_path:path, next=$next_macro:path[$next_macro_args:tt]
653                $dollar ($dollar rest:tt)*) => {
654                $crate::__extract_meta!(@error rest=($dollar($dollar rest)*) attrs=($($($($attr)* ;)?)*));
655            };
656
657            // @self extracts the self-attribute from a list of attributes.
658            (@self next=$next_macro:path [$next_macro_args:tt], input=(# [ $macro_name ])) => {
659                $next_macro ! ( $next_macro_args, ( self = (()) ) );
660            };
661            (@self next=$next_macro:path [$next_macro_args:tt], input=(# [ $macro_name $args:tt ])) => {
662                $next_macro ! ( $next_macro_args, ( self = ($args) ) );
663            };
664            (@self next=$next_macro:path [$next_macro_args:tt], input=$input:tt) => {
665                $next_macro ! ( $next_macro_args, ( other = $input ) );
666            };
667
668            // Extracts all features specified in $all_features and passes them
669            // to the next macro.
670            (@entry next=$next_macro:path [$next_macro_args:tt],
671                input=$all_features:tt,
672                args=[$macro:path => @extract $features:tt]) => {
673                $crate::__extract_features!(@entry macro=$macro, next=($next_macro [$next_macro_args]),
674                    features=$features, all_features=$all_features);
675            };
676
677            // Extracts features from enabled crate features.
678            (@entry next=$next_macro:path [$next_macro_args:tt],
679                input=$all_features:tt,
680                args=[$macro:path => @crate]) => {
681                $next_macro ! ( $next_macro_args, (
682                    $( $feature = $default_value, )*
683                ) );
684            };
685
686            // Extracts the self-attribute from a list of attributes.
687            (@entry next=$next_macro:path [$next_macro_args:tt],
688                input=($dollar ( # $dollar attr:tt )*),
689                args=[$macro:path => @self]) => {
690                $crate::__extract_self!(@entry macro=$macro, next=($next_macro [$next_macro_args]), input=($dollar ( # $dollar attr )*));
691            };
692
693            // Extracts the raw features from the input and passes them to the next macro.
694            (@entry next=$next_macro:path [$next_macro_args:tt],
695                input=$input:tt, // ignored
696                args=[$macro:path => @raw]) => {
697                $next_macro ! ( $next_macro_args, $raw_features );
698            };
699
700            (@entry $dollar ($rest:tt)*) => {
701                const _: () = { compile_error!(concat!("Unexpected input: ", stringify!($dollar ($rest)*))); };
702            };
703        }
704
705        $next ! ( $next_args, () );
706    };
707}
708
709/// Generates a module named $macro_impl and inside, two crate-scoped macros:
710///
711/// make_crate_docs and make_attr_docs.
712///
713/// These macros are used to generate the documentation for the crate-scoped
714/// features.
715///
716/// `make_crate_docs` generates docs for crate features. `make_attr_docs`
717/// generates docs for proc macro attributes.
718#[macro_export]
719#[doc(hidden)]
720macro_rules! __make_docs {
721    ( @entry next=$next:path[$next_args:tt], input=(
722        $(
723            (
724                feature = $feature:ident;
725                $(
726                    feature_crate = $feature_crate:ident;
727                    name = $feature_name:literal;
728                    crate_docs = [ $( $crate_doc_lit:literal )* ];
729                )?
730                $(
731                    feature_attr = $feature_attr:ident;
732                    attr = [($($attr:tt)*) => ($($attr_output:tt)*)];
733                    attr_docs = [ $( $attr_doc_lit:literal )* ];
734                )?
735                original_defaults = $original_defaults:tt;
736                default = $default_value:tt;
737            )
738        )*
739    )) => {
740        $crate::__make_docs!(@defaults accum=(
741            #![doc = "\n\n# Crate Features\n\n| Cargo feature | Description |\n| --- | --- |"]
742            $(
743                $(
744                    #![doc = concat!("\n| `", stringify!($feature_crate), "` | ", $( $crate_doc_lit, )* " |")]
745                )?
746            )*
747            #![doc = "\n\n# Macro Attributes\n\n<table><tr><th>Attribute</th><th>Description</th></tr>\n"]
748            $(
749                $(
750                    #![doc = concat!("\n<tr><td><code>", stringify!($($attr)*), "</code></td><td>\n\n", $( $attr_doc_lit, "\n", )*  "\n\n</td></tr>")]
751                )?
752            )*
753            #![doc = "</table>"]
754            #![doc = "\n\n# Defaults"]
755        ),
756            ($(
757                (feature = $feature; default = $original_defaults;)
758            )*)
759        );
760    };
761
762    // Emits one "defaults" subsection per feature that has a non-()` default.
763    (@defaults accum=($($accum:tt)*), ()) => {
764        mod __generated_docs {
765            $($accum)*
766        }
767    };
768
769    // Hide attributes with no default.
770    (@defaults accum=($($accum:tt)*), ((feature = $feature:ident; default = {(_ => ())};) $($rest:tt)*)) => {
771        $crate::__make_docs!(@defaults accum=(
772            $($accum)*
773        ), ($($rest)*));
774    };
775    // Hide crate features with no default.
776    (@defaults accum=($($accum:tt)*), ((feature = $feature:ident; default = {((feature = $feature_lit:literal) => $feature_default_value:ident) (_ => ())};) $($rest:tt)*)) => {
777        $crate::__make_docs!(@defaults accum=(
778            $($accum)*
779        ), ($($rest)*));
780    };
781
782    (@defaults accum=($($accum:tt)*), ((feature = $feature:ident; default = $default_value:tt;) $($rest:tt)*)) => {
783        $crate::__make_docs!(@default accum=(
784            $($accum)*
785            //!
786            #![doc = concat!("## `", stringify!($feature), "`")]
787            //!
788            //! ```rust
789            //! # #[cfg(false)] {
790        ), ((feature = $feature; default = $default_value;) $($rest)*));
791    };
792    (@default accum=($($accum:tt)*), ((feature = $feature:ident; default = {
793        (($($branch:tt)*) => $default_value:tt) $($branch_rest:tt)*};) $($rest:tt)*)) => {
794        $crate::__make_docs!(@default accum=(
795            $($accum)*
796            #![doc = concat!("#[cfg(", stringify!($($branch)*), ")]")]
797            //! # const _: () = { let
798            #![doc = concat!(stringify!($feature), " = ", stringify!($default_value))]
799            //! # ; };
800            //!
801        ), ((feature = $feature; default = {$($branch_rest)*};) $($rest)*));
802    };
803    (@default accum=($($accum:tt)*), ((feature = $feature:ident; default = {
804        (_ => $default_value:tt) $($branch_rest:tt)*};) $($rest:tt)*)) => {
805        $crate::__make_docs!(@defaults accum=(
806            $($accum)*
807            //! // default
808            #![doc = concat!(stringify!($feature), " = ", stringify!($default_value))]
809            //! # }
810            //! ```
811        ), ($($rest)*));
812    };
813
814
815    ( $($input:tt)* ) => {
816        const _: () = { compile_error!(concat!("Unexpected input: ", stringify!($($input)*))); };
817    };
818}