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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
use proc_macro::TokenStream; use quote::quote; use syn; use syn::Fields::Named; use syn::Data::Struct; use proc_macro2::TokenStream as TokenStream2; #[proc_macro_derive(IceDerive)] pub fn ice_derive(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); let blocks = vec![impl_ice_encode(&ast), impl_ice_decode(&ast)]; let gen = quote! { #(#blocks)* }; gen.into() } #[proc_macro_derive(IceEncode)] pub fn ice_encode(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); impl_ice_encode(&ast).into() } #[proc_macro_derive(IceDecode)] pub fn ice_decode(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); impl_ice_decode(&ast).into() } fn impl_ice_encode(ast: &syn::DeriveInput) -> TokenStream2 { let ident = &ast.ident; let mut members = Vec::new(); match &ast.data { Struct(data) => { match &data.fields { Named(fields) => { for field in fields.named.iter() { let field_ident = field.ident.as_ref().unwrap(); members.push(quote! { buffer.extend(self.#field_ident.to_bytes()?); }); } }, _ => { panic!("IceDerive supports named fields only") } } } _ => { panic!("IceDerive supports structs only") } } quote! { impl ToBytes for #ident { fn to_bytes(&self) -> Result<Vec<u8>, Box<dyn std::error::Error + Sync + Send>> { let mut buffer: Vec<u8> = Vec::new(); #(#members)* Ok(buffer) } } } } fn impl_ice_decode(ast: &syn::DeriveInput) -> TokenStream2 { let ident = &ast.ident; let mut members = Vec::new(); match &ast.data { Struct(data) => { match &data.fields { Named(fields) => { for field in fields.named.iter() { let field_ident = field.ident.as_ref().unwrap(); let field_type = &field.ty; members.push(quote! { #field_ident: <#field_type>::from_bytes(&bytes[read as usize..bytes.len()], &mut read)? }); } }, _ => { panic!("IceDerive supports named fields only") } } } _ => { panic!("IceDerive supports structs only") } } quote! { impl FromBytes for #ident { fn from_bytes(bytes: &[u8], read_bytes: &mut i32) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> { let mut read = 0; let result = #ident { #(#members),* }; *read_bytes = *read_bytes + read; Ok(result) } } } }