bincode_trait_derive/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{
4 Data, DeriveInput, Fields, GenericParam, Ident, Lifetime, LifetimeParam, Path, PathArguments,
5 Type, TypeParam, TypePath, WherePredicate, parse_macro_input, spanned::Spanned,
6};
7
8#[proc_macro_derive(Encode)]
9pub fn encode_derive(input: TokenStream) -> TokenStream {
10 let input = parse_macro_input!(input as DeriveInput);
11 let struct_name = input.ident;
12
13 let mut generics_for_impl = input.generics.clone();
14 let mut where_clause_for_impl = generics_for_impl.make_where_clause().clone();
15
16 for param in input.generics.params.iter() {
18 if let GenericParam::Type(type_param) = param {
19 let type_ident = &type_param.ident;
20 let type_path = Type::Path(TypePath {
21 qself: None,
22 path: type_ident.clone().into(),
23 });
24 let predicate: WherePredicate = syn::parse_quote! {
25 #type_path: ::bincode::Encode
26 };
27 where_clause_for_impl.predicates.push(predicate);
28 }
29 }
30
31 let field_types = match &input.data {
33 Data::Struct(data_struct) => data_struct.fields.iter().map(|f| &f.ty).collect::<Vec<_>>(),
34 Data::Enum(data_enum) => data_enum
35 .variants
36 .iter()
37 .flat_map(|variant| variant.fields.iter().map(|f| &f.ty))
38 .collect::<Vec<_>>(),
39 Data::Union(_) => vec![],
40 };
41
42 for ty in field_types {
44 if let Type::Path(type_path) = ty {
45 if type_path.path.segments.len() > 1 {
47 let predicate: WherePredicate = syn::parse_quote! {
48 #ty: ::bincode::Encode
49 };
50 where_clause_for_impl.predicates.push(predicate);
51 }
52
53 if !type_path.path.segments.is_empty() {
55 for segment in &type_path.path.segments {
56 if let PathArguments::AngleBracketed(args) = &segment.arguments {
57 for arg in &args.args {
58 if let syn::GenericArgument::Type(Type::Path(inner_type_path)) = arg {
59 if inner_type_path.path.segments.len() > 1 {
61 let inner_type = Type::Path(inner_type_path.clone());
62 let predicate: WherePredicate = syn::parse_quote! {
63 #inner_type: ::bincode::Encode
64 };
65 where_clause_for_impl.predicates.push(predicate);
66 }
67 }
68 }
69 }
70 }
71 }
72 }
73 }
74
75 let (impl_generics, _, _) = generics_for_impl.split_for_impl();
76 let (_, ty_generics, _) = input.generics.split_for_impl();
77
78 let encode_body = match &input.data {
79 Data::Struct(data_struct) => match &data_struct.fields {
80 Fields::Named(fields_named) => {
81 let encode_fields = fields_named.named.iter().map(|f| {
82 let ident = &f.ident;
83 quote! { ::bincode::Encode::encode(&self.#ident, encoder)?; }
84 });
85 quote! { #(#encode_fields)* Ok(()) }
86 }
87 Fields::Unnamed(fields_unnamed) => {
88 let encode_fields = fields_unnamed.unnamed.iter().enumerate().map(|(i, _)| {
89 let index = syn::Index::from(i);
90 quote! { ::bincode::Encode::encode(&self.#index, encoder)?; }
91 });
92 quote! { #(#encode_fields)* Ok(()) }
93 }
94 Fields::Unit => quote! { Ok(()) },
95 },
96 Data::Enum(data_enum) => {
97 let variant_arms = data_enum.variants.iter().enumerate().map(|(idx, variant)| {
98 let variant_ident = &variant.ident;
99 let discriminant = proc_macro2::Literal::usize_suffixed(idx);
100 match &variant.fields {
101 Fields::Named(fields_named) => {
102 let field_pats = fields_named.named.iter().map(|f| &f.ident);
103 let field_encodes = fields_named.named.iter().map(|f| {
104 let ident = &f.ident;
105 quote! { ::bincode::Encode::encode(#ident, encoder)?; }
106 });
107 quote! {
108 Self::#variant_ident { #(#field_pats),* } => {
109 ::bincode::Encode::encode(&#discriminant, encoder)?;
110 #(#field_encodes)*
111 Ok(())
112 }
113 }
114 }
115 Fields::Unnamed(fields_unnamed) => {
116 let field_pats_bindings = fields_unnamed
117 .unnamed
118 .iter()
119 .enumerate()
120 .map(|(i, field)| Ident::new(&format!("field{}", i), field.span()));
121 let field_pats = field_pats_bindings.clone();
122 let field_encodes = field_pats_bindings.map(|binding| {
123 quote! { ::bincode::Encode::encode(#binding, encoder)?; }
124 });
125 quote! {
126 Self::#variant_ident ( #(#field_pats),* ) => {
127 ::bincode::Encode::encode(&#discriminant, encoder)?;
128 #(#field_encodes)*
129 Ok(())
130 }
131 }
132 }
133 Fields::Unit => {
134 quote! {
135 Self::#variant_ident => {
136 ::bincode::Encode::encode(&#discriminant, encoder)?;
137 Ok(())
138 }
139 }
140 }
141 }
142 });
143 quote! {
144 match self {
145 #(#variant_arms)*
146 }
147 }
148 }
149 Data::Union(_) => unimplemented!("Unions are not supported by Encode derive"),
150 };
151
152 let expanded = quote! {
153 impl #impl_generics ::bincode::Encode for #struct_name #ty_generics #where_clause_for_impl {
154 fn encode<__E: ::bincode::enc::Encoder>(&self, encoder: &mut __E) -> std::result::Result<(), ::bincode::error::EncodeError> {
155 #encode_body
156 }
157 }
158 };
159
160 TokenStream::from(expanded)
161}
162
163#[proc_macro_derive(Decode, attributes(trait_decode))]
164pub fn trait_derive(input: TokenStream) -> TokenStream {
165 let mut input_ast = parse_macro_input!(input as DeriveInput);
166 let struct_name = &input_ast.ident;
167
168 let mut option_trait_name: Option<Path> = None;
169 let mut option_context_type_name: Option<Path> = None;
170
171 for attr in input_ast
172 .attrs
173 .iter()
174 .filter(|a| a.path().is_ident("trait_decode"))
175 {
176 if let Err(e) = attr.parse_nested_meta(|meta| {
177 if meta.path.is_ident("trait") {
178 if option_context_type_name.is_some() {
179 return Err(meta.error("cannot specify both `trait` and `context_type` in #[trait_decode]"));
180 }
181 option_trait_name = Some(meta.value()?.parse::<Path>()?);
182 Ok(())
183 } else if meta.path.is_ident("context_type") {
184 if option_trait_name.is_some() {
185 return Err(meta.error("cannot specify both `trait` and `context_type` in #[trait_decode]"));
186 }
187 option_context_type_name = Some(meta.value()?.parse::<Path>()?);
188 Ok(())
189 } else {
190 Err(meta.error("unrecognized key for #[trait_decode] attribute, supported keys are `trait` and `context_type`"))
191 }
192 }) {
193 return e.to_compile_error().into();
194 }
195 }
196
197 let mut generics_for_impl = input_ast.generics.clone();
198 let mut where_clause_for_impl = input_ast.generics.make_where_clause().clone();
199
200 let context_generic_ident = Ident::new("__Context", proc_macro2::Span::call_site());
202
203 if option_context_type_name.is_none() {
205 let context_generic_param_for_impl =
206 GenericParam::Type(TypeParam::from(context_generic_ident.clone()));
207
208 generics_for_impl
209 .params
210 .push(context_generic_param_for_impl);
211 }
212
213 if let Some(ref trait_ident_path) = option_trait_name {
214 let pred: WherePredicate = syn::parse_quote! { #context_generic_ident: #trait_ident_path };
215 where_clause_for_impl.predicates.push(pred);
216 } else if let Some(ref _concrete_type_path) = option_context_type_name {
217 } else {
221 }
224
225 for param in input_ast.generics.params.iter() {
227 if let GenericParam::Type(type_param) = param {
228 let type_ident = &type_param.ident;
229 let type_path = Type::Path(TypePath {
230 qself: None,
231 path: type_ident.clone().into(),
232 });
233 let predicate: WherePredicate = syn::parse_quote! {
234 #type_path: ::bincode::Decode<#context_generic_ident>
235 };
236 where_clause_for_impl.predicates.push(predicate);
237 }
238 }
239
240 let context_type = if let Some(ref concrete_type_path) = option_context_type_name {
242 quote! { #concrete_type_path }
244 } else {
245 quote! { #context_generic_ident }
247 };
248
249 let (impl_generics, _, _) = generics_for_impl.split_for_impl(); let (_, ty_generics_for_struct, _) = input_ast.generics.split_for_impl(); let decode_body = match &input_ast.data {
253 Data::Struct(data_struct) => match &data_struct.fields {
254 Fields::Named(fields_named) => {
255 let decode_fields = fields_named.named.iter().map(|f| {
256 let ident = &f.ident;
257 quote! { #ident: ::bincode::Decode::decode(decoder)? }
258 });
259 quote! { Ok(Self { #(#decode_fields),* }) }
260 }
261 Fields::Unnamed(fields_unnamed) => {
262 let decode_fields = fields_unnamed.unnamed.iter().map(|_| {
263 quote! { ::bincode::Decode::decode(decoder)? }
264 });
265 quote! { Ok(Self(#(#decode_fields),*)) }
266 }
267 Fields::Unit => quote! { Ok(Self) },
268 },
269 Data::Enum(data_enum) => {
270 let num_variants = data_enum.variants.iter().count();
271
272 let variants = data_enum.variants.iter().enumerate().map(|(idx, variant)| {
273 let variant_ident = &variant.ident;
274 match &variant.fields {
275 Fields::Named(fields_named) => {
276 let decode_fields = fields_named.named.iter().map(|f| {
277 let ident = &f.ident;
278 quote! { #ident: ::bincode::Decode::decode(decoder)? }
279 });
280 quote! { #idx => Ok(Self::#variant_ident { #(#decode_fields),* }), }
281 }
282 Fields::Unnamed(fields_unnamed) => {
283 let decode_fields = fields_unnamed.unnamed.iter().map(|_| {
284 quote! { ::bincode::Decode::decode(decoder)? }
285 });
286 quote! { #idx => Ok(Self::#variant_ident(#(#decode_fields),*)), }
287 }
288 Fields::Unit => quote! { #idx => Ok(Self::#variant_ident), },
289 }
290 });
291 quote! {
292 let discriminant: usize = ::bincode::Decode::decode(decoder)?;
293 match discriminant {
294 #(#variants)*
295 _other => Err(::bincode::error::DecodeError::UnexpectedVariant {
296 type_name: stringify!(#struct_name),
297 found: _other as u32,
298 allowed: &bincode::error::AllowedEnumVariants::Range {
299 min: 0u32,
300 max: (#num_variants - 1) as u32,
301 },
302 }),
303 }
304 }
305 }
306 Data::Union(_) => unimplemented!("Unions are not supported by Decode derive"),
307 };
308
309 let expanded = quote! {
310 impl #impl_generics ::bincode::Decode<#context_type> for #struct_name #ty_generics_for_struct #where_clause_for_impl {
311 fn decode<D: ::bincode::de::Decoder<Context = #context_type>>(decoder: &mut D) -> std::result::Result<Self, ::bincode::error::DecodeError> {
312 #decode_body
313 }
314 }
315 };
316
317 TokenStream::from(expanded)
318}
319
320#[proc_macro_derive(BorrowDecodeFromDecode, attributes(trait_decode))]
321pub fn borrow_decode_from_trait_decode(input: TokenStream) -> TokenStream {
322 let mut input_ast = parse_macro_input!(input as DeriveInput);
323 let struct_name = &input_ast.ident;
324
325 let mut option_trait_name: Option<Path> = None;
326 let mut option_context_type_name: Option<Path> = None;
327
328 for attr in input_ast
329 .attrs
330 .iter()
331 .filter(|a| a.path().is_ident("trait_decode"))
332 {
333 if let Err(e) = attr.parse_nested_meta(|meta| {
334 if meta.path.is_ident("trait") {
335 if option_context_type_name.is_some() {
336 return Err(meta.error("cannot specify both `trait` and `context_type` in #[trait_decode]"));
337 }
338 option_trait_name = Some(meta.value()?.parse::<Path>()?);
339 Ok(())
340 } else if meta.path.is_ident("context_type") {
341 if option_trait_name.is_some() {
342 return Err(meta.error("cannot specify both `trait` and `context_type` in #[trait_decode]"));
343 }
344 option_context_type_name = Some(meta.value()?.parse::<Path>()?);
345 Ok(())
346 } else {
347 Err(meta.error("unrecognized key for #[trait_decode] attribute, supported keys are `trait` and `context_type`"))
348 }
349 }) {
350 return e.to_compile_error().into();
351 }
352 }
353
354 let mut generics_for_impl = input_ast.generics.clone();
355 let mut where_clause_for_impl = input_ast.generics.make_where_clause().clone();
356
357 let lifetime_de_ident = Lifetime::new("'_de", proc_macro2::Span::call_site());
358 let lifetime_de_param = GenericParam::Lifetime(LifetimeParam::new(lifetime_de_ident.clone()));
359 generics_for_impl.params.push(lifetime_de_param);
360
361 let context_ident = Ident::new("__Context", proc_macro2::Span::call_site());
363
364 if option_context_type_name.is_none() {
366 let context_generic_param_for_impl =
367 GenericParam::Type(TypeParam::from(context_ident.clone()));
368 generics_for_impl
369 .params
370 .push(context_generic_param_for_impl);
371 }
372
373 if let Some(ref trait_ident_path) = option_trait_name {
374 let pred: WherePredicate = syn::parse_quote! { #context_ident: #trait_ident_path };
375 where_clause_for_impl.predicates.push(pred);
376 } else if let Some(ref _concrete_type_path) = option_context_type_name {
377 } else {
381 }
383
384 for param in input_ast.generics.params.iter() {
387 if let GenericParam::Type(type_param) = param {
388 let type_ident = &type_param.ident;
389 let type_path = Type::Path(TypePath {
390 qself: None,
391 path: type_ident.clone().into(),
392 });
393 let predicate: WherePredicate = syn::parse_quote! {
394 #type_path: ::bincode::Decode<#context_ident>
395 };
396 where_clause_for_impl.predicates.push(predicate);
397 }
398 }
399
400 let context_type = if let Some(ref concrete_type_path) = option_context_type_name {
406 quote! { #concrete_type_path }
408 } else {
409 quote! { #context_ident }
411 };
412
413 let (impl_generics, _, _) = generics_for_impl.split_for_impl(); let (_, ty_generics_for_struct, _) = input_ast.generics.split_for_impl(); let expanded = quote! {
417 impl #impl_generics ::bincode::BorrowDecode<#lifetime_de_ident, #context_type> for #struct_name #ty_generics_for_struct #where_clause_for_impl {
418 fn borrow_decode<D: ::bincode::de::BorrowDecoder<#lifetime_de_ident, Context = #context_type>>(decoder: &mut D) -> std::result::Result<Self, ::bincode::error::DecodeError> {
419 <Self as ::bincode::Decode<#context_type>>::decode(decoder)
420 }
421 }
422 };
423
424 TokenStream::from(expanded)
425}