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
extern crate proc_macro; extern crate syn; #[macro_use] extern crate quote; use std::collections::HashSet; use proc_macro::TokenStream; #[proc_macro_derive(Packed)] pub fn derive_parsed(input: TokenStream) -> TokenStream { let s = input.to_string(); let ast = syn::parse_derive_input(&s).unwrap(); match impl_parsed(&ast) { Ok(gen) => { gen.parse().unwrap() } Err(msg) => panic!(msg) } } fn impl_parsed(ast: &syn::DeriveInput) -> Result<quote::Tokens, String> { let name = &ast.ident; let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); let mut where_clause = where_clause.clone(); let mut type_set = HashSet::<syn::Ty>::new(); let mut members = Vec::<syn::Ident>::new(); match ast.body { syn::Body::Enum(_) => { return Err("Cannot implement Parsed for an enum".to_string()); }, syn::Body::Struct(syn::VariantData::Unit) => { return Err("Cannot implement Parsed for a unit struct".to_string()); } syn::Body::Struct(syn::VariantData::Struct(ref fields)) => { for ref field in fields { type_set.insert(field.ty.clone()); members.push(field.ident.clone().unwrap()); } }, syn::Body::Struct(syn::VariantData::Tuple(ref fields)) => { for i in 0..fields.len() { type_set.insert(fields[i].ty.clone()); members.push(syn::Ident::new(i)); } } } if members.len() == 0 { return Err("Cannot implement Parsed for an empty struct".to_string()); } let packed_bound = syn::parse_ty_param_bound("bytepack::Packed")?; for ty in &type_set { where_clause.predicates.push(syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { bound_lifetimes: Vec::new(), bounded_ty: ty.clone(), bounds: vec![packed_bound.clone()] })); } Ok(quote! { impl #impl_generics Packed for #name #ty_generics #where_clause { fn switch_endianness(&mut self) { #( self.#members.switch_endianness(); )* } } }) }