odra_ir/
odra_type_item.rs

1use proc_macro2::Ident;
2use syn::{DataEnum, DataStruct, DeriveInput, Fields, Variant};
3
4/// Odra Type definition.
5pub enum OdraTypeItem {
6    Struct(OdraStruct),
7    Enum(OdraEnum)
8}
9
10pub struct OdraStruct {
11    struct_ident: Ident,
12    fields: Vec<Ident>
13}
14
15impl OdraStruct {
16    pub fn struct_ident(&self) -> &Ident {
17        &self.struct_ident
18    }
19
20    pub fn fields(&self) -> &[Ident] {
21        self.fields.as_ref()
22    }
23}
24
25pub struct OdraEnum {
26    enum_ident: Ident,
27    variants: Vec<Variant>
28}
29
30impl OdraEnum {
31    pub fn enum_ident(&self) -> &Ident {
32        &self.enum_ident
33    }
34
35    pub fn variants(&self) -> &[Variant] {
36        &self.variants
37    }
38}
39
40impl OdraTypeItem {
41    pub fn parse(input: DeriveInput) -> Result<Self, syn::Error> {
42        let ident = input.ident.clone();
43        match &input.data {
44            syn::Data::Struct(DataStruct {
45                fields: Fields::Named(named_fields),
46                ..
47            }) => Ok(OdraTypeItem::Struct(OdraStruct {
48                struct_ident: ident,
49                fields: named_fields
50                    .named
51                    .iter()
52                    .map(|f| f.ident.clone().unwrap())
53                    .collect()
54            })),
55            syn::Data::Enum(DataEnum { variants, .. }) => {
56                let is_valid = variants
57                    .iter()
58                    .all(|v| matches!(v.fields, syn::Fields::Unit));
59                if is_valid {
60                    Ok(OdraTypeItem::Enum(OdraEnum {
61                        enum_ident: ident,
62                        variants: variants.iter().map(Clone::clone).collect()
63                    }))
64                } else {
65                    Err(syn::Error::new_spanned(
66                        input,
67                        "Expected a unit enum variant."
68                    ))
69                }
70            }
71            _ => Err(syn::Error::new_spanned(
72                input,
73                "Expected a struct or enum with named fields."
74            ))
75        }
76    }
77
78    pub fn ident(&self) -> &Ident {
79        match self {
80            OdraTypeItem::Struct(s) => s.struct_ident(),
81            OdraTypeItem::Enum(e) => e.enum_ident()
82        }
83    }
84}