1mod attributes;
4mod compile_error;
5mod deserialize_impl;
6mod utils;
7use attributes::Attributes;
9use deserialize_impl::DeserializeImpl;
10use utils::tri;
11extern crate alloc;
13use alloc::format;
14use quote::quote;
16use syn::Data;
17
18#[proc_macro_derive(Deserialize, attributes(serde, versioning))]
19pub fn derive_deserialize_versioned(
20 input: proc_macro::TokenStream,
21) -> proc_macro::TokenStream {
22 let derive_input: syn::DeriveInput = syn::parse_macro_input!(input);
23
24 let Some(versioning_attr) = derive_input
25 .attrs
26 .iter()
27 .find(|meta| meta.path().is_ident("versioning"))
28 else {
29 return tri!(DeserializeImpl::try_from(derive_input)).into();
30 };
31
32 let Attributes {
33 versioning,
34 optimistic,
35 } = tri!(Attributes::try_from(versioning_attr));
36 let ds_ident = derive_input.ident.clone();
37 let ds_kind_name = match derive_input.data {
38 Data::Enum(_) => "enum",
39 Data::Struct(_) => "struct",
40 Data::Union(_) => "union",
41 };
42 let no_match_message =
43 format!("data did not match any version of {ds_kind_name} {ds_ident}.");
44
45 let mut deserialize_impl = tri!(DeserializeImpl::try_from(derive_input));
46
47 tri!(deserialize_impl.replace_body(|de_stmts|{
48 let deserialization = if optimistic {
49 quote! {
50 if let Ok(__ok) = { #(#de_stmts)* } { return Ok(__ok) }
51 #versioning
52 return Err(_serde::de::Error::custom(#no_match_message));
53 }
54 } else {
55 quote! {
56 #versioning
57 #(#de_stmts)*
58 }
59 };
60
61 quote! {{
62 use _serde::__private::de::{Content, ContentRefDeserializer};
63 let __content = Content::deserialize(__deserializer)?;
64 let __deserializer = ContentRefDeserializer::<__D::Error>::new(&__content);
65
66 #deserialization
67 }}
68 }));
69
70 proc_macro::TokenStream::from(deserialize_impl)
71}
72
73#[rustfmt::skip]
75mod serde_derive_implementation;
76#[allow(clippy::wildcard_imports)]
77use serde_derive_implementation::*;