Skip to main content

tor_netdoc/parse2/poc/netstatus/
ns_per_flavour_macros.rs

1//! Machinery for defining multiple flavours of network status document
2//!
3//! This module has one sub-module for each flavour.
4//! That sub-module is named after the flavour, and its source file is `flavoured.rs`.
5//! (We treat votes as a "flavour".)
6//!
7//! The following macros are defined for use by `flavoured.rs`
8//! for flavour-dependent elements:
9//!
10//! * **`ns_type!( TypeForVote, TypeForConsensus, [TypeForConsensusMd] )`**:
11//!
12//!   Expands to the appropriate one of the two or three specified types.
13//!   If `TypeForConsensusMd` is not specified, `TypeForConsensus` is used.
14//!
15//! * **`ns_expr!( value_for_vote, value_for_consensus, [value_for_consensus_md] )`**:
16//!
17//!   Expands to the appropriate one of the two or three specified expressions.
18//!   If `value_for_consensus_md` is not specified, `TypeForConsensus` is used.
19//!
20//! * **`ns_choose!( ( FOR VOTE.. )( FOR CONSENSUS.. )( FOR CONSENSUS MD.. ) )`**:
21//!
22//!   Expands to the appropriate one of the two or three specified token streams.
23//!   (The `( )` surrounding each argument are discarded.)
24//
25// Other ways we could have done this:
26//
27//  * Generics: `NsdNetworkStatus<Flavour>`.
28//
29//    The generics get everywhere, and they seriously mess up the
30//    ad-hoc specialisation used for type-based multiplicity dispatch.
31//
32//  * tt-munching macro_rules macro that filters its input body,
33//    replacing pseudo-macro invocations with their expansions.
34//
35//    This does work, but it involves radically increasing
36//    the compiler recursion limit to many thousands.
37//
38//  * custom proc macro(s).
39//
40//    These would probably have to be bespoke to the application.
41//
42//  * build.rs, ad-hoc templating.  But this wouldn't be Rust syntax.
43
44/// Does the work for one flavour.
45///
46///  * `$abbrev` is one of `vote`, `cons`, or `md` as applicable.
47///
48///  * `$suffix` is the `Flavoursuffix`, `Vote`, absent, or `Md`.
49///
50///  * `$vote $cons $md $d` is always `vote cons md $`.
51///    `$d` is needed because it's not possible to write a literal `$`
52///    in the expansion part of a proc macro.  `$$` is not stable.
53///    `$vote` etc. are needed because to match the identifier hygiene of `$abbrev`.
54macro_rules! ns_do_one_flavour { {
55    $vote:ident $cons:ident $md:ident $d:tt :
56    $abbrev:ident
57    $($suffix:ident)?
58} => {
59    macro_rules! ns_choose {
60        {
61            ( $d( $d $vote:tt )* )
62            ( $d( $d $cons:tt )* )
63            ( $d( $d $md  :tt )* )
64        } => {
65            $d( $d $abbrev )*
66        };
67        {
68            ( $d( $d vote:tt )* )
69            ( $d( $d cons:tt )* )
70        } => { ns_choose! {
71            ( $d( $d vote    )* )
72            ( $d( $d cons    )* )
73            ( $d( $d cons    )* )
74        } }
75    }
76    macro_rules! ns_type {
77        { $d( $d option:ty ),* $d(,)? } => { ns_choose!( $d( ( $d option ) )* ) }
78    }
79    macro_rules! ns_expr {
80        { $d( $d option:expr ),* $d(,)? } => { ns_choose!( $d( ( $d option ) )* ) }
81    }
82    #[allow(clippy::duplicate_mod)]
83    #[path = "flavoured.rs"]
84    pub mod $abbrev;
85} }
86ns_do_one_flavour! {
87    vote cons md $ : vote Vote
88}
89ns_do_one_flavour! {
90    vote cons md $ : cons Ns
91}
92ns_do_one_flavour! {
93    vote cons md $ : md Md
94}
95
96/// Export each `flavour::Ty` as `TyFlavour`
97macro_rules! ns_export_flavoured_types { { $( $ty:ident ),* $(,)? } => { paste!{
98    pub use { $( vote::$ty as [<$ty Vote>], )* };
99    pub use { $( cons::$ty as [<$ty Ns>],   )* };
100    pub use { $( md::$ty   as [<$ty Md>],   )* };
101} } }
102pub(crate) use ns_export_flavoured_types;