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}