@@ -3,80 +3,86 @@ use syntax::attr::AttrMetaMethods;
33use syntax:: codemap:: Span ;
44use syntax:: ext:: base:: { Annotatable , ExtCtxt } ;
55use syntax:: ptr:: P ;
6- use syntax:: parse:: token:: { InternedString , str_to_ident} ;
7- use syntax:: tokenstream:: TokenTree ;
86
97use model:: Model ;
10- use util:: lifetime_list_tokens;
8+ use util:: { lifetime_list_tokens, str_value_of_attr_with_name } ;
119
12- pub fn expand_changeset_for (
10+ pub fn expand_derive_as_changeset (
1311 cx : & mut ExtCtxt ,
1412 span : Span ,
1513 meta_item : & MetaItem ,
1614 annotatable : & Annotatable ,
1715 push : & mut FnMut ( Annotatable ) ,
1816) {
1917 if let Some ( model) = Model :: from_annotable ( cx, span, annotatable) {
20- let options = changeset_options ( cx, meta_item ) . unwrap ( ) ;
18+ let options = changeset_options ( cx, span , annotatable . attrs ( ) ) . unwrap ( ) ;
2119 push ( Annotatable :: Item ( changeset_impl ( cx, span, & options, & model) . unwrap ( ) ) ) ;
2220 } else {
2321 cx. span_err ( meta_item. span ,
24- "`changeset_for ` may only be applied to enums and structs" ) ;
22+ "`#[derive(AsChangeset)] ` may only be applied to enums and structs" ) ;
2523 }
2624}
2725
2826struct ChangesetOptions {
2927 table_name : ast:: Ident ,
30- treat_none_as_null : Vec < TokenTree > ,
28+ treat_none_as_null : bool ,
3129}
3230
33- fn changeset_options ( cx : & mut ExtCtxt , meta_item : & MetaItem ) -> Result < ChangesetOptions , ( ) > {
34- match meta_item. node {
35- MetaItemKind :: List ( _, ref meta_items) => {
36- let table_name = try!( table_name ( cx, & meta_items[ 0 ] ) ) ;
37- let treat_none_as_null = try!( boolean_option ( cx, & meta_items[ 1 ..] , "treat_none_as_null" ) ) ;
38- Ok ( ChangesetOptions {
39- table_name : str_to_ident ( & table_name) ,
40- treat_none_as_null : treat_none_as_null,
41- } )
31+ fn changeset_options (
32+ cx : & mut ExtCtxt ,
33+ span : Span ,
34+ attributes : & [ ast:: Attribute ]
35+ ) -> Result < ChangesetOptions , ( ) > {
36+ let changeset_options_attr = attributes. iter ( ) . find ( |a| a. check_name ( "changeset_options" ) ) ;
37+ let treat_none_as_null = try!( changeset_options_attr
38+ . map ( |a| extract_treat_none_as_null ( cx, a) )
39+ . unwrap_or ( Ok ( false ) ) ) ;
40+ let table_name = match str_value_of_attr_with_name ( cx, attributes, "table_name" ) {
41+ Some ( name) => name,
42+ None => return missing_table_name_error ( cx, span) ,
43+ } ;
44+
45+ Ok ( ChangesetOptions {
46+ table_name : table_name,
47+ treat_none_as_null : treat_none_as_null,
48+ } )
49+ }
50+
51+ fn extract_treat_none_as_null ( cx : & mut ExtCtxt , attr : & ast:: Attribute ) -> Result < bool , ( ) > {
52+ match attr. node . value . node {
53+ MetaItemKind :: List ( _, ref items) if items. len ( ) == 1 => {
54+ if items[ 0 ] . check_name ( "treat_none_as_null" ) {
55+ boolean_option ( cx, & * items[ 0 ] )
56+ } else {
57+ options_usage_error ( cx, attr. span )
58+ }
4259 }
43- _ => usage_error ( cx, meta_item ) ,
60+ _ => options_usage_error ( cx, attr . span ) ,
4461 }
4562}
4663
47- fn table_name ( cx : & mut ExtCtxt , meta_item : & MetaItem ) -> Result < InternedString , ( ) > {
48- match meta_item. node {
49- MetaItemKind :: Word ( ref word) => Ok ( word. clone ( ) ) ,
50- _ => usage_error ( cx, meta_item) ,
64+ fn boolean_option ( cx : & mut ExtCtxt , item : & MetaItem ) -> Result < bool , ( ) > {
65+ match item. value_str ( ) {
66+ Some ( ref s) if * s == "true" => Ok ( true ) ,
67+ Some ( ref s) if * s == "false" => Ok ( false ) ,
68+ _ => options_usage_error ( cx, item. span )
5169 }
5270}
5371
54- #[ allow( unused_imports) ] // quote_tokens! generates warnings
55- fn boolean_option ( cx : & mut ExtCtxt , meta_items : & [ P < MetaItem > ] , option_name : & str )
56- -> Result < Vec < TokenTree > , ( ) >
57- {
58- if let Some ( item) = meta_items. iter ( ) . find ( |item| item. name ( ) == option_name) {
59- match item. value_str ( ) {
60- Some ( ref s) if * s == "true" => Ok ( quote_tokens ! ( cx, "true" ) ) ,
61- Some ( ref s) if * s == "false" => Ok ( quote_tokens ! ( cx, "false" ) ) ,
62- _ => {
63- cx. span_err ( item. span ,
64- & format ! ( "Expected {} to be in the form `option=\" true\" ` or \
65- option=\" false\" ", option_name) ) ;
66- Err ( ( ) )
67- }
68- }
69- } else {
70- Ok ( quote_tokens ! ( cx, "false" ) )
71- }
72+ fn options_usage_error < T > ( cx : & mut ExtCtxt , span : Span ) -> Result < T , ( ) > {
73+ cx. span_err ( span,
74+ r#"`changeset_options` must be used in the form \
75+ `#[changeset_options(treat_none_as_null = "true")]`"# ) ;
76+ Err ( ( ) )
7277}
7378
74- fn usage_error < T > ( cx : & mut ExtCtxt , meta_item : & MetaItem ) -> Result < T , ( ) > {
75- cx. span_err ( meta_item . span ,
76- "`changeset_for` must be used in the form `#[changeset_for(table1) ]`") ;
79+ fn missing_table_name_error < T > ( cx : & mut ExtCtxt , span : Span ) -> Result < T , ( ) > {
80+ cx. span_err ( span, r#"Structs annotated with `#[derive(AsChangeset)]` must \
81+ also be annotated with `#[table_name="something" ]`"# ) ;
7782 Err ( ( ) )
7883}
7984
85+ #[ allow( unused_imports) ] // quote_tokens! generates warnings
8086fn changeset_impl (
8187 cx : & mut ExtCtxt ,
8288 span : Span ,
@@ -85,7 +91,11 @@ fn changeset_impl(
8591) -> Option < P < ast:: Item > > {
8692 let struct_name = model. name ;
8793 let table_name = options. table_name ;
88- let treat_none_as_null = & options. treat_none_as_null ;
94+ let treat_none_as_null = if options. treat_none_as_null {
95+ quote_tokens ! ( cx, "true" )
96+ } else {
97+ quote_tokens ! ( cx, "false" )
98+ } ;
8999 let struct_ty = & model. ty ;
90100 let lifetimes = lifetime_list_tokens ( & model. generics . lifetimes , span) ;
91101
0 commit comments