serde_double_tag_derive/
lib.rs1mod generate;
6mod input;
7mod util;
8
9fn crate_name() -> syn::Path {
10 let mut segments = syn::punctuated::Punctuated::new();
11 segments.push(syn::PathSegment {
12 ident: syn::Ident::new("serde_double_tag", proc_macro2::Span::call_site()),
13 arguments: syn::PathArguments::None,
14 });
15 syn::Path {
16 leading_colon: Some(syn::token::PathSep(proc_macro2::Span::call_site())),
17 segments,
18 }
19}
20
21struct Context {
22 internal: syn::Path,
23 serde: syn::Path,
24 #[cfg(feature = "schemars")]
25 schemars: syn::Path,
26 errors: Vec<syn::Error>,
27}
28
29impl Context {
30 fn new(crate_name: syn::Path) -> Self {
31 let internal = extend_path(&crate_name, "internal__");
32 let serde = extend_path(&internal, "serde");
33 #[cfg(feature = "schemars")]
34 let schemars = extend_path(&internal, "schemars");
35 Self {
36 internal,
37 serde,
38 #[cfg(feature = "schemars")]
39 schemars,
40 errors: Vec::new(),
41 }
42 }
43
44 fn error(&mut self, span: proc_macro2::Span, message: impl std::fmt::Display) {
45 self.errors.push(syn::Error::new(span, format_args!("serde_double_tag: {message}")))
46 }
47
48 fn spanned_error<T: quote::ToTokens>(&mut self, object: &T, message: impl std::fmt::Display) {
49 self.errors.push(syn::Error::new_spanned(
50 object,
51 format_args!("serde_double_tag: {message}"),
52 ))
53 }
54
55 fn syn_error(&mut self, error: syn::Error) {
56 self.error(error.span(), error)
57 }
58
59 fn collect_errors(self, mut tokens: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
60 for error in self.errors {
61 tokens.extend(error.into_compile_error())
62 }
63 tokens
64 }
65}
66
67#[proc_macro_derive(Deserialize, attributes(serde))]
68pub fn derive_deserialize(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
69 let mut context = Context::new(crate_name());
70 let output = match input::Enum::parse2(&mut context, tokens.into()) {
71 Ok(input) => generate::impl_deserialize_enum(&mut context, input),
72 Err(()) => proc_macro2::TokenStream::new(),
73 };
74 context.collect_errors(output).into()
75}
76
77#[proc_macro_derive(Serialize, attributes(serde))]
78pub fn derive_serialize(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
79 let mut context = Context::new(crate_name());
80 let output = match input::Enum::parse2(&mut context, tokens.into()) {
81 Ok(input) => generate::impl_serialize_enum(&mut context, input),
82 Err(()) => proc_macro2::TokenStream::new(),
83 };
84 context.collect_errors(output).into()
85}
86
87#[proc_macro_derive(JsonSchema, attributes(serde))]
88#[cfg(feature = "schemars")]
89pub fn derive_json_schema(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
90 let mut context = Context::new(crate_name());
91 let output = match input::Enum::parse2(&mut context, tokens.into()) {
92 Ok(input) => generate::impl_json_schema(&mut context, input),
93 Err(()) => proc_macro2::TokenStream::new(),
94 };
95 context.collect_errors(output).into()
96}
97
98fn extend_path(path: &syn::Path, segment: &str) -> syn::Path {
99 let mut output = path.clone();
100 output.segments.push(syn::PathSegment {
101 ident: syn::Ident::new(segment, proc_macro2::Span::call_site()),
102 arguments: Default::default(),
103 });
104 output
105}