1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{parse_macro_input, Attribute, Data, DeriveInput, Expr, Fields, Path};
4
5#[proc_macro_derive(BorshDeserializeIncremental, attributes(incremental))]
6pub fn derive(input: TokenStream) -> TokenStream {
7 let input = parse_macro_input!(input as DeriveInput);
9 let ident = input.ident;
10 let (impl_g, ty_g, where_c) = input.generics.split_for_impl();
11
12 let mut error_ty: Option<Path> = None;
14 for a in &input.attrs {
15 if a.path().is_ident("incremental") {
16 let _ = a.parse_nested_meta(|meta| {
17 if meta.path.is_ident("error") {
18 let value: Expr = meta.value()?.parse()?;
19 if let Expr::Path(p) = value {
20 error_ty = Some(p.path);
21 } else {
22 return Err(meta.error("expected path for error type"));
23 }
24 }
25 Ok(())
26 });
27 }
28 }
29 let error_ty = error_ty.unwrap_or_else(|| syn::parse_quote!(::std::io::Error));
31
32 let fields = match input.data {
34 Data::Struct(s) => match s.fields {
35 Fields::Named(n) => n.named,
36 _ => panic!("BorshDeserializeIncremental only supports named structs"),
37 },
38 _ => panic!("BorshDeserializeIncremental only supports structs"),
39 };
40
41 fn parse_field_attrs(attrs: &[Attribute]) -> (Option<Path>, Option<Expr>) {
43 let mut deser_with: Option<Path> = None;
44 let mut default_expr: Option<Expr> = None;
45 for a in attrs {
46 if a.path().is_ident("incremental") {
47 let _ = a.parse_nested_meta(|meta| {
48 if meta.path.is_ident("deser_with") {
49 let value: Expr = meta.value()?.parse()?;
50 if let Expr::Path(p) = value {
51 deser_with = Some(p.path);
52 }
53 } else if meta.path.is_ident("default") {
54 let value: Expr = meta.value()?.parse()?;
55 default_expr = Some(value);
56 }
57 Ok(())
58 });
59 }
60 }
61 (deser_with, default_expr)
62 }
63
64 struct F {
66 name: syn::Ident,
67 ty: syn::Type,
68 deser_with: Option<Path>,
69 default_expr: Option<Expr>,
70 }
71 let mut fdefs = Vec::new();
72 for f in fields {
73 let name = f.ident.unwrap();
74 let ty = f.ty;
75 let (deser_with, default_expr) = parse_field_attrs(&f.attrs);
76 fdefs.push(F {
77 name,
78 ty,
79 deser_with,
80 default_expr,
81 });
82 }
83
84 let temps: Vec<_> = fdefs
86 .iter()
87 .map(|f| format_ident!("__tmp_{}", f.name))
88 .collect();
89
90 let reads = fdefs.iter().zip(&temps).map(|(f, tmp)| {
95 let ty = &f.ty;
96 let fallback = f
97 .default_expr
98 .as_ref()
99 .map(|e| quote!(#e))
100 .unwrap_or_else(|| quote!(<#ty as ::core::default::Default>::default()));
101
102 if let Some(dw) = &f.deser_with {
103 quote! {
104 let before_len = data.len();
105 let #tmp: #ty = match (#dw)(&mut data) {
106 Ok(v) => v,
107 Err(e_any) => {
108 let after_len = data.len();
109 if after_len == before_len {
110 #fallback
111 } else {
112 let e: ::std::io::Error = ::core::convert::Into::into(e_any);
113 return Err(<#error_ty as ::core::convert::From<::std::io::Error>>::from(e));
114 }
115 }
116 };
117 }
118 } else {
119 quote! {
120 let before_len = data.len();
121 let #tmp: #ty = match <#ty as ::borsh::BorshDeserialize>::deserialize(&mut data) {
122 Ok(v) => v,
123 Err(e) => {
124 let after_len = data.len();
125 if after_len == before_len {
126 #fallback
127 } else {
128 return Err(<#error_ty as ::core::convert::From<::std::io::Error>>::from(e));
129 }
130 }
131 };
132 }
133 }
134 });
135
136 let assigns = fdefs.iter().zip(&temps).map(|(f, tmp)| {
138 let name = &f.name;
139 quote!(#name: #tmp)
140 });
141
142 let expanded = quote! {
144 impl #impl_g ::core::convert::TryFrom<&[u8]> for #ident #ty_g #where_c {
145 type Error = #error_ty;
146 fn try_from(mut data: &[u8]) -> ::core::result::Result<Self, Self::Error> {
147 #( #reads )*
148 Ok(Self { #( #assigns ),* })
149 }
150 }
151 };
152
153 TokenStream::from(expanded)
154}