/home/runner/actions-runner/_work/fuel-vm/fuel-vm/fuel-derive/src/serialize.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use proc_macro2::TokenStream as TokenStream2; |
2 | | use quote::quote; |
3 | | |
4 | | use crate::attribute::{ |
5 | | should_skip_field_binding, |
6 | | StructAttrs, |
7 | | }; |
8 | | |
9 | 68 | fn serialize_struct(s: &synstructure::Structure) -> TokenStream2 { |
10 | 68 | let attrs = StructAttrs::parse(s); |
11 | 68 | let mut s = s.clone(); |
12 | 68 | |
13 | 68 | assert_eq!(s.variants().len(), 1, "structs must have one variant"0 ); |
14 | | |
15 | 68 | let variant: &mut synstructure::VariantInfo = &mut s.variants_mut()[0]; |
16 | 182 | variant.filter(|binding| !should_skip_field_binding(binding)); |
17 | 68 | |
18 | 178 | let encode_static = variant.each(|binding| { |
19 | 178 | quote! { |
20 | 178 | ::fuel_types::canonical::Serialize::encode_static(#binding, buffer)?; |
21 | 178 | } |
22 | 178 | }); |
23 | 68 | |
24 | 178 | let encode_dynamic = variant.each(|binding| { |
25 | 178 | quote! { |
26 | 178 | ::fuel_types::canonical::Serialize::encode_dynamic(#binding, buffer)?; |
27 | 178 | } |
28 | 178 | }); |
29 | 68 | |
30 | 178 | let size_static_code = variant.each(|binding| { |
31 | 178 | quote! { |
32 | 178 | size = size.saturating_add(#binding.size_static()); |
33 | 178 | } |
34 | 178 | })68 ; |
35 | | |
36 | 68 | let initial_size = if attrs.prefix.is_some() { Branch (36:27): [Folded - Ignored]
Branch (36:27): [True: 12, False: 56]
|
37 | 12 | quote! { let mut size = 8usize; } |
38 | | } else { |
39 | 56 | quote! { let mut size = 0usize; } |
40 | | }; |
41 | 68 | let size_static_code = quote! { #initial_size match self { #size_static_code}; size }; |
42 | 68 | |
43 | 178 | let size_dynamic_code = variant.each(|binding| { |
44 | 178 | quote! { |
45 | 178 | size = size.saturating_add(#binding.size_dynamic()); |
46 | 178 | } |
47 | 178 | }); |
48 | 68 | let size_dynamic_code = |
49 | 68 | quote! { let mut size = 0usize; match self { #size_dynamic_code}; size }; |
50 | | |
51 | 68 | let prefix = if let Some(prefix_type12 ) = attrs.prefix.as_ref() { Branch (51:25): [Folded - Ignored]
Branch (51:25): [True: 12, False: 56]
|
52 | 12 | quote! { |
53 | 12 | <_ as ::fuel_types::canonical::Serialize>::encode(&#prefix_type, buffer)?; |
54 | 12 | } |
55 | | } else { |
56 | 56 | quote! {} |
57 | | }; |
58 | | |
59 | 68 | s.gen_impl(quote! { |
60 | 68 | gen impl ::fuel_types::canonical::Serialize for @Self { |
61 | 68 | #[inline(always)] |
62 | 68 | fn size_static(&self) -> usize { |
63 | 68 | #size_static_code |
64 | 68 | } |
65 | 68 | |
66 | 68 | #[inline(always)] |
67 | 68 | fn size_dynamic(&self) -> usize { |
68 | 68 | #size_dynamic_code |
69 | 68 | } |
70 | 68 | |
71 | 68 | #[inline(always)] |
72 | 68 | fn encode_static<O: ::fuel_types::canonical::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), ::fuel_types::canonical::Error> { |
73 | 68 | #prefix |
74 | 68 | match self { |
75 | 68 | #encode_static |
76 | 68 | }; |
77 | 68 | |
78 | 68 | ::core::result::Result::Ok(()) |
79 | 68 | } |
80 | 68 | |
81 | 68 | fn encode_dynamic<O: ::fuel_types::canonical::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), ::fuel_types::canonical::Error> { |
82 | 68 | match self { |
83 | 68 | #encode_dynamic |
84 | 68 | }; |
85 | 68 | |
86 | 68 | ::core::result::Result::Ok(()) |
87 | 68 | } |
88 | 68 | } |
89 | 68 | }) |
90 | 68 | } |
91 | | |
92 | 16 | fn serialize_enum(s: &synstructure::Structure) -> TokenStream2 { |
93 | 16 | assert!(!s.variants().is_empty(), "got invalid empty enum"0 ); |
94 | 16 | let mut s = s.clone(); |
95 | 16 | let mut next_discriminant = quote! { { 0u64 } }; |
96 | 16 | |
97 | 179 | s.variants_mut().iter_mut().for_each(|v| { |
98 | 187 | v.filter(|binding| !should_skip_field_binding(binding)); |
99 | 179 | }); |
100 | 16 | |
101 | 179 | let encode_static = s.variants().iter().map(|v| { |
102 | 179 | let pat = v.pat(); |
103 | 179 | |
104 | 179 | let encode_static_iter = v.bindings().iter().map(|binding| { |
105 | 179 | quote! { |
106 | 179 | ::fuel_types::canonical::Serialize::encode_static(#binding, buffer)?; |
107 | 179 | } |
108 | 179 | }); |
109 | 179 | |
110 | 179 | if v.ast().discriminant.is_some() { Branch (110:12): [Folded - Ignored]
Branch (110:12): [True: 125, False: 54]
|
111 | 125 | let variant_ident = v.ast().ident; |
112 | 125 | next_discriminant = quote! { { Self::#variant_ident as u64 } }; |
113 | 125 | }54 |
114 | | |
115 | 179 | let encode_discriminant = quote! { |
116 | 179 | <::core::primitive::u64 as ::fuel_types::canonical::Serialize>::encode(&#next_discriminant, buffer)?; |
117 | 179 | }; |
118 | 179 | next_discriminant = quote! { ( (#next_discriminant) + 1u64 ) }; |
119 | 179 | |
120 | 179 | quote! { |
121 | 179 | #pat => { |
122 | 179 | #encode_discriminant |
123 | 179 | #( |
124 | 179 | { #encode_static_iter } |
125 | 179 | )* |
126 | 179 | } |
127 | 179 | } |
128 | 179 | }); |
129 | 179 | let encode_dynamic = s.variants().iter().map(|v| { |
130 | 179 | let encode_dynamic_iter = v.each(|binding| { |
131 | 179 | quote! { |
132 | 179 | ::fuel_types::canonical::Serialize::encode_dynamic(#binding, buffer)?; |
133 | 179 | } |
134 | 179 | }); |
135 | 179 | quote! { |
136 | 179 | #encode_dynamic_iter |
137 | 179 | } |
138 | 179 | }); |
139 | 16 | |
140 | 16 | let match_size_static: TokenStream2 = s |
141 | 16 | .variants() |
142 | 16 | .iter() |
143 | 179 | .map(|variant| { |
144 | 179 | variant.each(|binding| { |
145 | 179 | quote! { |
146 | 179 | size = size.saturating_add(#binding.size_static()); |
147 | 179 | } |
148 | 179 | }) |
149 | 179 | }) |
150 | 16 | .collect(); |
151 | 16 | let match_size_static = quote! {{ |
152 | 16 | // `repr(128)` is unstable, so because of that we can use 8 bytes. |
153 | 16 | let mut size = 8usize; |
154 | 16 | match self { #match_size_static } size } |
155 | 16 | }; |
156 | 16 | |
157 | 16 | let match_size_dynamic: TokenStream2 = s |
158 | 16 | .variants() |
159 | 16 | .iter() |
160 | 179 | .map(|variant| { |
161 | 179 | variant.each(|binding| { |
162 | 179 | quote! { |
163 | 179 | size = size.saturating_add(#binding.size_dynamic()); |
164 | 179 | } |
165 | 179 | }) |
166 | 179 | }) |
167 | 16 | .collect(); |
168 | 16 | let match_size_dynamic = |
169 | 16 | quote! {{ let mut size = 0usize; match self { #match_size_dynamic } size }}; |
170 | | |
171 | 16 | let impl_code = s.gen_impl(quote! { |
172 | 16 | gen impl ::fuel_types::canonical::Serialize for @Self { |
173 | 16 | #[inline(always)] |
174 | 16 | fn size_static(&self) -> usize { |
175 | 16 | #match_size_static |
176 | 16 | } |
177 | 16 | |
178 | 16 | #[inline(always)] |
179 | 16 | fn size_dynamic(&self) -> usize { |
180 | 16 | #match_size_dynamic |
181 | 16 | } |
182 | 16 | |
183 | 16 | #[inline(always)] |
184 | 16 | fn encode_static<O: ::fuel_types::canonical::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), ::fuel_types::canonical::Error> { |
185 | 16 | match self { |
186 | 16 | #( |
187 | 16 | #encode_static |
188 | 16 | )*, |
189 | 16 | _ => return ::core::result::Result::Err(::fuel_types::canonical::Error::UnknownDiscriminant), |
190 | 16 | }; |
191 | 16 | |
192 | 16 | ::core::result::Result::Ok(()) |
193 | 16 | } |
194 | 16 | |
195 | 16 | fn encode_dynamic<O: ::fuel_types::canonical::Output + ?Sized>(&self, buffer: &mut O) -> ::core::result::Result<(), ::fuel_types::canonical::Error> { |
196 | 16 | match self { |
197 | 16 | #( |
198 | 16 | #encode_dynamic |
199 | 16 | )*, |
200 | 16 | _ => return ::core::result::Result::Err(::fuel_types::canonical::Error::UnknownDiscriminant), |
201 | 16 | }; |
202 | 16 | |
203 | 16 | ::core::result::Result::Ok(()) |
204 | 16 | } |
205 | 16 | } |
206 | 16 | }); |
207 | | |
208 | 16 | quote! { |
209 | 16 | #impl_code |
210 | 16 | } |
211 | 16 | } |
212 | | |
213 | | /// Derives `Serialize` trait for the given `struct` or `enum`. |
214 | 84 | pub fn serialize_derive(mut s: synstructure::Structure) -> TokenStream2 { |
215 | 84 | s.add_bounds(synstructure::AddBounds::Fields) |
216 | 84 | .underscore_const(true); |
217 | 84 | |
218 | 84 | match s.ast().data { |
219 | 68 | syn::Data::Struct(_) => serialize_struct(&s), |
220 | 16 | syn::Data::Enum(_) => serialize_enum(&s), |
221 | 0 | _ => panic!("Can't derive `Serialize` for `union`s"), |
222 | | } |
223 | 84 | } |