@@ -13,9 +13,7 @@ The compiler code necessary for #[deriving(Decodable)]. See
13
13
encodable.rs for more.
14
14
*/
15
15
16
- use std:: vec;
17
-
18
- use ast:: { MetaItem , item, Expr , MutMutable } ;
16
+ use ast:: { MetaItem , item, Expr , MutMutable , Ident } ;
19
17
use codemap:: Span ;
20
18
use ext:: base:: ExtCtxt ;
21
19
use ext:: build:: AstBuilder ;
@@ -66,37 +64,18 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
66
64
return match * substr. fields {
67
65
StaticStruct ( _, ref summary) => {
68
66
let nfields = match * summary {
69
- Left ( n) => n , Right ( ref fields) => fields. len( )
67
+ Unnamed ( ref fields) => fields. len ( ) ,
68
+ Named ( ref fields) => fields. len( )
70
69
} ;
71
70
let read_struct_field = cx. ident_of( "read_struct_field" ) ;
72
71
73
- let getarg = |name: @str , field : uint | {
72
+ let result = do decode_static_fields( cx, span, substr. type_ident,
73
+ summary) |span, name, field| {
74
74
cx. expr_method_call( span, blkdecoder, read_struct_field,
75
75
~[ cx. expr_str( span, name) ,
76
76
cx. expr_uint( span, field) ,
77
77
lambdadecode] )
78
78
} ;
79
-
80
- let result = match * summary {
81
- Left ( n) => {
82
- if n == 0 {
83
- cx. expr_ident( span, substr. type_ident)
84
- } else {
85
- let mut fields = vec:: with_capacity( n) ;
86
- for i in range( 0 , n) {
87
- fields. push( getarg( format ! ( "_field{}" , i) . to_managed( ) , i) ) ;
88
- }
89
- cx. expr_call_ident( span, substr. type_ident, fields)
90
- }
91
- }
92
- Right ( ref fields) => {
93
- let fields = do fields. iter( ) . enumerate( ) . map |( i, f) | {
94
- cx. field_imm( span, * f, getarg( cx. str_of( * f) , i) )
95
- } . collect( ) ;
96
- cx. expr_struct_ident( span, substr. type_ident, fields)
97
- }
98
- } ;
99
-
100
79
cx. expr_method_call( span, decoder, cx. ident_of( "read_struct" ) ,
101
80
~[ cx. expr_str( span, cx. str_of( substr. type_ident) ) ,
102
81
cx. expr_uint( span, nfields) ,
@@ -113,31 +92,13 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
113
92
let ( name, parts) = match * f { ( i, ref p) => ( i, p) } ;
114
93
variants. push( cx. expr_str( span, cx. str_of( name) ) ) ;
115
94
116
- let getarg = |field: uint | {
95
+ let decoded = do decode_static_fields( cx, span, name,
96
+ parts) |span, _, field| {
117
97
cx. expr_method_call( span, blkdecoder, rvariant_arg,
118
98
~[ cx. expr_uint( span, field) ,
119
99
lambdadecode] )
120
100
} ;
121
101
122
- let decoded = match * parts {
123
- Left ( n) => {
124
- if n == 0 {
125
- cx. expr_ident( span, name)
126
- } else {
127
- let mut fields = vec:: with_capacity( n) ;
128
- for i in range( 0 u, n) {
129
- fields. push( getarg( i) ) ;
130
- }
131
- cx. expr_call_ident( span, name, fields)
132
- }
133
- }
134
- Right ( ref fields) => {
135
- let fields = do fields. iter( ) . enumerate( ) . map |( i, f) | {
136
- cx. field_imm( span, * f, getarg( i) )
137
- } . collect( ) ;
138
- cx. expr_struct_ident( span, name, fields)
139
- }
140
- } ;
141
102
arms. push( cx. arm( span,
142
103
~[ cx. pat_lit( span, cx. expr_uint( span, i) ) ] ,
143
104
decoded ) ) ;
@@ -158,3 +119,31 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
158
119
_ => cx. bug ( "expected StaticEnum or StaticStruct in deriving(Decodable)" )
159
120
} ;
160
121
}
122
+
123
+ /// Create a decoder for a single enum variant/struct:
124
+ /// - `outer_pat_ident` is the name of this enum variant/struct
125
+ /// - `getarg` should retrieve the `uint`-th field with name `@str`.
126
+ fn decode_static_fields( cx: @ExtCtxt , outer_span: Span , outer_pat_ident: Ident ,
127
+ fields: & StaticFields ,
128
+ getarg: & fn ( Span , @str, uint) -> @Expr ) -> @Expr {
129
+ match * fields {
130
+ Unnamed ( ref fields) => {
131
+ if fields. is_empty ( ) {
132
+ cx. expr_ident ( outer_span, outer_pat_ident)
133
+ } else {
134
+ let fields = do fields. iter ( ) . enumerate ( ) . map |( i, & span) | {
135
+ getarg ( span, format ! ( "_field{}" , i) . to_managed ( ) , i)
136
+ } . collect ( ) ;
137
+
138
+ cx. expr_call_ident ( outer_span, outer_pat_ident, fields)
139
+ }
140
+ }
141
+ Named ( ref fields) => {
142
+ // use the field's span to get nicer error messages.
143
+ let fields = do fields. iter ( ) . enumerate ( ) . map |( i, & ( name, span) ) | {
144
+ cx. field_imm ( span, name, getarg ( span, cx. str_of ( name) , i) )
145
+ } . collect ( ) ;
146
+ cx. expr_struct_ident ( outer_span, outer_pat_ident, fields)
147
+ }
148
+ }
149
+ }
0 commit comments