serde_repr/
parse.rs

1use proc_macro2::{Span, TokenStream, TokenTree};
2use syn::parse::{Error, Parse, ParseStream, Result};
3use syn::{parenthesized, token, Attribute, Data, DeriveInput, Expr, Fields, Ident, Meta, Token};
4
5pub struct Input {
6    pub ident: Ident,
7    pub repr: Ident,
8    pub variants: Vec<Variant>,
9    pub default_variant: Option<Variant>,
10}
11
12#[derive(Clone)]
13pub struct Variant {
14    pub ident: Ident,
15    pub attrs: VariantAttrs,
16}
17
18#[derive(Clone)]
19pub struct VariantAttrs {
20    pub is_default: bool,
21}
22
23fn parse_serde_attr(attrs: &mut VariantAttrs, attr: &Attribute) {
24    if let Meta::List(_) = attr.meta {
25        let _ = attr.parse_nested_meta(|meta| {
26            if meta.input.peek(Token![=]) {
27                let _value: Expr = meta.value()?.parse()?;
28            } else if meta.input.peek(token::Paren) {
29                let _group: TokenTree = meta.input.parse()?;
30            } else if meta.path.is_ident("other") {
31                attrs.is_default = true;
32            }
33            Ok(())
34        });
35    }
36}
37
38fn parse_attrs(variant: &syn::Variant) -> VariantAttrs {
39    let mut attrs = VariantAttrs { is_default: false };
40    for attr in &variant.attrs {
41        if attr.path().is_ident("serde") {
42            parse_serde_attr(&mut attrs, attr);
43        }
44    }
45    attrs
46}
47
48impl Parse for Input {
49    fn parse(input: ParseStream) -> Result<Self> {
50        let call_site = Span::call_site();
51        let derive_input = DeriveInput::parse(input)?;
52
53        let data = match derive_input.data {
54            Data::Enum(data) => data,
55            _ => {
56                return Err(Error::new(call_site, "input must be an enum"));
57            }
58        };
59
60        let variants = data
61            .variants
62            .into_iter()
63            .map(|variant| match variant.fields {
64                Fields::Unit => {
65                    let attrs = parse_attrs(&variant);
66                    Ok(Variant {
67                        ident: variant.ident,
68                        attrs,
69                    })
70                }
71                Fields::Named(_) | Fields::Unnamed(_) => Err(Error::new(
72                    variant.ident.span(),
73                    "must be a unit variant to use serde_repr derive",
74                )),
75            })
76            .collect::<Result<Vec<Variant>>>()?;
77
78        if variants.is_empty() {
79            return Err(Error::new(call_site, "there must be at least one variant"));
80        }
81
82        let generics = derive_input.generics;
83        if !generics.params.is_empty() || generics.where_clause.is_some() {
84            return Err(Error::new(call_site, "generic enum is not supported"));
85        }
86
87        let mut repr = None;
88        for attr in derive_input.attrs {
89            if attr.path().is_ident("repr") {
90                if let Meta::List(meta) = &attr.meta {
91                    meta.parse_nested_meta(|meta| {
92                        const RECOGNIZED: &[&str] = &[
93                            "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64",
94                            "i128", "isize",
95                        ];
96                        if RECOGNIZED.iter().any(|int| meta.path.is_ident(int)) {
97                            repr = Some(meta.path.get_ident().unwrap().clone());
98                            return Ok(());
99                        }
100                        if meta.path.is_ident("align") || meta.path.is_ident("packed") {
101                            if meta.input.peek(token::Paren) {
102                                let arg;
103                                parenthesized!(arg in meta.input);
104                                let _ = arg.parse::<TokenStream>()?;
105                            }
106                            return Ok(());
107                        }
108                        Err(meta.error("unsupported repr for serde_repr enum"))
109                    })?;
110                }
111            }
112        }
113        let repr = repr.ok_or_else(|| Error::new(call_site, "missing #[repr(...)] attribute"))?;
114
115        let mut default_variants = variants.iter().filter(|x| x.attrs.is_default);
116        let default_variant = default_variants.next().cloned();
117        if default_variants.next().is_some() {
118            return Err(Error::new(
119                call_site,
120                "only one variant can be #[serde(other)]",
121            ));
122        }
123
124        Ok(Input {
125            ident: derive_input.ident,
126            repr,
127            variants,
128            default_variant,
129        })
130    }
131}