1use proc_macro::TokenStream;
4use quote::ToTokens;
5use syn::{Attribute, ItemEnum, ItemStruct, Token, parse::Parse};
6
7mod ext_traits;
8mod preprocessor;
9mod process_enum;
10mod process_struct;
11mod processed_fields;
12
13enum Item {
17 Struct(ItemStruct),
19 Enum(ItemEnum),
21}
22
23impl Parse for Item {
24 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
25 let attrs = input.call(Attribute::parse_outer)?;
26 let vis = input.parse()?;
27
28 if input.peek(Token![struct]) {
29 input
30 .parse()
31 .map(|item: ItemStruct| ItemStruct { vis, attrs, ..item })
32 .map(Item::Struct)
33 } else {
34 input
35 .parse()
36 .map(|item: ItemEnum| ItemEnum { attrs, vis, ..item })
37 .map(Item::Enum)
38 }
39 }
40}
41
42impl From<Item> for TokenStream {
43 fn from(val: Item) -> Self {
44 match val {
45 Item::Struct(item) => item.into_token_stream().into(),
46 Item::Enum(item) => item.into_token_stream().into(),
47 }
48 }
49}
50
51impl Item {
52 fn into_processed(self, strict_mode: bool) -> TokenStream {
55 let result = match self {
56 Item::Struct(item) => {
57 process_struct::into_processed(item, strict_mode)
58 }
59 Item::Enum(item) => process_enum::into_processed(item, strict_mode),
60 };
61
62 match result {
63 Ok(token_stream) => token_stream,
64 Err(error) => error.to_compile_error().into(),
65 }
66 }
67}
68
69#[proc_macro_attribute]
72pub fn sync(args: TokenStream, input: TokenStream) -> TokenStream {
73 let input = syn::parse_macro_input!(input as Item);
74
75 let strict_mode = if !args.is_empty() {
76 let meta = syn::parse_macro_input!(args as syn::Meta);
77 let name_value = match meta.require_name_value() {
78 Ok(name_value) => name_value,
79 Err(err) => {
80 return err.to_compile_error().into();
81 }
82 };
83 if !name_value.path.is_ident("strict_mode") {
84 return syn::Error::new_spanned(
85 name_value.path.clone(),
86 "expected `strict_mode` as the attribute argument",
87 )
88 .to_compile_error()
89 .into();
90 }
91
92 match &name_value.value {
93 syn::Expr::Lit(syn::ExprLit {
94 attrs: _,
95 lit: syn::Lit::Bool(lit),
96 }) => lit.value,
97 _ => {
98 return syn::Error::new_spanned(
99 name_value.value.clone(),
100 "expected a boolean literal as the attribute argument",
101 )
102 .to_compile_error()
103 .into();
104 }
105 }
106 } else {
107 false
108 };
109
110 input.into_processed(strict_mode)
111}