1//! Analyze structs
2use syn::{ItemStruct, Visibility};
3
4use crate::data_model::{Field, Struct};
5
6use super::{docstring_from_attrs, type_::convert_type};
7
8impl Struct {
9 /// Fully qualified name of the variant
10 pub fn path_str(&self) -> String {
11 self.path.join("::")
12 }
13 /// Extract the relevant information from the AST
14 pub fn parse(parent: &[&str], ast: &ItemStruct) -> Self {
15 let name = ast.ident.to_string();
16 let path = parent
17 .iter()
18 .copied()
19 .chain(Some(name.as_str()))
20 .collect::<Vec<&str>>();
21 let docstring = docstring_from_attrs(&ast.attrs);
22 let mut struct_ = Self {
23 path: path.iter().map(|s| s.to_string()).collect(),
24 docstring,
25 fields: vec![],
26 };
27 for (i, field) in ast.fields.iter().enumerate() {
28 if let Visibility::Public(_) = field.vis {
29 struct_.fields.push(Field::parse(&path, i, field));
30 }
31 }
32 struct_
33 }
34}
35
36impl Field {
37 /// Extract the relevant information from the AST
38 pub fn parse(parent: &[&str], position: usize, ast: &syn::Field) -> Self {
39 let name = ast
40 .ident
41 .as_ref()
42 .map(|name| name.to_string())
43 .unwrap_or(position.to_string());
44 let path = parent
45 .iter()
46 .copied()
47 .chain(Some(name.as_str()))
48 .collect::<Vec<&str>>();
49 let docstring = docstring_from_attrs(&ast.attrs);
50 let type_ = convert_type(&ast.ty);
51 Self {
52 path: path.iter().map(|s| s.to_string()).collect(),
53 docstring,
54 type_,
55 }
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use insta::assert_yaml_snapshot;
63 use syn::parse_quote;
64
65 #[test]
66 fn test_parse_struct_no_fields() {
67 let ast: ItemStruct = parse_quote! {
68 /// Multi-line
69 /// docstring
70 pub struct MyStruct;
71 };
72 let struct_ = Struct::parse(&["crate"], &ast);
73 assert_yaml_snapshot!(struct_, @r###"
74 ---
75 path:
76 - crate
77 - MyStruct
78 docstring: "Multi-line\ndocstring"
79 fields: []
80 "###);
81 }
82
83 #[test]
84 fn test_parse_struct_fields() {
85 let ast: ItemStruct = parse_quote! {
86 /// Multi-line
87 /// docstring
88 pub struct MyStruct {
89 /// Docstring
90 pub my_field: [T; 1],
91 /// a non-public field
92 other: String,
93 }
94 };
95 let struct_ = Struct::parse(&["crate"], &ast);
96 assert_yaml_snapshot!(struct_, @r###"
97 ---
98 path:
99 - crate
100 - MyStruct
101 docstring: "Multi-line\ndocstring"
102 fields:
103 - path:
104 - crate
105 - MyStruct
106 - my_field
107 docstring: Docstring
108 type_:
109 - String: "["
110 - Path: T
111 - String: "; 1]"
112 "###);
113 }
114}