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
#![recursion_limit="1024"] extern crate proc_macro; extern crate syn; #[macro_use] extern crate quote; use proc_macro::TokenStream; fn impl_struct(name: &syn::Ident, fields: &[syn::Field]) -> quote::Tokens { let items: Vec<_> = fields.iter().map(|f| { let ident = &f.ident; let ty = &f.ty; quote! { #ident: src.gread_with::<#ty>(offset, ctx)? } }).collect(); quote! { impl<'a> ::scroll::ctx::TryFromCtx<'a> for #name where #name: 'a { type Error = ::scroll::Error; fn try_from_ctx(src: &'a [u8], (mut offset, ctx): (usize, ::scroll::Endian)) -> ::std::result::Result<Self, Self::Error> { use ::scroll::Gread; let mut offset = &mut offset; let data = #name { #(#items,)* }; Ok(data) } } } } fn impl_try_from_ctx(ast: &syn::MacroInput) -> quote::Tokens { let name = &ast.ident; match &ast.body { &syn::Body::Struct(ref data) => { match data { &syn::VariantData::Struct(ref fields) => { impl_struct(name, &fields) }, _ => { panic!("Pread can only be derived for a regular struct with public fields") } } }, _ => panic!("Pread can only be derived for structs") } } #[proc_macro_derive(Pread)] pub fn derive_pread(input: TokenStream) -> TokenStream { let s = input.to_string(); let ast = syn::parse_macro_input(&s).unwrap(); let gen = impl_try_from_ctx(&ast); gen.parse().unwrap() } fn impl_try_into_ctx(name: &syn::Ident, fields: &[syn::Field]) -> quote::Tokens { let items: Vec<_> = fields.iter().map(|f| { let ident = &f.ident; quote! { dst.gwrite_with(self.#ident, offset, ctx)? } }).collect(); quote! { impl ::scroll::ctx::TryIntoCtx for #name { type Error = ::scroll::Error; fn try_into_ctx(self, mut dst: &mut [u8], (mut offset, ctx): (usize, ::scroll::Endian)) -> ::std::result::Result<(), Self::Error> { use ::scroll::Gwrite; let mut offset = &mut offset; #(#items;)*; Ok(()) } } } } fn impl_pwrite(ast: &syn::MacroInput) -> quote::Tokens { let name = &ast.ident; match &ast.body { &syn::Body::Struct(ref data) => { match data { &syn::VariantData::Struct(ref fields) => { impl_try_into_ctx(name, &fields) }, _ => { panic!("Pwrite can only be derived for a regular struct with public fields") } } }, _ => panic!("Pwrite can only be derived for structs") } } #[proc_macro_derive(Pwrite)] pub fn derive_pwrite(input: TokenStream) -> TokenStream { let s = input.to_string(); let ast = syn::parse_macro_input(&s).unwrap(); let gen = impl_pwrite(&ast); gen.parse().unwrap() }