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