preprocess_macro/
lib.rs

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}