1#![crate_type = "proc-macro"]
2extern crate proc_macro;
3
4use proc_macro::TokenStream;
5use proc_macro2::TokenStream as TokenStream2;
6use quote::{format_ident, quote};
7use syn::{
8 parse_macro_input, Data, DataEnum, DataStruct, DeriveInput, Field, Fields, FieldsNamed,
9 FieldsUnnamed, GenericArgument, Generics, Ident, Meta, PathArguments, Type,
10};
11
12fn has_attr(field: &Field, name: &str) -> bool {
13 field.attrs.iter().any(|attr| {
14 let Meta::List(list) = &attr.meta else {
15 return false;
16 };
17 list.path.is_ident("msgpacker")
18 && list
19 .tokens
20 .clone()
21 .into_iter()
22 .any(|t| t.to_string() == name)
23 })
24}
25
26fn is_slice_of_u8(ty: &Type) -> bool {
27 let Type::Reference(r) = ty else { return false };
28 let Type::Slice(s) = r.elem.as_ref() else {
29 return false;
30 };
31 let Type::Path(p) = s.elem.as_ref() else {
32 return false;
33 };
34 p.path.segments.last().is_some_and(|s| s.ident == "u8")
35}
36
37fn is_vec_of_u8(ty: &Type) -> bool {
38 let Type::Path(p) = ty else { return false };
39 let Some(last) = p.path.segments.last() else {
40 return false;
41 };
42 if last.ident != "Vec" {
43 return false;
44 }
45 let PathArguments::AngleBracketed(args) = &last.arguments else {
46 return false;
47 };
48 if args.args.len() != 1 {
49 return false;
50 }
51 let Some(GenericArgument::Type(Type::Path(inner))) = args.args.first() else {
52 return false;
53 };
54 inner.path.segments.last().is_some_and(|s| s.ident == "u8")
55}
56
57fn is_option_type(ty: &Type) -> bool {
58 let Type::Path(p) = ty else { return false };
59 let Some(last) = p.path.segments.last() else {
60 return false;
61 };
62 last.ident == "Option"
63 && matches!(&last.arguments, PathArguments::AngleBracketed(args) if args.args.len() == 1)
64}
65
66fn is_vec_of_non_u8(ty: &Type) -> bool {
67 if is_vec_of_u8(ty) {
68 return false;
69 }
70 let Type::Path(p) = ty else { return false };
71 let Some(last) = p.path.segments.last() else {
72 return false;
73 };
74 if last.ident != "Vec" {
75 return false;
76 }
77 let PathArguments::AngleBracketed(args) = &last.arguments else {
78 return false;
79 };
80 args.args.len() == 1
81}
82
83fn binary_named_stmts(ident: &Ident, ty: &Type) -> (TokenStream2, TokenStream2, TokenStream2) {
88 if is_option_type(ty) {
89 (
90 quote! {
91 n += ::msgpacker::pack_bytes_option(
92 buf,
93 self.#ident.as_ref().map(::core::convert::AsRef::as_ref),
94 );
95 },
96 quote! {
97 let #ident = ::msgpacker::unpack_bytes_option(buf).map(|(nv, t)| {
98 n += nv;
99 buf = &buf[nv..];
100 t.map(::core::convert::From::from)
101 })?;
102 },
103 quote! {
104 let #ident = ::msgpacker::unpack_bytes_option_iter(bytes.by_ref()).map(|(nv, t)| {
105 n += nv;
106 t.map(::core::convert::From::from)
107 })?;
108 },
109 )
110 } else {
111 (
112 quote! {
113 n += ::msgpacker::pack_bytes(buf, ::core::convert::AsRef::<[u8]>::as_ref(&self.#ident));
114 },
115 quote! {
116 let #ident = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
117 n += nv;
118 buf = &buf[nv..];
119 ::core::convert::From::from(<[u8]>::to_vec(t))
120 })?;
121 },
122 quote! {
123 let #ident = ::msgpacker::unpack_bytes_iter(bytes.by_ref()).map(|(nv, t)| {
124 n += nv;
125 ::core::convert::From::from(t)
126 })?;
127 },
128 )
129 }
130}
131
132fn binary_named_unpack_borrowed(ident: &Ident, ty: &Type) -> TokenStream2 {
134 if is_option_type(ty) {
135 quote! {
136 let #ident = ::msgpacker::unpack_bytes_option_ref(buf).map(|(nv, t)| {
137 n += nv;
138 buf = &buf[nv..];
139 t.map(::core::convert::From::from)
140 })?;
141 }
142 } else {
143 quote! {
144 let #ident = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
145 n += nv;
146 buf = &buf[nv..];
147 ::core::convert::From::from(t)
148 })?;
149 }
150 }
151}
152
153fn emit_struct_impls(
156 name: &Ident,
157 generics: &Generics,
158 pack_stmts: &[TokenStream2],
159 unpack_stmts: &[TokenStream2],
160 unpack_iter_stmts: &[TokenStream2],
161 construct: TokenStream2,
162) -> TokenStream2 {
163 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
164 quote! {
165 impl #impl_generics ::msgpacker::Packable for #name #ty_generics #where_clause {
166 fn pack<T>(&self, buf: &mut T) -> usize
167 where
168 T: ::msgpacker::BufMut,
169 {
170 use ::msgpacker::Packable as _;
171 let mut n = 0usize;
172 #(#pack_stmts)*
173 n
174 }
175 }
176
177 impl #impl_generics ::msgpacker::Unpackable for #name #ty_generics #where_clause {
178 type Error = ::msgpacker::Error;
179
180 fn unpack_with_ofs(mut buf: &[u8]) -> Result<(usize, Self), Self::Error> {
181 let mut n = 0usize;
182 #(#unpack_stmts)*
183 Ok((n, #construct))
184 }
185
186 fn unpack_iter<I>(bytes: I) -> Result<(usize, Self), Self::Error>
187 where
188 I: IntoIterator<Item = u8>,
189 {
190 let mut bytes = bytes.into_iter();
191 let mut n = 0usize;
192 #(#unpack_iter_stmts)*
193 Ok((n, #construct))
194 }
195 }
196 }
197}
198
199fn named_field_stmts(ident: &Ident, field: &Field) -> (TokenStream2, TokenStream2, TokenStream2) {
200 let ty = &field.ty;
201
202 if has_attr(field, "binary") {
203 return binary_named_stmts(ident, ty);
204 }
205
206 if has_attr(field, "map") {
207 return (
208 quote! { n += ::msgpacker::pack_map(buf, &self.#ident); },
209 quote! {
210 let #ident = ::msgpacker::unpack_map(buf).map(|(nv, t)| {
211 n += nv;
212 buf = &buf[nv..];
213 t
214 })?;
215 },
216 quote! {
217 let #ident = ::msgpacker::unpack_map_iter(bytes.by_ref()).map(|(nv, t)| {
218 n += nv;
219 t
220 })?;
221 },
222 );
223 }
224
225 if has_attr(field, "array") || is_vec_of_non_u8(ty) {
226 return (
227 quote! { n += ::msgpacker::pack_array(buf, &self.#ident); },
228 quote! {
229 let #ident = ::msgpacker::unpack_array(buf).map(|(nv, t)| {
230 n += nv;
231 buf = &buf[nv..];
232 t
233 })?;
234 },
235 quote! {
236 let #ident = ::msgpacker::unpack_array_iter(bytes.by_ref()).map(|(nv, t)| {
237 n += nv;
238 t
239 })?;
240 },
241 );
242 }
243
244 if is_slice_of_u8(ty) {
245 return (
246 quote! { n += ::msgpacker::pack_bytes(buf, self.#ident); },
247 quote! {
248 let #ident = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
249 n += nv;
250 buf = &buf[nv..];
251 t
252 })?;
253 },
254 quote! {
255 let #ident = ::msgpacker::unpack_bytes_iter(bytes.by_ref()).map(|(nv, t)| {
256 n += nv;
257 t
258 })?;
259 },
260 );
261 }
262
263 if is_vec_of_u8(ty) {
264 return (
265 quote! { n += ::msgpacker::pack_bytes(buf, self.#ident.as_slice()); },
266 quote! {
267 let #ident = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
268 n += nv;
269 buf = &buf[nv..];
270 <[u8]>::to_vec(t)
271 })?;
272 },
273 quote! {
274 let #ident = ::msgpacker::unpack_bytes_iter(bytes.by_ref()).map(|(nv, t)| {
275 n += nv;
276 t
277 })?;
278 },
279 );
280 }
281
282 (
283 quote! { n += self.#ident.pack(buf); },
284 quote! {
285 let #ident = ::msgpacker::Unpackable::unpack_with_ofs(buf).map(|(nv, t)| {
286 n += nv;
287 buf = &buf[nv..];
288 t
289 })?;
290 },
291 quote! {
292 let #ident = ::msgpacker::Unpackable::unpack_iter(bytes.by_ref()).map(|(nv, t)| {
293 n += nv;
294 t
295 })?;
296 },
297 )
298}
299
300fn impl_struct_named(name: &Ident, f: FieldsNamed, generics: &Generics) -> TokenStream2 {
301 let mut pack_stmts = Vec::new();
302 let mut unpack_stmts = Vec::new();
303 let mut unpack_iter_stmts = Vec::new();
304 let mut field_names = Vec::new();
305
306 for field in f.named {
307 let ident = field.ident.as_ref().cloned().unwrap();
308 let (pack, unpack, unpack_iter) = named_field_stmts(&ident, &field);
309 pack_stmts.push(pack);
310 unpack_stmts.push(unpack);
311 unpack_iter_stmts.push(unpack_iter);
312 field_names.push(ident);
313 }
314
315 emit_struct_impls(
316 name,
317 generics,
318 &pack_stmts,
319 &unpack_stmts,
320 &unpack_iter_stmts,
321 quote! { Self { #(#field_names),* } },
322 )
323}
324
325fn impl_struct_unnamed(name: &Ident, f: FieldsUnnamed, generics: &Generics) -> TokenStream2 {
326 let mut pack_stmts = Vec::new();
327 let mut unpack_stmts = Vec::new();
328 let mut unpack_iter_stmts = Vec::new();
329 let mut var_names = Vec::new();
330
331 for (i, field) in f.unnamed.into_iter().enumerate() {
332 if has_attr(&field, "map") {
333 todo!("unnamed map is not implemented for derive macro; implement the traits manually");
334 }
335 if has_attr(&field, "array") {
336 todo!(
337 "unnamed array is not implemented for derive macro; implement the traits manually"
338 );
339 }
340
341 let var = format_ident!("v{}", i);
342 let index = syn::Index::from(i);
343
344 if has_attr(&field, "binary") {
345 if is_option_type(&field.ty) {
346 pack_stmts.push(quote! {
347 n += ::msgpacker::pack_bytes_option(
348 buf,
349 self.#index.as_ref().map(::core::convert::AsRef::as_ref),
350 );
351 });
352 unpack_stmts.push(quote! {
353 let #var = ::msgpacker::unpack_bytes_option(buf).map(|(nv, t)| {
354 n += nv;
355 buf = &buf[nv..];
356 t.map(::core::convert::From::from)
357 })?;
358 });
359 unpack_iter_stmts.push(quote! {
360 let #var = ::msgpacker::unpack_bytes_option_iter(bytes.by_ref()).map(|(nv, t)| {
361 n += nv;
362 t.map(::core::convert::From::from)
363 })?;
364 });
365 } else {
366 pack_stmts.push(quote! {
367 n += ::msgpacker::pack_bytes(buf, ::core::convert::AsRef::<[u8]>::as_ref(&self.#index));
368 });
369 unpack_stmts.push(quote! {
370 let #var = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
371 n += nv;
372 buf = &buf[nv..];
373 ::core::convert::From::from(<[u8]>::to_vec(t))
374 })?;
375 });
376 unpack_iter_stmts.push(quote! {
377 let #var = ::msgpacker::unpack_bytes_iter(bytes.by_ref()).map(|(nv, t)| {
378 n += nv;
379 ::core::convert::From::from(t)
380 })?;
381 });
382 }
383 var_names.push(var);
384 continue;
385 }
386
387 if is_vec_of_u8(&field.ty) {
388 pack_stmts.push(quote! { n += ::msgpacker::pack_bytes(buf, self.#index.as_slice()); });
389 unpack_stmts.push(quote! {
390 let #var = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
391 n += nv;
392 buf = &buf[nv..];
393 <[u8]>::to_vec(t)
394 })?;
395 });
396 unpack_iter_stmts.push(quote! {
397 let #var = ::msgpacker::unpack_bytes_iter(bytes.by_ref()).map(|(nv, t)| {
398 n += nv;
399 t
400 })?;
401 });
402 } else {
403 pack_stmts.push(quote! { n += self.#index.pack(buf); });
404 unpack_stmts.push(quote! {
405 let #var = ::msgpacker::Unpackable::unpack_with_ofs(buf).map(|(nv, t)| {
406 n += nv;
407 buf = &buf[nv..];
408 t
409 })?;
410 });
411 unpack_iter_stmts.push(quote! {
412 let #var = ::msgpacker::Unpackable::unpack_iter(bytes.by_ref()).map(|(nv, t)| {
413 n += nv;
414 t
415 })?;
416 });
417 }
418 var_names.push(var);
419 }
420
421 emit_struct_impls(
422 name,
423 generics,
424 &pack_stmts,
425 &unpack_stmts,
426 &unpack_iter_stmts,
427 quote! { Self(#(#var_names),*) },
428 )
429}
430
431fn impl_struct_unit(name: &Ident, generics: &Generics) -> TokenStream2 {
432 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
433 quote! {
434 impl #impl_generics ::msgpacker::Packable for #name #ty_generics #where_clause {
435 fn pack<T>(&self, _buf: &mut T) -> usize
436 where
437 T: ::msgpacker::BufMut,
438 {
439 0
440 }
441 }
442
443 impl #impl_generics ::msgpacker::Unpackable for #name #ty_generics #where_clause {
444 type Error = ::msgpacker::Error;
445
446 fn unpack_with_ofs(_buf: &[u8]) -> Result<(usize, Self), Self::Error> {
447 Ok((0, Self))
448 }
449
450 fn unpack_iter<I>(_bytes: I) -> Result<(usize, Self), Self::Error>
451 where
452 I: IntoIterator<Item = u8>,
453 {
454 Ok((0, Self))
455 }
456 }
457 }
458}
459
460fn impl_enum(name: &Ident, data: DataEnum, generics: &Generics) -> TokenStream2 {
461 if data.variants.is_empty() {
462 todo!("empty enum is not implemented for derive macro; implement the traits manually");
463 }
464
465 let mut pack_arms = Vec::new();
466 let mut unpack_arms = Vec::new();
467 let mut unpack_iter_arms = Vec::new();
468
469 for (i, variant) in data.variants.into_iter().enumerate() {
470 let discriminant = variant
471 .discriminant
472 .map(|(_, d)| d)
473 .unwrap_or_else(|| syn::parse_str(&i.to_string()).unwrap());
474 let variant_ident = &variant.ident;
475
476 match variant.fields {
477 Fields::Named(f) => {
478 let mut field_names = Vec::new();
479 let mut pack_field_stmts = Vec::new();
480 let mut unpack_field_stmts = Vec::new();
481 let mut unpack_iter_field_stmts = Vec::new();
482
483 for field in &f.named {
484 let ident = field.ident.as_ref().unwrap();
485 field_names.push(ident.clone());
486 if has_attr(field, "binary") {
487 if is_option_type(&field.ty) {
488 pack_field_stmts.push(quote! {
489 n += ::msgpacker::pack_bytes_option(
490 buf,
491 #ident.as_ref().map(::core::convert::AsRef::as_ref),
492 );
493 });
494 unpack_field_stmts.push(quote! {
495 let #ident = ::msgpacker::unpack_bytes_option(buf).map(|(nv, t)| {
496 n += nv;
497 buf = &buf[nv..];
498 t.map(::core::convert::From::from)
499 })?;
500 });
501 unpack_iter_field_stmts.push(quote! {
502 let #ident = ::msgpacker::unpack_bytes_option_iter(bytes.by_ref()).map(|(nv, t)| {
503 n += nv;
504 t.map(::core::convert::From::from)
505 })?;
506 });
507 } else {
508 pack_field_stmts.push(quote! {
509 n += ::msgpacker::pack_bytes(buf, ::core::convert::AsRef::<[u8]>::as_ref(#ident));
510 });
511 unpack_field_stmts.push(quote! {
512 let #ident = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
513 n += nv;
514 buf = &buf[nv..];
515 ::core::convert::From::from(<[u8]>::to_vec(t))
516 })?;
517 });
518 unpack_iter_field_stmts.push(quote! {
519 let #ident = ::msgpacker::unpack_bytes_iter(bytes.by_ref()).map(|(nv, t)| {
520 n += nv;
521 ::core::convert::From::from(t)
522 })?;
523 });
524 }
525 } else if is_vec_of_u8(&field.ty) {
526 pack_field_stmts
527 .push(quote! { n += ::msgpacker::pack_bytes(buf, #ident.as_slice()); });
528 unpack_field_stmts.push(quote! {
529 let #ident = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
530 n += nv;
531 buf = &buf[nv..];
532 <[u8]>::to_vec(t)
533 })?;
534 });
535 unpack_iter_field_stmts.push(quote! {
536 let #ident = ::msgpacker::unpack_bytes_iter(bytes.by_ref()).map(|(nv, t)| {
537 n += nv;
538 t
539 })?;
540 });
541 } else {
542 pack_field_stmts.push(quote! { n += #ident.pack(buf); });
543 unpack_field_stmts.push(quote! {
544 let #ident = ::msgpacker::Unpackable::unpack_with_ofs(buf).map(|(nv, t)| {
545 n += nv;
546 buf = &buf[nv..];
547 t
548 })?;
549 });
550 unpack_iter_field_stmts.push(quote! {
551 let #ident = ::msgpacker::Unpackable::unpack_iter(bytes.by_ref()).map(|(nv, t)| {
552 n += nv;
553 t
554 })?;
555 });
556 }
557 }
558
559 pack_arms.push(quote! {
560 #name::#variant_ident { #(#field_names),* } => {
561 n += <u32 as ::msgpacker::Packable>::pack(&(#discriminant as u32), buf);
562 #(#pack_field_stmts)*
563 }
564 });
565 unpack_arms.push(quote! {
566 #discriminant => {
567 #(#unpack_field_stmts)*
568 slf = #name::#variant_ident { #(#field_names),* };
569 }
570 });
571 unpack_iter_arms.push(quote! {
572 #discriminant => {
573 #(#unpack_iter_field_stmts)*
574 slf = #name::#variant_ident { #(#field_names),* };
575 }
576 });
577 }
578
579 Fields::Unnamed(f) => {
580 let vars: Vec<Ident> = (0..f.unnamed.len())
581 .map(|j| format_ident!("t{}", j))
582 .collect();
583 let mut pack_field_stmts = Vec::new();
584 let mut unpack_field_stmts = Vec::new();
585 let mut unpack_iter_field_stmts = Vec::new();
586
587 for (var, field) in vars.iter().zip(f.unnamed.iter()) {
588 if has_attr(field, "binary") {
589 if is_option_type(&field.ty) {
590 pack_field_stmts.push(quote! {
591 n += ::msgpacker::pack_bytes_option(
592 buf,
593 #var.as_ref().map(::core::convert::AsRef::as_ref),
594 );
595 });
596 unpack_field_stmts.push(quote! {
597 let #var = ::msgpacker::unpack_bytes_option(buf).map(|(nv, t)| {
598 n += nv;
599 buf = &buf[nv..];
600 t.map(::core::convert::From::from)
601 })?;
602 });
603 unpack_iter_field_stmts.push(quote! {
604 let #var = ::msgpacker::unpack_bytes_option_iter(bytes.by_ref()).map(|(nv, t)| {
605 n += nv;
606 t.map(::core::convert::From::from)
607 })?;
608 });
609 } else {
610 pack_field_stmts.push(quote! {
611 n += ::msgpacker::pack_bytes(buf, ::core::convert::AsRef::<[u8]>::as_ref(#var));
612 });
613 unpack_field_stmts.push(quote! {
614 let #var = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
615 n += nv;
616 buf = &buf[nv..];
617 ::core::convert::From::from(<[u8]>::to_vec(t))
618 })?;
619 });
620 unpack_iter_field_stmts.push(quote! {
621 let #var = ::msgpacker::unpack_bytes_iter(bytes.by_ref()).map(|(nv, t)| {
622 n += nv;
623 ::core::convert::From::from(t)
624 })?;
625 });
626 }
627 } else if is_vec_of_u8(&field.ty) {
628 pack_field_stmts
629 .push(quote! { n += ::msgpacker::pack_bytes(buf, #var.as_slice()); });
630 unpack_field_stmts.push(quote! {
631 let #var = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
632 n += nv;
633 buf = &buf[nv..];
634 <[u8]>::to_vec(t)
635 })?;
636 });
637 unpack_iter_field_stmts.push(quote! {
638 let #var = ::msgpacker::unpack_bytes_iter(bytes.by_ref()).map(|(nv, t)| {
639 n += nv;
640 t
641 })?;
642 });
643 } else {
644 pack_field_stmts.push(quote! { n += #var.pack(buf); });
645 unpack_field_stmts.push(quote! {
646 let #var = ::msgpacker::Unpackable::unpack_with_ofs(buf).map(|(nv, t)| {
647 n += nv;
648 buf = &buf[nv..];
649 t
650 })?;
651 });
652 unpack_iter_field_stmts.push(quote! {
653 let #var = ::msgpacker::Unpackable::unpack_iter(bytes.by_ref()).map(|(nv, t)| {
654 n += nv;
655 t
656 })?;
657 });
658 }
659 }
660
661 pack_arms.push(quote! {
662 #name::#variant_ident(#(#vars),*) => {
663 n += <u32 as ::msgpacker::Packable>::pack(&(#discriminant as u32), buf);
664 #(#pack_field_stmts)*
665 }
666 });
667 unpack_arms.push(quote! {
668 #discriminant => {
669 #(#unpack_field_stmts)*
670 slf = #name::#variant_ident(#(#vars),*);
671 }
672 });
673 unpack_iter_arms.push(quote! {
674 #discriminant => {
675 #(#unpack_iter_field_stmts)*
676 slf = #name::#variant_ident(#(#vars),*);
677 }
678 });
679 }
680
681 Fields::Unit => {
682 pack_arms.push(quote! {
683 #name::#variant_ident => {
684 n += <u32 as ::msgpacker::Packable>::pack(&(#discriminant as u32), buf);
685 }
686 });
687 unpack_arms.push(quote! {
688 #discriminant => slf = #name::#variant_ident,
689 });
690 unpack_iter_arms.push(quote! {
691 #discriminant => slf = #name::#variant_ident,
692 });
693 }
694 }
695 }
696
697 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
698 quote! {
699 impl #impl_generics ::msgpacker::Packable for #name #ty_generics #where_clause {
700 fn pack<T>(&self, buf: &mut T) -> usize
701 where
702 T: ::msgpacker::BufMut,
703 {
704 use ::msgpacker::Packable as _;
705 let mut n = 0usize;
706 match self {
707 #(#pack_arms)*
708 }
709 n
710 }
711 }
712
713 impl #impl_generics ::msgpacker::Unpackable for #name #ty_generics #where_clause {
714 type Error = ::msgpacker::Error;
715
716 #[allow(unused_mut)]
717 fn unpack_with_ofs(mut buf: &[u8]) -> Result<(usize, Self), Self::Error> {
718 let (mut n, discriminant) =
719 <u32 as ::msgpacker::Unpackable>::unpack_with_ofs(buf)?;
720 buf = &buf[n..];
721 let slf;
722 match discriminant {
723 #(#unpack_arms)*
724 _ => return Err(::msgpacker::Error::InvalidEnumVariant),
725 }
726 Ok((n, slf))
727 }
728
729 fn unpack_iter<I>(bytes: I) -> Result<(usize, Self), Self::Error>
730 where
731 I: IntoIterator<Item = u8>,
732 {
733 let mut bytes = bytes.into_iter();
734 let (mut n, discriminant) =
735 <u32 as ::msgpacker::Unpackable>::unpack_iter(bytes.by_ref())?;
736 let slf;
737 match discriminant {
738 #(#unpack_iter_arms)*
739 _ => return Err(::msgpacker::Error::InvalidEnumVariant),
740 }
741 Ok((n, slf))
742 }
743 }
744 }
745}
746
747#[proc_macro_derive(MsgPacker, attributes(msgpacker))]
748pub fn msg_packer(input: TokenStream) -> TokenStream {
749 let input = parse_macro_input!(input as DeriveInput);
750 let name = &input.ident;
751 let generics = &input.generics;
752
753 let tokens = match input.data {
754 Data::Struct(DataStruct {
755 fields: Fields::Named(f),
756 ..
757 }) => impl_struct_named(name, f, generics),
758
759 Data::Struct(DataStruct {
760 fields: Fields::Unnamed(f),
761 ..
762 }) => impl_struct_unnamed(name, f, generics),
763
764 Data::Struct(DataStruct {
765 fields: Fields::Unit,
766 ..
767 }) => impl_struct_unit(name, generics),
768
769 Data::Enum(data) => impl_enum(name, data, generics),
770
771 Data::Union(_) => {
772 todo!(
773 "union support is not implemented for derive macro; implement the traits manually"
774 )
775 }
776 };
777
778 tokens.into()
779}
780
781fn resolve_borrow_lifetime(generics: &Generics) -> (syn::Lifetime, Option<syn::Generics>) {
784 match generics.lifetimes().next() {
785 Some(lt_def) => (lt_def.lifetime.clone(), None),
786 None => {
787 let lt: syn::Lifetime = syn::parse_quote!('__a);
788 let mut modified = generics.clone();
789 modified.params.insert(
790 0,
791 syn::GenericParam::Lifetime(syn::LifetimeParam::new(lt.clone())),
792 );
793 (lt, Some(modified))
794 }
795 }
796}
797
798fn emit_borrowed_struct_impl(
799 name: &Ident,
800 generics: &Generics,
801 borrow_lt: &syn::Lifetime,
802 impl_gen_src: &Generics,
803 pack_stmts: Option<&[TokenStream2]>,
804 unpack_stmts: &[TokenStream2],
805 construct: TokenStream2,
806) -> TokenStream2 {
807 let (pack_impl_generics, ty_generics, pack_where_clause) = generics.split_for_impl();
808 let (impl_generics, _, where_clause) = impl_gen_src.split_for_impl();
809
810 let packable_impl = pack_stmts.map(|stmts| quote! {
811 impl #pack_impl_generics ::msgpacker::Packable for #name #ty_generics #pack_where_clause {
812 fn pack<T>(&self, buf: &mut T) -> usize
813 where
814 T: ::msgpacker::BufMut,
815 {
816 use ::msgpacker::Packable as _;
817 let mut n = 0usize;
818 #(#stmts)*
819 n
820 }
821 }
822 });
823
824 quote! {
825 #packable_impl
826
827 impl #impl_generics ::msgpacker::UnpackableBorrowed<#borrow_lt> for #name #ty_generics #where_clause {
828 type Error = ::msgpacker::Error;
829
830 fn unpack_with_ofs(mut buf: &#borrow_lt [u8]) -> Result<(usize, Self), Self::Error> {
831 let mut n = 0usize;
832 #(#unpack_stmts)*
833 Ok((n, #construct))
834 }
835 }
836 }
837}
838
839fn named_field_borrowed_stmt(
840 ident: &Ident,
841 field: &Field,
842 borrow_lt: &syn::Lifetime,
843) -> TokenStream2 {
844 let ty = &field.ty;
845
846 if has_attr(field, "binary") {
847 return binary_named_unpack_borrowed(ident, ty);
848 }
849
850 if has_attr(field, "map") {
851 return quote! {
852 let #ident = ::msgpacker::unpack_map(buf).map(|(nv, t)| {
853 n += nv;
854 buf = &buf[nv..];
855 t
856 })?;
857 };
858 }
859
860 if is_slice_of_u8(ty) || is_vec_of_u8(ty) {
861 return quote! {
862 let #ident = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
863 n += nv;
864 buf = &buf[nv..];
865 t.into()
866 })?;
867 };
868 }
869
870 if has_attr(field, "array") || is_vec_of_non_u8(ty) {
871 return quote! {
872 let #ident = ::msgpacker::unpack_array_borrowed::<_, _>(buf).map(|(nv, t)| {
873 n += nv;
874 buf = &buf[nv..];
875 t
876 })?;
877 };
878 }
879
880 quote! {
881 let #ident = <_ as ::msgpacker::UnpackableBorrowed<#borrow_lt>>::unpack_with_ofs(buf).map(|(nv, t)| {
882 n += nv;
883 buf = &buf[nv..];
884 t
885 })?;
886 }
887}
888
889fn impl_struct_named_borrowed(
890 name: &Ident,
891 f: FieldsNamed,
892 generics: &Generics,
893 with_packable: bool,
894) -> TokenStream2 {
895 let (borrow_lt, maybe_modified) = resolve_borrow_lifetime(generics);
896 let impl_gen_src = maybe_modified.as_ref().unwrap_or(generics);
897
898 let mut pack_stmts = Vec::new();
899 let mut unpack_stmts = Vec::new();
900 let mut field_names = Vec::new();
901
902 for field in f.named {
903 let ident = field.ident.as_ref().cloned().unwrap();
904 if with_packable {
905 pack_stmts.push(named_field_stmts(&ident, &field).0);
906 }
907 unpack_stmts.push(named_field_borrowed_stmt(&ident, &field, &borrow_lt));
908 field_names.push(ident);
909 }
910
911 emit_borrowed_struct_impl(
912 name,
913 generics,
914 &borrow_lt,
915 impl_gen_src,
916 with_packable.then_some(&pack_stmts[..]),
917 &unpack_stmts,
918 quote! { Self { #(#field_names),* } },
919 )
920}
921
922fn impl_struct_unnamed_borrowed(
923 name: &Ident,
924 f: FieldsUnnamed,
925 generics: &Generics,
926 with_packable: bool,
927) -> TokenStream2 {
928 let (borrow_lt, maybe_modified) = resolve_borrow_lifetime(generics);
929 let impl_gen_src = maybe_modified.as_ref().unwrap_or(generics);
930
931 let mut pack_stmts = Vec::new();
932 let mut unpack_stmts = Vec::new();
933 let mut var_names = Vec::new();
934
935 for (i, field) in f.unnamed.into_iter().enumerate() {
936 if has_attr(&field, "map") {
937 todo!("unnamed map is not implemented for derive macro; implement the traits manually");
938 }
939 if has_attr(&field, "array") {
940 todo!(
941 "unnamed array is not implemented for derive macro; implement the traits manually"
942 );
943 }
944
945 let var = format_ident!("v{}", i);
946 let index = syn::Index::from(i);
947
948 if has_attr(&field, "binary") {
949 if with_packable {
950 if is_option_type(&field.ty) {
951 pack_stmts.push(quote! {
952 n += ::msgpacker::pack_bytes_option(
953 buf,
954 self.#index.as_ref().map(::core::convert::AsRef::as_ref),
955 );
956 });
957 } else {
958 pack_stmts.push(quote! {
959 n += ::msgpacker::pack_bytes(buf, ::core::convert::AsRef::<[u8]>::as_ref(&self.#index));
960 });
961 }
962 }
963 if is_option_type(&field.ty) {
964 unpack_stmts.push(quote! {
965 let #var = ::msgpacker::unpack_bytes_option_ref(buf).map(|(nv, t)| {
966 n += nv;
967 buf = &buf[nv..];
968 t.map(::core::convert::From::from)
969 })?;
970 });
971 } else {
972 unpack_stmts.push(quote! {
973 let #var = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
974 n += nv;
975 buf = &buf[nv..];
976 ::core::convert::From::from(t)
977 })?;
978 });
979 }
980 var_names.push(var);
981 continue;
982 }
983
984 if with_packable {
985 pack_stmts.push(if is_vec_of_u8(&field.ty) {
986 quote! { n += ::msgpacker::pack_bytes(buf, self.#index.as_slice()); }
987 } else if is_slice_of_u8(&field.ty) {
988 quote! { n += ::msgpacker::pack_bytes(buf, self.#index); }
989 } else {
990 quote! { n += self.#index.pack(buf); }
991 });
992 }
993 unpack_stmts.push(quote! {
994 let #var = <_ as ::msgpacker::UnpackableBorrowed<#borrow_lt>>::unpack_with_ofs(buf).map(|(nv, t)| {
995 n += nv;
996 buf = &buf[nv..];
997 t
998 })?;
999 });
1000 var_names.push(var);
1001 }
1002
1003 emit_borrowed_struct_impl(
1004 name,
1005 generics,
1006 &borrow_lt,
1007 impl_gen_src,
1008 with_packable.then_some(&pack_stmts[..]),
1009 &unpack_stmts,
1010 quote! { Self(#(#var_names),*) },
1011 )
1012}
1013
1014fn impl_struct_unit_borrowed(
1015 name: &Ident,
1016 generics: &Generics,
1017 with_packable: bool,
1018) -> TokenStream2 {
1019 let (borrow_lt, maybe_modified) = resolve_borrow_lifetime(generics);
1020 let impl_gen_src = maybe_modified.as_ref().unwrap_or(generics);
1021 let (pack_impl_generics, ty_generics, pack_where_clause) = generics.split_for_impl();
1022 let (impl_generics, _, where_clause) = impl_gen_src.split_for_impl();
1023
1024 let packable_impl = with_packable.then(|| quote! {
1025 impl #pack_impl_generics ::msgpacker::Packable for #name #ty_generics #pack_where_clause {
1026 fn pack<T>(&self, _buf: &mut T) -> usize
1027 where
1028 T: ::msgpacker::BufMut,
1029 {
1030 0
1031 }
1032 }
1033 });
1034
1035 quote! {
1036 #packable_impl
1037
1038 impl #impl_generics ::msgpacker::UnpackableBorrowed<#borrow_lt> for #name #ty_generics #where_clause {
1039 type Error = ::msgpacker::Error;
1040
1041 fn unpack_with_ofs(_buf: &#borrow_lt [u8]) -> Result<(usize, Self), Self::Error> {
1042 Ok((0, Self))
1043 }
1044 }
1045 }
1046}
1047
1048fn impl_enum_borrowed(
1049 name: &Ident,
1050 data: DataEnum,
1051 generics: &Generics,
1052 with_packable: bool,
1053) -> TokenStream2 {
1054 if data.variants.is_empty() {
1055 todo!("empty enum is not implemented for derive macro; implement the traits manually");
1056 }
1057
1058 let (borrow_lt, maybe_modified) = resolve_borrow_lifetime(generics);
1059 let impl_gen_src = maybe_modified.as_ref().unwrap_or(generics);
1060 let (pack_impl_generics, ty_generics, pack_where_clause) = generics.split_for_impl();
1061 let (impl_generics, _, where_clause) = impl_gen_src.split_for_impl();
1062
1063 let mut pack_arms = Vec::new();
1064 let mut unpack_arms = Vec::new();
1065
1066 for (i, variant) in data.variants.into_iter().enumerate() {
1067 let discriminant = variant
1068 .discriminant
1069 .map(|(_, d)| d)
1070 .unwrap_or_else(|| syn::parse_str(&i.to_string()).unwrap());
1071 let variant_ident = &variant.ident;
1072
1073 match variant.fields {
1074 Fields::Named(f) => {
1075 let mut field_names = Vec::new();
1076 let mut pack_field_stmts = Vec::new();
1077 let mut unpack_field_stmts = Vec::new();
1078
1079 for field in &f.named {
1080 let ident = field.ident.as_ref().unwrap();
1081 field_names.push(ident.clone());
1082 if has_attr(field, "binary") {
1083 if with_packable {
1084 if is_option_type(&field.ty) {
1085 pack_field_stmts.push(quote! {
1086 n += ::msgpacker::pack_bytes_option(
1087 buf,
1088 #ident.as_ref().map(::core::convert::AsRef::as_ref),
1089 );
1090 });
1091 } else {
1092 pack_field_stmts.push(quote! {
1093 n += ::msgpacker::pack_bytes(buf, ::core::convert::AsRef::<[u8]>::as_ref(#ident));
1094 });
1095 }
1096 }
1097 if is_option_type(&field.ty) {
1098 unpack_field_stmts.push(quote! {
1099 let #ident = ::msgpacker::unpack_bytes_option_ref(buf).map(|(nv, t)| {
1100 n += nv;
1101 buf = &buf[nv..];
1102 t.map(::core::convert::From::from)
1103 })?;
1104 });
1105 } else {
1106 unpack_field_stmts.push(quote! {
1107 let #ident = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
1108 n += nv;
1109 buf = &buf[nv..];
1110 ::core::convert::From::from(t)
1111 })?;
1112 });
1113 }
1114 } else {
1115 if with_packable {
1116 pack_field_stmts.push(if is_vec_of_u8(&field.ty) {
1117 quote! { n += ::msgpacker::pack_bytes(buf, #ident.as_slice()); }
1118 } else if is_slice_of_u8(&field.ty) {
1119 quote! { n += ::msgpacker::pack_bytes(buf, #ident); }
1120 } else {
1121 quote! { n += #ident.pack(buf); }
1122 });
1123 }
1124 unpack_field_stmts.push(quote! {
1125 let #ident = <_ as ::msgpacker::UnpackableBorrowed<#borrow_lt>>::unpack_with_ofs(buf).map(|(nv, t)| {
1126 n += nv;
1127 buf = &buf[nv..];
1128 t
1129 })?;
1130 });
1131 }
1132 }
1133
1134 if with_packable {
1135 pack_arms.push(quote! {
1136 #name::#variant_ident { #(#field_names),* } => {
1137 n += <u32 as ::msgpacker::Packable>::pack(&(#discriminant as u32), buf);
1138 #(#pack_field_stmts)*
1139 }
1140 });
1141 }
1142 unpack_arms.push(quote! {
1143 #discriminant => {
1144 #(#unpack_field_stmts)*
1145 slf = #name::#variant_ident { #(#field_names),* };
1146 }
1147 });
1148 }
1149
1150 Fields::Unnamed(f) => {
1151 let vars: Vec<Ident> = (0..f.unnamed.len())
1152 .map(|j| format_ident!("t{}", j))
1153 .collect();
1154 let mut pack_field_stmts = Vec::new();
1155 let mut unpack_field_stmts = Vec::new();
1156
1157 for (var, field) in vars.iter().zip(f.unnamed.iter()) {
1158 if has_attr(field, "binary") {
1159 if with_packable {
1160 if is_option_type(&field.ty) {
1161 pack_field_stmts.push(quote! {
1162 n += ::msgpacker::pack_bytes_option(
1163 buf,
1164 #var.as_ref().map(::core::convert::AsRef::as_ref),
1165 );
1166 });
1167 } else {
1168 pack_field_stmts.push(quote! {
1169 n += ::msgpacker::pack_bytes(buf, ::core::convert::AsRef::<[u8]>::as_ref(#var));
1170 });
1171 }
1172 }
1173 if is_option_type(&field.ty) {
1174 unpack_field_stmts.push(quote! {
1175 let #var = ::msgpacker::unpack_bytes_option_ref(buf).map(|(nv, t)| {
1176 n += nv;
1177 buf = &buf[nv..];
1178 t.map(::core::convert::From::from)
1179 })?;
1180 });
1181 } else {
1182 unpack_field_stmts.push(quote! {
1183 let #var = ::msgpacker::unpack_bytes(buf).map(|(nv, t)| {
1184 n += nv;
1185 buf = &buf[nv..];
1186 ::core::convert::From::from(t)
1187 })?;
1188 });
1189 }
1190 } else {
1191 if with_packable {
1192 pack_field_stmts.push(if is_vec_of_u8(&field.ty) {
1193 quote! { n += ::msgpacker::pack_bytes(buf, #var.as_slice()); }
1194 } else if is_slice_of_u8(&field.ty) {
1195 quote! { n += ::msgpacker::pack_bytes(buf, #var); }
1196 } else {
1197 quote! { n += #var.pack(buf); }
1198 });
1199 }
1200 unpack_field_stmts.push(quote! {
1201 let #var = <_ as ::msgpacker::UnpackableBorrowed<#borrow_lt>>::unpack_with_ofs(buf).map(|(nv, t)| {
1202 n += nv;
1203 buf = &buf[nv..];
1204 t
1205 })?;
1206 });
1207 }
1208 }
1209
1210 if with_packable {
1211 pack_arms.push(quote! {
1212 #name::#variant_ident(#(#vars),*) => {
1213 n += <u32 as ::msgpacker::Packable>::pack(&(#discriminant as u32), buf);
1214 #(#pack_field_stmts)*
1215 }
1216 });
1217 }
1218 unpack_arms.push(quote! {
1219 #discriminant => {
1220 #(#unpack_field_stmts)*
1221 slf = #name::#variant_ident(#(#vars),*);
1222 }
1223 });
1224 }
1225
1226 Fields::Unit => {
1227 if with_packable {
1228 pack_arms.push(quote! {
1229 #name::#variant_ident => {
1230 n += <u32 as ::msgpacker::Packable>::pack(&(#discriminant as u32), buf);
1231 }
1232 });
1233 }
1234 unpack_arms.push(quote! {
1235 #discriminant => slf = #name::#variant_ident,
1236 });
1237 }
1238 }
1239 }
1240
1241 let packable_impl = with_packable.then(|| quote! {
1242 impl #pack_impl_generics ::msgpacker::Packable for #name #ty_generics #pack_where_clause {
1243 fn pack<T>(&self, buf: &mut T) -> usize
1244 where
1245 T: ::msgpacker::BufMut,
1246 {
1247 use ::msgpacker::Packable as _;
1248 let mut n = 0usize;
1249 match self {
1250 #(#pack_arms)*
1251 }
1252 n
1253 }
1254 }
1255 });
1256
1257 quote! {
1258 #packable_impl
1259
1260 impl #impl_generics ::msgpacker::UnpackableBorrowed<#borrow_lt> for #name #ty_generics #where_clause {
1261 type Error = ::msgpacker::Error;
1262
1263 #[allow(unused_mut)]
1264 fn unpack_with_ofs(mut buf: &#borrow_lt [u8]) -> Result<(usize, Self), Self::Error> {
1265 let (mut n, discriminant) =
1266 <u32 as ::msgpacker::Unpackable>::unpack_with_ofs(buf)?;
1267 buf = &buf[n..];
1268 let slf;
1269 match discriminant {
1270 #(#unpack_arms)*
1271 _ => return Err(::msgpacker::Error::InvalidEnumVariant),
1272 }
1273 Ok((n, slf))
1274 }
1275 }
1276 }
1277}
1278
1279fn dispatch_borrowed(input: DeriveInput, with_packable: bool) -> TokenStream2 {
1280 let name = &input.ident;
1281 let generics = &input.generics;
1282
1283 match input.data {
1284 Data::Struct(DataStruct {
1285 fields: Fields::Named(f),
1286 ..
1287 }) => impl_struct_named_borrowed(name, f, generics, with_packable),
1288
1289 Data::Struct(DataStruct {
1290 fields: Fields::Unnamed(f),
1291 ..
1292 }) => impl_struct_unnamed_borrowed(name, f, generics, with_packable),
1293
1294 Data::Struct(DataStruct {
1295 fields: Fields::Unit,
1296 ..
1297 }) => impl_struct_unit_borrowed(name, generics, with_packable),
1298
1299 Data::Enum(data) => impl_enum_borrowed(name, data, generics, with_packable),
1300
1301 Data::Union(_) => {
1302 todo!(
1303 "union support is not implemented for derive macro; implement the traits manually"
1304 )
1305 }
1306 }
1307}
1308
1309#[proc_macro_derive(MsgPackerBorrowed, attributes(msgpacker))]
1310pub fn msg_packer_borrowed(input: TokenStream) -> TokenStream {
1311 dispatch_borrowed(parse_macro_input!(input as DeriveInput), true).into()
1312}
1313
1314#[proc_macro_derive(MsgUnpackerBorrowed, attributes(msgpacker))]
1315pub fn msg_unpacker_borrowed(input: TokenStream) -> TokenStream {
1316 dispatch_borrowed(parse_macro_input!(input as DeriveInput), false).into()
1317}