lazy_borink_derive/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, Data, DeriveInput, Fields};
6
7#[proc_macro_derive(UnwrapLazy)]
8pub fn unwrap_lazy_derive(input: TokenStream) -> TokenStream {
9    let input = parse_macro_input!(input as DeriveInput);
10
11    let name = &input.ident;
12    let generics = &input.generics;
13    let unwrap_lazy_impl = generate_unwrap_lazy_impl(&input.data, name);
14
15    let expanded = quote! {
16        const _: () = {
17            use rmp_serde::decode::Error as UnwrapLazyError;
18            #[automatically_derived]
19            impl #generics UnwrapLazy for #name #generics {
20                fn try_unwrap_lazy(self) -> Result<Self, UnwrapLazyError> {
21                    Ok(#unwrap_lazy_impl)
22                }
23            }
24        };
25    };
26
27    TokenStream::from(expanded)
28}
29
30fn generate_unwrap_lazy_impl(data: &Data, name: &syn::Ident) -> proc_macro2::TokenStream {
31    match data {
32        Data::Struct(data_struct) => {
33            let fields = match &data_struct.fields {
34                Fields::Named(fields) => &fields.named,
35                _ => panic!("UnwrapLazy can only be derived for structs with named fields"),
36            };
37
38            let field_unwraps = fields.iter().map(|field| {
39                let field_name = &field.ident;
40                quote! {
41                    #field_name: self.#field_name.try_unwrap_lazy()?,
42                }
43            });
44
45            quote! {
46                #name {
47                    #(#field_unwraps)*
48                }
49            }
50        }
51        _ => panic!("UnwrapLazy can only be derived for structs"),
52    }
53}