1
- use std:: fmt :: Write ;
1
+ use std:: iter ;
2
2
use syn:: { self , Body , Ident , MacroInput , VariantData } ;
3
- use quote:: { Tokens , ToTokens } ;
3
+ use quote:: Tokens ;
4
4
5
5
use accepts;
6
6
use composites:: Field ;
@@ -15,15 +15,15 @@ pub fn expand_derive_fromsql(input: &MacroInput) -> Result<String, String> {
15
15
let ( accepts_body, to_sql_body) = match input. body {
16
16
Body :: Enum ( ref variants) => {
17
17
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) )
19
19
}
20
20
Body :: Struct ( VariantData :: Tuple ( ref fields) ) if fields. len ( ) == 1 => {
21
21
let field = & fields[ 0 ] ;
22
22
( domain_accepts_body ( field) , domain_body ( & input. ident , field) )
23
23
}
24
24
Body :: Struct ( VariantData :: Struct ( ref fields) ) => {
25
25
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) ,
27
27
composite_body ( & input. ident , & fields) )
28
28
}
29
29
_ => {
@@ -32,86 +32,92 @@ pub fn expand_derive_fromsql(input: &MacroInput) -> Result<String, String> {
32
32
}
33
33
} ;
34
34
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
+ }
52
47
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
+ } ;
56
53
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 ) ;
61
61
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
+ ) *
63
67
s => {
64
68
:: 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) ) )
67
70
}
68
- }" ) ;
69
-
70
- out
71
+ }
72
+ }
71
73
}
72
74
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
+ }
78
80
}
79
81
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
+ }
85
87
}
86
88
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 ! {
89
95
fn read_be_i32( buf: & mut & [ u8 ] ) -> :: std:: io:: Result <i32 > {
90
96
let mut bytes = [ 0 ; 4 ] ;
91
97
try!( :: std:: io:: Read :: read_exact( buf, & mut bytes) ) ;
92
98
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 ) ;
96
102
:: std:: result:: Result :: Ok ( num)
97
103
}
98
104
99
105
fn read_value<T >( type_: & :: postgres:: types:: Type ,
100
106
buf: & mut & [ u8 ] ,
101
107
info: & :: postgres:: types:: SessionInfo )
102
108
-> :: 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
107
113
{
108
114
let len = try!( read_be_i32( buf) ) ;
109
115
let value = if len < 0 {
110
116
:: std:: option:: Option :: None
111
117
} else {
112
118
if len as usize > buf. len( ) {
113
119
return :: std:: result:: Result :: Err (
114
- ::std::convert::Into::into(\ " invalid buffer size\ " ));
120
+ :: std:: convert:: Into :: into( "invalid buffer size" ) ) ;
115
121
}
116
122
let ( head, tail) = buf. split_at( len as usize ) ;
117
123
* buf = tail;
@@ -129,49 +135,35 @@ fn composite_body(ident: &Ident, fields: &[Field]) -> String {
129
135
let num_fields = try!( read_be_i32( & mut buf) ) ;
130
136
if num_fields as usize != fields. len( ) {
131
137
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,
133
139
fields. len( ) ) ) ) ;
134
140
}
135
- " . to_owned ( ) ;
136
141
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
+ ) *
141
145
142
- write ! ( out, "
143
- for field in fields {{
146
+ for field in fields {
144
147
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
+ }
160
151
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
+ ) *
162
159
_ => unreachable!( ) ,
163
- }}
164
- }}
165
-
166
- ::std::result::Result::Ok({} {{" , ident) . unwrap ( ) ;
160
+ }
161
+ }
167
162
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
+ } )
171
168
}
172
-
173
- write ! ( out, "
174
- }})" ) . unwrap ( ) ;
175
-
176
- out
177
169
}
0 commit comments