% 列挙型の解析
macro_rules! parse_unitary_variants { (@as_expr $e:expr) => {$e}; (@as_item $($i:item)+) => {$($i)+}; // 終了ルール。 ( @collect_unitary_variants ($callback:ident ( $($args:tt)* )), ($(,)*) -> ($($var_names:ident,)*) ) => { parse_unitary_variants! { @as_expr $callback!{ $($args)* ($($var_names),*) } } }; ( @collect_unitary_variants ($callback:ident { $($args:tt)* }), ($(,)*) -> ($($var_names:ident,)*) ) => { parse_unitary_variants! { @as_item $callback!{ $($args)* ($($var_names),*) } } }; // 属性を消費する。 ( @collect_unitary_variants $fixed:tt, (#[$_attr:meta] $($tail:tt)*) -> ($($var_names:tt)*) ) => { parse_unitary_variants! { @collect_unitary_variants $fixed, ($($tail)*) -> ($($var_names)*) } }; // 必要に応じて初期化子付きのバリアントを処理する。 ( @collect_unitary_variants $fixed:tt, ($var:ident $(= $_val:expr)*, $($tail:tt)*) -> ($($var_names:tt)*) ) => { parse_unitary_variants! { @collect_unitary_variants $fixed, ($($tail)*) -> ($($var_names)* $var,) } }; // ペイロードを持つバリアントで中止する。 ( @collect_unitary_variants $fixed:tt, ($var:ident $_struct:tt, $($tail:tt)*) -> ($($var_names:tt)*) ) => { const _error: () = "非単位バリアントを含む enum から単位バリアントを解析できません"; }; // エントリルール。 (enum $name:ident {$($body:tt)*} => $callback:ident $arg:tt) => { parse_unitary_variants! { @collect_unitary_variants ($callback $arg), ($($body)*,) -> () } }; } fn main() { assert_eq!( parse_unitary_variants!( enum Dummy { A, B, C } => stringify(variants:) ), "variants : ( A , B , C )" ); }
このマクロは、インクリメンタル tt muncher と プッシュダウン蓄積 を使用して、すべてのバリアントが単位バリアント(すなわち、ペイロードを持たない)である enum のバリアントを解析する方法を示しています。完了すると、parse_unitary_variants! はバリアントのリスト(および指定されたその他の任意の引数)を指定して コールバック マクロを呼び出します。
これは、struct フィールドの解析、バリアントのタグ値の計算、さらには任意の enum に含まれる すべての バリアント名の抽出も行えるように変更できます。