binary_serialize_derive/
macro.rs1use proc_macro::TokenStream;
2use syn_helpers::{
3 derive_trait,
4 proc_macro2::Span,
5 syn::{parse_macro_input, parse_quote, DeriveInput, Expr, Ident, Stmt},
6 Constructable, FieldMut, NamedOrUnnamedFieldMut, Structure, Trait, TraitItem, TypeOfSelf,
7};
8
9#[proc_macro_derive(BinarySerializable)]
10pub fn derive_binary_serializable(input: TokenStream) -> TokenStream {
11 let input = parse_macro_input!(input as DeriveInput);
12 let result = derive_trait(
13 input,
14 Trait {
15 name: parse_quote!(crate::BinarySerializable),
16 generic_parameters: None,
17 items: vec![
18 TraitItem::new_method(
19 Ident::new("serialize", Span::call_site()),
20 None,
21 TypeOfSelf::Owned,
22 vec![parse_quote!(buf: &mut Vec<u8>)],
23 None,
24 |mut item| {
25 item.map_constructable(|mut constructable| {
26 let iterator = constructable
27 .as_enum_variant()
28 .map(|variant| {
29 let idx = variant.idx as u8;
30 parse_quote!(buf.push(#idx);)
31 })
32 .into_iter()
33 .chain(constructable.get_fields_mut().fields_iterator_mut().map(
34 |mut field: NamedOrUnnamedFieldMut| -> Stmt {
35 let reference = field.get_reference();
36 parse_quote!(crate::BinarySerializable::serialize(#reference, buf);)
37 },
38 ));
39 Ok(iterator.collect())
40 })
41 },
42 ),
43 TraitItem::new_associated_function(
44 Ident::new("deserialize", Span::call_site()),
45 Some(vec![parse_quote!(I: Iterator<Item = u8>)]),
46 vec![
47 parse_quote!(iter: &mut I),
48 parse_quote!(backing_source: ::source_map::SourceId),
49 ],
50 Some(parse_quote!(Self)),
51 |structure| {
52 let deserialize_call: Expr = parse_quote!(
53 crate::BinarySerializable::deserialize(iter, backing_source)
54 );
55
56 match structure {
57 Structure::Enum(r#enum) => {
58 let indexer: Stmt =
59 parse_quote!(let indexer = iter.next().unwrap(););
60
61 let bad_case = parse_quote!(
62 unreachable!("invalid discriminant when deserializing enum");
63 );
64
65 Ok(std::iter::once(indexer)
66 .chain(r#enum.get_variants().iter().map(|variant| {
67 let idx = variant.idx as u8;
68 let constructor = variant
69 .build_constructor(|_| Ok(deserialize_call.clone()))
70 .unwrap();
71
72 parse_quote!(if indexer == #idx {
73 return #constructor;
74 })
75 }))
76 .chain(std::iter::once(bad_case))
77 .collect())
78 }
79 Structure::Struct(r#struct) => r#struct
80 .build_constructor(|_| Ok(deserialize_call.clone()))
81 .map(|expr| vec![Stmt::Expr(expr, None)]),
82 }
83 },
84 ),
85 ],
86 },
87 );
88
89 result.into()
90}