1//! Analyze enums
  2use quote::quote;
  3use syn::ItemEnum;
  4
  5use crate::data_model::{Enum, Field, Variant};
  6
  7use super::docstring_from_attrs;
  8
  9impl Enum {
 10    /// Fully qualified name of the variant
 11    pub fn path_str(&self) -> String {
 12        self.path.join("::")
 13    }
 14    /// Extract the relevant information from the AST
 15    pub fn parse(parent: &[&str], ast: &ItemEnum) -> Self {
 16        let name = ast.ident.to_string();
 17        let path: Vec<&str> = parent.iter().copied().chain(Some(name.as_str())).collect();
 18        let docstring = docstring_from_attrs(&ast.attrs);
 19        let variants = ast
 20            .variants
 21            .iter()
 22            .map(|v| Variant::parse(&path, v))
 23            .collect::<Vec<_>>();
 24        Self {
 25            path: path.iter().map(|s| s.to_string()).collect(),
 26            docstring,
 27            variants,
 28        }
 29    }
 30}
 31
 32impl Variant {
 33    /// Fully qualified name of the variant
 34    pub fn name(&self) -> String {
 35        self.path.join("::")
 36    }
 37    /// Extract the relevant information from the AST
 38    pub fn parse(parent: &[&str], ast: &syn::Variant) -> Self {
 39        let name = ast.ident.to_string();
 40        let path = parent
 41            .iter()
 42            .copied()
 43            .chain(Some(name.as_str()))
 44            .collect::<Vec<&str>>();
 45        let docstring = docstring_from_attrs(&ast.attrs);
 46        let discriminant = ast
 47            .discriminant
 48            .as_ref()
 49            .map(|(_, e)| quote! {#e}.to_string());
 50        let fields = ast
 51            .fields
 52            .iter()
 53            .enumerate()
 54            .map(|(i, f)| Field::parse(&path, i, f))
 55            .collect::<Vec<_>>();
 56        Self {
 57            path: path.iter().map(|s| s.to_string()).collect(),
 58            docstring,
 59            discriminant,
 60            fields,
 61        }
 62    }
 63}
 64
 65#[cfg(test)]
 66mod tests {
 67    use super::*;
 68    use insta::assert_yaml_snapshot;
 69    use syn::parse_quote;
 70
 71    #[test]
 72    fn test_parse_enum() {
 73        let ast: ItemEnum = parse_quote! {
 74            /// Multi-line
 75            /// docstring
 76            pub enum MyEnum {
 77                /// variant without fields
 78                MyVariant1,
 79                /// variant with discriminant
 80                MyVariant2 = 1,
 81                /// variant with unnamed fields
 82                MyVariant3(u8),
 83                /// variant with named fields
 84                MyVariant3 {
 85                    /// field docstring
 86                    field: u8,
 87                },
 88            }
 89        };
 90        let enum_ = Enum::parse(&["crate"], &ast);
 91        assert_yaml_snapshot!(enum_, @r###"
 92        ---
 93        path:
 94          - crate
 95          - MyEnum
 96        docstring: "Multi-line\ndocstring"
 97        variants:
 98          - path:
 99              - crate
100              - MyEnum
101              - MyVariant1
102            docstring: variant without fields
103            discriminant: ~
104            fields: []
105          - path:
106              - crate
107              - MyEnum
108              - MyVariant2
109            docstring: variant with discriminant
110            discriminant: "1"
111            fields: []
112          - path:
113              - crate
114              - MyEnum
115              - MyVariant3
116            docstring: variant with unnamed fields
117            discriminant: ~
118            fields:
119              - path:
120                  - crate
121                  - MyEnum
122                  - MyVariant3
123                  - "0"
124                docstring: ""
125                type_:
126                  - Path: u8
127          - path:
128              - crate
129              - MyEnum
130              - MyVariant3
131            docstring: variant with named fields
132            discriminant: ~
133            fields:
134              - path:
135                  - crate
136                  - MyEnum
137                  - MyVariant3
138                  - field
139                docstring: field docstring
140                type_:
141                  - Path: u8
142        "###);
143    }
144}