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
use proc_macro2::TokenStream; use quote::{quote, quote_spanned}; use syn::spanned::Spanned; use syn::{parse_macro_input, Data, DeriveInput, Fields}; #[proc_macro_derive(Decode)] pub fn decode_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; let expr = gen_expr(&input.data); let expanded = quote! { impl ts3::Decode<#name> for #name { type Err = ts3::Error; fn decode(buf: &[u8]) -> std::result::Result<#name, ts3::Error> { let mut st = #name::default(); for s in buf.split(|c| *c == b' ') { let parts: Vec<&[u8]> = s.splitn(2, |c| *c == b'=').collect(); match *parts.get(0).unwrap() { #expr _ => (), } } Ok(st) } } }; proc_macro::TokenStream::from(expanded) } fn gen_expr(data: &Data) -> TokenStream { match *data { Data::Struct(ref data) => match data.fields { Fields::Named(ref fields) => { let recurse = fields.named.iter().map(|f| { let name = &f.ident; let ty = &f.ty; let bytes = name.clone().unwrap().to_string().as_bytes().to_owned(); let bytes_fmt = bin_to_tokens(&bytes); quote_spanned! {f.span()=> #bytes_fmt => { st.#name = match <#ty>::decode(match parts.get(1) { Some(val) => val, None => continue, }) { Ok(val) => val, Err(err) => return Err(err.into()), } }, } }); quote! { #(#recurse)* } } _ => unimplemented!(), }, _ => unimplemented!(), } } fn bin_to_tokens(slice: &[u8]) -> TokenStream { let recurse = slice.iter().map(|b| quote!(#b)); quote! { [#(#recurse),*] } }