fluence_sdk_wit/parse_macro_input/
item_record.rs1use super::ParseMacroInput;
18use crate::ast_types;
19use crate::ast_types::AstRecordField;
20use crate::ast_types::AstRecordFields;
21use crate::ast_types::FCEAst;
22use crate::syn_error;
23use crate::parsed_type::ParsedType;
24
25use syn::Result;
26use syn::spanned::Spanned;
27
28impl ParseMacroInput for syn::ItemStruct {
29 fn parse_macro_input(self) -> Result<FCEAst> {
30 check_record(&self)?;
31
32 let fields = match &self.fields {
33 syn::Fields::Named(named_fields) => &named_fields.named,
34 _ => return syn_error!(self.span(), "only named fields are allowed in structs"),
35 };
36
37 let fields = fields_into_ast(fields)?;
38 let fields = AstRecordFields::Named(fields);
39
40 let name = self.ident.to_string();
41 let ast_record_item = ast_types::AstRecord {
42 name,
43 fields,
44 original: self,
45 };
46
47 Ok(FCEAst::Record(ast_record_item))
48 }
49}
50
51fn check_record(record: &syn::ItemStruct) -> Result<()> {
52 if record.generics.lt_token.is_some()
53 || record.generics.gt_token.is_some()
54 || record.generics.where_clause.is_some()
55 {
56 return syn_error!(
57 record.span(),
58 "#[fce] couldn't be applied to a struct with generics or lifetimes"
59 );
60 }
61
62 Ok(())
63}
64
65fn fields_into_ast(
66 fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>,
67) -> Result<Vec<AstRecordField>> {
68 fields
69 .iter()
70 .map(|field| {
71 check_field(field)?;
72 let name = field.ident.as_ref().map(|ident| {
73 ident
74 .to_string()
75 .split(' ')
76 .last()
77 .unwrap_or_default()
78 .to_string()
79 });
80 let ty = ParsedType::from_type(&field.ty)?;
81
82 let record_field = AstRecordField { name, ty };
83 Ok(record_field)
84 })
85 .collect::<Result<Vec<_>>>()
86}
87
88fn check_field(field: &syn::Field) -> Result<()> {
92 match field.vis {
93 syn::Visibility::Public(_) => {}
94 _ => {
95 return syn_error!(
96 field.span(),
97 "#[fce] could be applied only to struct with all public fields"
98 )
99 }
100 };
101
102 const DOC_ATTR_NAME: &str = "doc";
103
104 let is_all_attrs_public = field.attrs.iter().all(|attr| {
106 let meta = match attr.parse_meta() {
107 Ok(meta) => meta,
108 Err(_) => return false,
109 };
110 meta.path().is_ident(DOC_ATTR_NAME)
111 });
112
113 if !is_all_attrs_public {
114 return syn_error!(field.span(), "field attributes isn't allowed");
115 }
116
117 Ok(())
118}