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;