1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#![deny(missing_docs)]
extern crate proc_macro;
extern crate proc_macro2;
extern crate quote;
extern crate syn;
mod common;
mod descriptors;
mod fields;
mod helpers;
use common::Descriptor;
use descriptors::{enum_desc::EnumDescriptor, struct_desc::StructDescriptor};
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
pub(crate) const ATTRIBUTE_NAME: &str = "version";
pub(crate) const DEFAULT_FN: &str = "default_fn";
pub(crate) const SEMANTIC_SER_FN: &str = "ser_fn";
pub(crate) const SEMANTIC_DE_FN: &str = "de_fn";
pub(crate) const START_VERSION: &str = "start";
pub(crate) const END_VERSION: &str = "end";
#[proc_macro_derive(Versionize, attributes(version))]
pub fn impl_versionize(input: TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let ident = input.ident.clone();
let generics = input.generics.clone();
let descriptor: Box<dyn Descriptor> = match &input.data {
syn::Data::Struct(data_struct) => {
Box::new(StructDescriptor::new(&data_struct, ident.clone()))
}
syn::Data::Enum(data_enum) => Box::new(EnumDescriptor::new(&data_enum, ident.clone())),
syn::Data::Union(_) => {
return (quote! {
compile_error!("Union serialization is not supported.");
})
.into()
}
};
let version = descriptor.version();
let versioned_serializer = descriptor.generate_serializer();
let deserializer = descriptor.generate_deserializer();
let serializer = quote! {
let version = version_map.get_type_version(app_version, <Self as Versionize>::type_id());
let mut copy_of_self = self.clone();
match version {
#versioned_serializer
_ => panic!("Unknown {:?} version {}.", &<Self as Versionize>::type_id(), version)
}
};
(quote! {
impl Versionize for #ident #generics {
fn serialize<W: std::io::Write>(&self, writer: &mut W, version_map: &VersionMap, app_version: u16) -> VersionizeResult<()> {
#serializer
Ok(())
}
fn deserialize<R: std::io::Read>(mut reader: &mut R, version_map: &VersionMap, app_version: u16) -> VersionizeResult<Self> {
#deserializer
}
fn version() -> u16 {
#version
}
}
}).into()
}