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
extern crate proc_macro; #[macro_use] extern crate quote; extern crate syn; use proc_macro::TokenStream; use syn::DeriveInput; #[proc_macro_derive(FitsRow, attributes(fitsio))] pub fn read_row(input: TokenStream) -> TokenStream { let input: DeriveInput = syn::parse(input).unwrap(); let expanded = impl_read_row(input); expanded.into() } fn impl_read_row(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; let mut tokens = Vec::new(); match &input.data { &syn::Data::Struct(ref s) => match &s.fields { &syn::Fields::Named(ref fields) => for field in &fields.named { let ident = &field.ident.unwrap(); let ident_str = ident.to_string(); if field.attrs.is_empty() { tokens.push(quote! { out.#ident = tbl.read_cell_value(fits_file, #ident_str, idx)?; }); } else { for attr in &field.attrs { match attr.interpret_meta() { Some(syn::Meta::List(l)) => for entry in l.nested { match entry { syn::NestedMeta::Meta(syn::Meta::NameValue( syn::MetaNameValue { ident: attr_ident, lit, .. }, )) => { if attr_ident.to_string() != "colname" { continue; } match lit { syn::Lit::Str(ls) => { tokens.push(quote! { out.#ident = tbl.read_cell_value( fits_file, #ls, idx)?; }); } _ => panic!( "Only #[fitsio(colname = \"...\")] is supported" ), } } _ => panic!("Only #[fitsio(colname = \"...\")] is supported"), } }, _ => panic!("Only #[fitsio(colname = \"...\")] is supported"), } } } }, _ => panic!("Only #[fitsio(colname = \"...\")] is supported"), }, _ => panic!("derive only possible for structs"), } quote!{ impl FitsRow for #name { fn from_table( tbl: &::fitsio::FitsHdu, fits_file: &mut ::fitsio::FitsFile, idx: usize) -> ::fitsio::errors::Result<Self> where Self: Sized { let mut out = Self::default(); #(#tokens)* Ok(out) } } } }