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
extern crate proc_macro;
use proc_macro::TokenStream;
use syn;
use std::str::FromStr;
use syn::export::ToTokens;
#[proc_macro_derive(Marshall, attributes(marshall))]
pub fn marshall_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
impl_marshall(&ast)
}
fn impl_marshall(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let (marshall, unmarshall) = marshall_content(ast);
let implementation = stringify! (
impl bytebuff::Marshall<#name> for #name {
fn marshall(&self, buff: &mut bytebuff::ByteBuff) {
#marshall
}
fn unmarshall(buff: &mut bytebuff::ByteBuff) -> Result<#name, bytebuff::ReadError> {
Ok(Self {
#unmarshall
})
}
}
);
TokenStream::from_str(implementation
.replace("# name", name.to_string().as_str())
.replace("# marshall", marshall.as_str())
.replace("# unmarshall", unmarshall.as_str())
.as_str()
).unwrap()
}
fn marshall_content(ast: &syn::DeriveInput) -> (String, String) {
let mut marshall = String::new();
let mut unmarshall = String::new();
match &ast.data {
syn::Data::Struct(data) => {
'main: for field in data.fields.iter() {
let name = &field.ident.as_ref().unwrap().to_string();
let ty = &field.ty.to_token_stream().to_string();
for atr in field.attrs.iter() {
if atr.path.is_ident("marshall") {
match atr.tokens.to_string().as_str() {
"(ignore)" => {
unmarshall += stringify!(#: Default::default(),).replace("#", name).as_str();
continue 'main;
}
"(nested)" => {
marshall += stringify!(bytebuff::Marshall::marshall(&self.#, buff);).replace("#", name).as_str();
unmarshall += stringify!(#: <@ as bytebuff::Marshall<@>>::unmarshall(buff)?,).replace("#", name).replace("@", ty).as_str();
continue 'main;
}
_ => ()
}
}
}
marshall += stringify!(bytebuff::Interface::write(buff, self.#.clone());).replace("#", name).as_str();
unmarshall += stringify!(#: bytebuff::Interface::read(buff)?,).replace("#", name).as_str();
}
}
_ => ()
}
(marshall, unmarshall)
}