1- use std:: fmt :: Write ;
1+ use std:: iter ;
22use syn:: { self , Body , Ident , MacroInput , VariantData } ;
3- use quote:: { Tokens , ToTokens } ;
3+ use quote:: Tokens ;
44
55use accepts;
66use composites:: Field ;
@@ -15,15 +15,15 @@ pub fn expand_derive_fromsql(input: &MacroInput) -> Result<String, String> {
1515 let ( accepts_body, to_sql_body) = match input. body {
1616 Body :: Enum ( ref variants) => {
1717 let variants: Vec < Variant > = try!( variants. iter ( ) . map ( Variant :: parse) . collect ( ) ) ;
18- ( accepts:: enum_body ( & name, & variants) . to_string ( ) , enum_body ( & input. ident , & variants) )
18+ ( accepts:: enum_body ( & name, & variants) , enum_body ( & input. ident , & variants) )
1919 }
2020 Body :: Struct ( VariantData :: Tuple ( ref fields) ) if fields. len ( ) == 1 => {
2121 let field = & fields[ 0 ] ;
2222 ( domain_accepts_body ( field) , domain_body ( & input. ident , field) )
2323 }
2424 Body :: Struct ( VariantData :: Struct ( ref fields) ) => {
2525 let fields: Vec < Field > = try!( fields. iter ( ) . map ( Field :: parse) . collect ( ) ) ;
26- ( accepts:: composite_body ( & name, "FromSql" , & fields) . to_string ( ) ,
26+ ( accepts:: composite_body ( & name, "FromSql" , & fields) ,
2727 composite_body ( & input. ident , & fields) )
2828 }
2929 _ => {
@@ -32,86 +32,92 @@ pub fn expand_derive_fromsql(input: &MacroInput) -> Result<String, String> {
3232 }
3333 } ;
3434
35- let out = format ! ( "
36- impl ::postgres::types::FromSql for {} {{
37- fn from_sql(_type: &::postgres::types::Type,
38- buf: &[u8],
39- _info: &::postgres::types::SessionInfo)
40- -> ::std::result::Result<{},
41- ::std::boxed::Box<::std::error::Error +
42- ::std::marker::Sync +
43- ::std::marker::Send>> {{{}
44- }}
45-
46- fn accepts(type_: &::postgres::types::Type) -> bool {{{}
47- }}
48- }}" , input. ident, input. ident, to_sql_body, accepts_body) ;
49-
50- Ok ( out)
51- }
35+ let ident = & input. ident ;
36+ let out = quote ! {
37+ impl :: postgres:: types:: FromSql for #ident {
38+ fn from_sql( _type: & :: postgres:: types:: Type ,
39+ buf: & [ u8 ] ,
40+ _info: & :: postgres:: types:: SessionInfo )
41+ -> :: std:: result:: Result <#ident,
42+ :: std:: boxed:: Box <:: std:: error:: Error +
43+ :: std:: marker:: Sync +
44+ :: std:: marker:: Send >> {
45+ #to_sql_body
46+ }
5247
53- fn enum_body ( ident : & Ident , variants : & [ Variant ] ) -> String {
54- let mut out = "
55- match buf {" . to_owned ( ) ;
48+ fn accepts( type_: & :: postgres:: types:: Type ) -> bool {
49+ #accepts_body
50+ }
51+ }
52+ } ;
5653
57- for variant in variants {
58- write ! ( out, "
59- b\" {}\" => Ok({}::{})," , variant. name, ident, variant. ident) . unwrap ( ) ;
60- }
54+ Ok ( out. to_string ( ) )
55+ }
56+
57+ fn enum_body ( ident : & Ident , variants : & [ Variant ] ) -> Tokens {
58+ let variant_names = variants. iter ( ) . map ( |v| & v. name ) ;
59+ let idents = iter:: repeat ( ident) ;
60+ let variant_idents = variants. iter ( ) . map ( |v| & v. ident ) ;
6161
62- out. push_str ( "
62+ quote ! {
63+ match try!( :: std:: str :: from_utf8( buf) ) {
64+ #(
65+ #variant_names => :: std:: result:: Result :: Ok ( #idents:: #variant_idents) ,
66+ ) *
6367 s => {
6468 :: std:: result:: Result :: Err (
65- ::std::convert::Into::into(format!(\" invalid variant `{}`\" ,
66- ::std::string::String::from_utf8_lossy(s))))
69+ :: std:: convert:: Into :: into( format!( "invalid variant `{}`" , s) ) )
6770 }
68- }" ) ;
69-
70- out
71+ }
72+ }
7173}
7274
73- fn domain_accepts_body ( field : & syn:: Field ) -> String {
74- let mut tokens = Tokens :: new ( ) ;
75- field . ty . to_tokens ( & mut tokens ) ;
76- format ! ( "
77- <{} as ::postgres::types::FromSql>::accepts(type_)" , tokens )
75+ fn domain_accepts_body ( field : & syn:: Field ) -> Tokens {
76+ let ty = & field . ty ;
77+ quote ! {
78+ <#ty as :: postgres :: types :: FromSql > :: accepts ( type_ )
79+ }
7880}
7981
80- fn domain_body ( ident : & Ident , field : & syn:: Field ) -> String {
81- let mut tokens = Tokens :: new ( ) ;
82- field . ty . to_tokens ( & mut tokens ) ;
83- format ! ( " \
84- <{} as ::postgres::types::FromSql>::from_sql(_type, buf, _info).map({})" , tokens , ident )
82+ fn domain_body ( ident : & Ident , field : & syn:: Field ) -> Tokens {
83+ let ty = & field . ty ;
84+ quote ! {
85+ <#ty as :: postgres :: types :: FromSql > :: from_sql ( _type , buf , _info ) . map ( #ident )
86+ }
8587}
8688
87- fn composite_body ( ident : & Ident , fields : & [ Field ] ) -> String {
88- let mut out = "
89+ fn composite_body ( ident : & Ident , fields : & [ Field ] ) -> Tokens {
90+ let temp_vars = & fields. iter ( ) . map ( |f| Ident :: new ( format ! ( "__{}" , f. ident) ) ) . collect :: < Vec < _ > > ( ) ;
91+ let field_names = & fields. iter ( ) . map ( |f| & f. name ) . collect :: < Vec < _ > > ( ) ;
92+ let field_idents = & fields. iter ( ) . map ( |f| & f. ident ) . collect :: < Vec < _ > > ( ) ;
93+
94+ quote ! {
8995 fn read_be_i32( buf: & mut & [ u8 ] ) -> :: std:: io:: Result <i32 > {
9096 let mut bytes = [ 0 ; 4 ] ;
9197 try!( :: std:: io:: Read :: read_exact( buf, & mut bytes) ) ;
9298 let num = ( ( bytes[ 0 ] as i32 ) << 24 ) |
93- ((bytes[1] as i32) << 16) |
94- ((bytes[2] as i32) << 8) |
95- (bytes[3] as i32);
99+ ( ( bytes[ 1 ] as i32 ) << 16 ) |
100+ ( ( bytes[ 2 ] as i32 ) << 8 ) |
101+ ( bytes[ 3 ] as i32 ) ;
96102 :: std:: result:: Result :: Ok ( num)
97103 }
98104
99105 fn read_value<T >( type_: & :: postgres:: types:: Type ,
100106 buf: & mut & [ u8 ] ,
101107 info: & :: postgres:: types:: SessionInfo )
102108 -> :: std:: result:: Result <T ,
103- ::std::boxed::Box<::std::error::Error +
104- ::std::marker::Sync +
105- ::std::marker::Send>>
106- where T: ::postgres::types::FromSql
109+ :: std:: boxed:: Box <:: std:: error:: Error +
110+ :: std:: marker:: Sync +
111+ :: std:: marker:: Send >>
112+ where T : :: postgres:: types:: FromSql
107113 {
108114 let len = try!( read_be_i32( buf) ) ;
109115 let value = if len < 0 {
110116 :: std:: option:: Option :: None
111117 } else {
112118 if len as usize > buf. len( ) {
113119 return :: std:: result:: Result :: Err (
114- ::std::convert::Into::into(\ " invalid buffer size\ " ));
120+ :: std:: convert:: Into :: into( "invalid buffer size" ) ) ;
115121 }
116122 let ( head, tail) = buf. split_at( len as usize ) ;
117123 * buf = tail;
@@ -129,49 +135,35 @@ fn composite_body(ident: &Ident, fields: &[Field]) -> String {
129135 let num_fields = try!( read_be_i32( & mut buf) ) ;
130136 if num_fields as usize != fields. len( ) {
131137 return :: std:: result:: Result :: Err (
132- ::std::convert::Into::into(format!(\ " invalid field count: {} vs {}\ " , num_fields,
138+ :: std:: convert:: Into :: into( format!( "invalid field count: {} vs {}" , num_fields,
133139 fields. len( ) ) ) ) ;
134140 }
135- " . to_owned ( ) ;
136141
137- for field in fields {
138- write ! ( out, "
139- let mut __{} = ::std::option::Option::None;" , field. ident) . unwrap ( ) ;
140- }
142+ #(
143+ let mut #temp_vars = :: std:: option:: Option :: None ;
144+ ) *
141145
142- write ! ( out, "
143- for field in fields {{
146+ for field in fields {
144147 let oid = try!( read_be_i32( & mut buf) ) as u32 ;
145- if oid != field.type_().oid() {{
146- return ::std::result::Result::Err(
147- ::std::convert::Into::into(\" unexpected OID\" ));
148- }}
149-
150- match field.name() {{" ) . unwrap ( ) ;
151-
152- for field in fields {
153- write ! ( out, "
154- \" {}\" => {{
155- __{} = ::std::option::Option::Some(
156- try!(read_value(field.type_(), &mut buf, _info)));
157- }}" ,
158- field. name, field. ident) . unwrap ( ) ;
159- }
148+ if oid != field. type_( ) . oid( ) {
149+ return :: std:: result:: Result :: Err ( :: std:: convert:: Into :: into( "unexpected OID" ) ) ;
150+ }
160151
161- write ! ( out, "
152+ match field. name( ) {
153+ #(
154+ #field_names => {
155+ #temp_vars = :: std:: option:: Option :: Some (
156+ try!( read_value( field. type_( ) , & mut buf, _info) ) ) ;
157+ }
158+ ) *
162159 _ => unreachable!( ) ,
163- }}
164- }}
165-
166- ::std::result::Result::Ok({} {{" , ident) . unwrap ( ) ;
160+ }
161+ }
167162
168- for field in fields {
169- write ! ( out, "
170- {}: __{}.unwrap()," , field. ident, field. ident) . unwrap ( ) ;
163+ :: std:: result:: Result :: Ok ( #ident {
164+ #(
165+ #field_idents: #temp_vars. unwrap( ) ,
166+ ) *
167+ } )
171168 }
172-
173- write ! ( out, "
174- }})" ) . unwrap ( ) ;
175-
176- out
177169}
0 commit comments