borsh_derive_internal/
struct_ser.rs1use core::convert::TryFrom;
2
3use proc_macro2::{Span, TokenStream as TokenStream2};
4use quote::quote;
5use syn::{Fields, Ident, Index, ItemStruct, WhereClause};
6
7use crate::attribute_helpers::contains_skip;
8
9pub fn struct_ser(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStream2> {
10 let name = &input.ident;
11 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
12 let mut where_clause = where_clause.map_or_else(
13 || WhereClause {
14 where_token: Default::default(),
15 predicates: Default::default(),
16 },
17 Clone::clone,
18 );
19 let mut body = TokenStream2::new();
20 match &input.fields {
21 Fields::Named(fields) => {
22 for field in &fields.named {
23 if contains_skip(&field.attrs) {
24 continue;
25 }
26 let field_name = field.ident.as_ref().unwrap();
27 let delta = quote! {
28 #cratename::BorshSerialize::serialize(&self.#field_name, writer)?;
29 };
30 body.extend(delta);
31
32 let field_type = &field.ty;
33 where_clause.predicates.push(
34 syn::parse2(quote! {
35 #field_type: #cratename::ser::BorshSerialize
36 })
37 .unwrap(),
38 );
39 }
40 }
41 Fields::Unnamed(fields) => {
42 for field_idx in 0..fields.unnamed.len() {
43 let field_idx = Index {
44 index: u32::try_from(field_idx).expect("up to 2^32 fields are supported"),
45 span: Span::call_site(),
46 };
47 let delta = quote! {
48 #cratename::BorshSerialize::serialize(&self.#field_idx, writer)?;
49 };
50 body.extend(delta);
51 }
52 }
53 Fields::Unit => {}
54 }
55 Ok(quote! {
56 impl #impl_generics #cratename::ser::BorshSerialize for #name #ty_generics #where_clause {
57 fn serialize<W: #cratename::maybestd::io::Write>(&self, writer: &mut W) -> ::core::result::Result<(), #cratename::maybestd::io::Error> {
58 #body
59 Ok(())
60 }
61 }
62 })
63}
64
65#[rustfmt::skip]
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 fn assert_eq(expected: TokenStream2, actual: TokenStream2) {
72 assert_eq!(expected.to_string(), actual.to_string())
73 }
74
75 #[test]
76 fn simple_struct() {
77 let item_struct: ItemStruct = syn::parse2(quote!{
78 struct A {
79 x: u64,
80 y: String,
81 }
82 }).unwrap();
83
84 let actual = struct_ser(&item_struct, Ident::new("borsh", Span::call_site())).unwrap();
85 let expected = quote!{
86 impl borsh::ser::BorshSerialize for A
87 where
88 u64: borsh::ser::BorshSerialize,
89 String: borsh::ser::BorshSerialize
90 {
91 fn serialize<W: borsh::maybestd::io::Write>(&self, writer: &mut W) -> ::core::result::Result<(), borsh::maybestd::io::Error> {
92 borsh::BorshSerialize::serialize(&self.x, writer)?;
93 borsh::BorshSerialize::serialize(&self.y, writer)?;
94 Ok(())
95 }
96 }
97 };
98 assert_eq(expected, actual);
99 }
100
101 #[test]
102 fn simple_generics() {
103 let item_struct: ItemStruct = syn::parse2(quote!{
104 struct A<K, V> {
105 x: HashMap<K, V>,
106 y: String,
107 }
108 }).unwrap();
109
110 let actual = struct_ser(&item_struct, Ident::new("borsh", Span::call_site())).unwrap();
111 let expected = quote!{
112 impl<K, V> borsh::ser::BorshSerialize for A<K, V>
113 where
114 HashMap<K, V>: borsh::ser::BorshSerialize,
115 String: borsh::ser::BorshSerialize
116 {
117 fn serialize<W: borsh::maybestd::io::Write>(&self, writer: &mut W) -> ::core::result::Result<(), borsh::maybestd::io::Error> {
118 borsh::BorshSerialize::serialize(&self.x, writer)?;
119 borsh::BorshSerialize::serialize(&self.y, writer)?;
120 Ok(())
121 }
122 }
123 };
124 assert_eq(expected, actual);
125 }
126
127 #[test]
128 fn bound_generics() {
129 let item_struct: ItemStruct = syn::parse2(quote!{
130 struct A<K: Key, V> where V: Value {
131 x: HashMap<K, V>,
132 y: String,
133 }
134 }).unwrap();
135
136 let actual = struct_ser(&item_struct, Ident::new("borsh", Span::call_site())).unwrap();
137 let expected = quote!{
138 impl<K: Key, V> borsh::ser::BorshSerialize for A<K, V>
139 where
140 V: Value,
141 HashMap<K, V>: borsh::ser::BorshSerialize,
142 String: borsh::ser::BorshSerialize
143 {
144 fn serialize<W: borsh::maybestd::io::Write>(&self, writer: &mut W) -> ::core::result::Result<(), borsh::maybestd::io::Error> {
145 borsh::BorshSerialize::serialize(&self.x, writer)?;
146 borsh::BorshSerialize::serialize(&self.y, writer)?;
147 Ok(())
148 }
149 }
150 };
151 assert_eq(expected, actual);
152 }
153}