serde_versioning/
lib.rs

1// #![no_std]
2/* Modules */
3mod attributes;
4mod compile_error;
5mod deserialize_impl;
6mod utils;
7/* Crate imports */
8use attributes::Attributes;
9use deserialize_impl::DeserializeImpl;
10use utils::tri;
11/* Built-in imports */
12extern crate alloc;
13use alloc::format;
14/* Dependencies */
15use 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/* SERDE DERIVE INTERNALS */
74#[rustfmt::skip]
75mod serde_derive_implementation;
76#[allow(clippy::wildcard_imports)]
77use serde_derive_implementation::*;