1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use super::ParseMacroInput;
use crate::{fce_ast_types, AstRecordField};
use crate::fce_ast_types::FCEAst;
use syn::Error;
use syn::Result;
use syn::spanned::Spanned;
use crate::parsed_type::ParsedType;
impl ParseMacroInput for syn::ItemStruct {
fn parse_macro_input(self) -> Result<FCEAst> {
check_record(&self)?;
let fields = match &self.fields {
syn::Fields::Named(named_fields) => &named_fields.named,
syn::Fields::Unnamed(unnamed_fields) => &unnamed_fields.unnamed,
_ => return Err(Error::new(self.span(), "only named field allowed")),
};
let fields = fields
.iter()
.map(|field| {
check_field(field)?;
let field_name = field.ident.as_ref().map(|ident| {
ident
.to_string()
.split(' ')
.last()
.unwrap_or_default()
.to_string()
});
let field_type = ParsedType::from_type(&field.ty)?;
Ok(AstRecordField {
name: field_name,
ty: field_type,
})
})
.collect::<Result<Vec<_>>>()?;
let name = self.ident.to_string();
let ast_record_item = fce_ast_types::AstRecordItem {
name,
fields,
original: Some(self),
};
Ok(FCEAst::Record(ast_record_item))
}
}
fn check_record(record: &syn::ItemStruct) -> Result<()> {
if record.generics.lt_token.is_some()
|| record.generics.gt_token.is_some()
|| record.generics.where_clause.is_some()
{
return Err(Error::new(
record.span(),
"#[fce] couldn't be applied to a struct with generics",
));
}
Ok(())
}
fn check_field(field: &syn::Field) -> Result<()> {
match field.vis {
syn::Visibility::Public(_) => {}
_ => {
return Err(Error::new(
field.span(),
"#[fce] could be applied only to struct with all public fields",
))
}
};
const DOC_ATTR_NAME: &str = "doc";
let is_all_attrs_public = field.attrs.iter().all(|attr| {
let meta = match attr.parse_meta() {
Ok(meta) => meta,
Err(_) => return false,
};
meta.path().is_ident(DOC_ATTR_NAME)
});
if !is_all_attrs_public {
return Err(Error::new(field.span(), "field attributes isn't allowed"));
}
Ok(())
}