binary_serialize_derive/
macro.rs

1use 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}