#![deny(warnings)]
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
use syn::MetaItem::*;
#[proc_macro_derive(IsDao)]
pub fn is_dao(input: TokenStream) -> TokenStream {
let s = input.to_string();
let ast = syn::parse_macro_input(&s).unwrap();
let gen = impl_is_dao(&ast);
gen.parse().unwrap()
}
fn impl_is_dao(ast: &syn::MacroInput) -> quote::Tokens {
let name = &ast.ident;
let fields:Vec<(&syn::Ident, &syn::Ty)> = match ast.body {
syn::Body::Struct(ref data) => {
match *data{
syn::VariantData::Struct(ref fields) => {
fields.iter().map(|f| {
let ident = f.ident.as_ref().unwrap();
let ty = &f.ty;
(ident,ty)
}).collect::<Vec<_>>()
},
_ => panic!("tuples and unit are not covered")
}
},
syn::Body::Enum(_) => panic!("#[derive(NumFields)] can only be used with structs"),
};
let from_fields:Vec<quote::Tokens> =
fields.iter().map(|&(field,_ty)| {
quote!{
#field: {
let v = dao.get(stringify!(#field)).unwrap();
FromValue::from_type(v.to_owned())
},
}
}).collect::<Vec<_>>();
let to_dao:Vec<quote::Tokens> =
fields.iter().map(|&(field,_ty)| {
quote!{
dao.insert(stringify!(#field).to_string(), self.#field.to_db_type());
}
}).collect::<Vec<_>>();
quote! {
impl IsDao for #name {
fn from_dao(dao: &Dao) -> Self{
#name{
#(#from_fields)*
}
}
fn to_dao(&self) -> Dao {
let mut dao = Dao::new();
#(#to_dao)*
dao
}
}
}
}
#[proc_macro_derive(IsTable)]
pub fn to_table_name(input: TokenStream) -> TokenStream {
let s = input.to_string();
let ast = syn::parse_macro_input(&s).unwrap();
let gen = impl_to_table_name(&ast);
gen.parse().unwrap()
}
fn get_table_attr(attrs: &Vec<syn::Attribute>)->Option<String>{
for att in attrs{
println!("{:?}", att);
match att.value{
Word(_) => continue,
List(_,_) => continue,
NameValue(ref name, ref value) => {
if name == "table"{
match *value{
syn::Lit::Str(ref s,ref _style) => {
return Some(s.to_owned())
}
_ => continue
}
}else{continue}
}
};
}
None
}
fn impl_to_table_name(ast: &syn::MacroInput) -> quote::Tokens {
let name = &ast.ident;
let attrs = &ast.attrs;
let tbl = get_table_attr(attrs);
let table_name = match tbl{
Some(tbl) => tbl,
None => format!("{}",name).to_lowercase()
};
let fields:Vec<&syn::Ident> = match ast.body {
syn::Body::Struct(ref data) => {
match *data{
syn::VariantData::Struct(ref fields) => {
fields.iter().map(|f| {
let ident = f.ident.as_ref().unwrap();
let _ty = &f.ty;
ident
}).collect::<Vec<_>>()
},
_ => panic!("tuples and unit are not covered")
}
},
syn::Body::Enum(_) => panic!("#[derive(NumFields)] can only be used with structs"),
};
let from_fields:Vec<quote::Tokens> =
fields.iter().map(|field| {
quote!{
ColumnName{
column: stringify!(#field).to_string(),
table: Some(#table_name.to_string()),
schema: None
}
}
}).collect::<Vec<_>>();
quote! {
impl IsTable for #name {
fn table_name() -> TableName{
TableName{
schema: None,
name: #table_name.to_string(),
columns: vec![#(#from_fields),*],
}
}
}
}
}