extract_variant_internal/
lib.rs1use proc_macro::TokenStream;
4use proc_macro2::Ident;
5use quote::{quote, ToTokens};
6use syn::visit::Visit;
7use syn::{parse_macro_input, Error, Pat, PatIdent, PatOr};
8
9#[derive(Default, Debug)]
10struct VisitPatIdent<'a> {
11 idents: Vec<&'a Ident>,
12 pat_or: Option<proc_macro2::TokenStream>,
13}
14
15impl<'ast> Visit<'ast> for VisitPatIdent<'ast> {
16 fn visit_pat_ident(&mut self, node: &'ast PatIdent) {
17 if node.ident != "None" {
20 self.idents.push(&node.ident);
21 }
22 syn::visit::visit_pat_ident(self, node)
23 }
24
25 fn visit_pat_or(&mut self, node: &'ast PatOr) {
26 self.pat_or = Some(node.to_token_stream())
27 }
29}
30
31#[proc_macro]
32pub fn extract_variant_assign(input: TokenStream) -> TokenStream {
33 let input = parse_macro_input!(input as Pat);
34 let mut visitor = VisitPatIdent::default();
35 visitor.visit_pat(&input);
36
37 if let Some(tokens) = visitor.pat_or {
38 let msg = "`variant` cannot match `or` patterns";
39 let err = Error::new_spanned(tokens, msg).to_compile_error();
40 return TokenStream::from(err);
41 }
42
43 visitor.idents.sort_unstable();
44 let tokens = match visitor.idents.as_slice() {
45 [id] => quote! {
46 #id
47 },
48 ids => quote! {
49 (#(#ids),*)
50 },
51 };
52
53 TokenStream::from(tokens)
54}