1
1
//! Support for deserializing configuration via `serde`
2
2
3
- use crate :: util:: config:: { Config , ConfigError , ConfigKey , ConfigKeyPart } ;
4
- use crate :: util:: config:: { ConfigValue as CV , Value , Definition } ;
5
- use std :: path :: PathBuf ;
3
+ use crate :: util:: config:: value ;
4
+ use crate :: util:: config:: { Config , ConfigError , ConfigKey } ;
5
+ use crate :: util :: config :: { ConfigValue as CV , Definition , Value } ;
6
6
use serde:: { de, de:: IntoDeserializer } ;
7
7
use std:: collections:: HashSet ;
8
+ use std:: path:: PathBuf ;
8
9
use std:: vec;
9
10
10
11
/// Serde deserializer used to convert config values to a target type using
11
12
/// `Config::get`.
13
+ #[ derive( Clone ) ]
12
14
pub ( crate ) struct Deserializer < ' config > {
13
15
pub ( crate ) config : & ' config Config ,
14
16
pub ( crate ) key : ConfigKey ,
@@ -21,10 +23,10 @@ macro_rules! deserialize_method {
21
23
V : de:: Visitor <' de>,
22
24
{
23
25
let v = self . config. $getter( & self . key) ?. ok_or_else( ||
24
- ConfigError :: missing( & self . key. to_config ( ) ) ) ?;
26
+ ConfigError :: missing( & self . key) ) ?;
25
27
let Value { val, definition} = v;
26
28
let res: Result <V :: Value , ConfigError > = visitor. $visit( val) ;
27
- res. map_err( |e| e. with_key_context( & self . key. to_config ( ) , definition) )
29
+ res. map_err( |e| e. with_key_context( & self . key, definition) )
28
30
}
29
31
}
30
32
}
@@ -39,7 +41,7 @@ impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
39
41
// Future note: If you ever need to deserialize a non-self describing
40
42
// map type, this should implement a starts_with check (similar to how
41
43
// ConfigMapAccess does).
42
- if let Some ( v) = self . config . env . get ( & self . key . to_env ( ) ) {
44
+ if let Some ( v) = self . config . env . get ( self . key . as_env_key ( ) ) {
43
45
let res: Result < V :: Value , ConfigError > = if v == "true" || v == "false" {
44
46
visitor. visit_bool ( v. parse ( ) . unwrap ( ) )
45
47
} else if let Ok ( v) = v. parse :: < i64 > ( ) {
@@ -48,38 +50,34 @@ impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
48
50
&& v. starts_with ( '[' )
49
51
&& v. ends_with ( ']' )
50
52
{
51
- visitor. visit_seq ( ConfigSeqAccess :: new ( self . config , & self . key ) ?)
53
+ visitor. visit_seq ( ConfigSeqAccess :: new ( self . clone ( ) ) ?)
52
54
} else {
53
55
visitor. visit_string ( v. clone ( ) )
54
56
} ;
55
57
return res. map_err ( |e| {
56
58
e. with_key_context (
57
- & self . key . to_config ( ) ,
58
- Definition :: Environment ( self . key . to_env ( ) ) ,
59
+ & self . key ,
60
+ Definition :: Environment ( self . key . as_env_key ( ) . to_string ( ) ) ,
59
61
)
60
62
} ) ;
61
63
}
62
64
63
- let o_cv = self . config . get_cv ( & self . key . to_config ( ) ) ?;
65
+ let o_cv = self . config . get_cv ( self . key . as_config_key ( ) ) ?;
64
66
if let Some ( cv) = o_cv {
65
67
let res: ( Result < V :: Value , ConfigError > , PathBuf ) = match cv {
66
68
CV :: Integer ( i, path) => ( visitor. visit_i64 ( i) , path) ,
67
69
CV :: String ( s, path) => ( visitor. visit_string ( s) , path) ,
68
- CV :: List ( _, path) => (
69
- visitor. visit_seq ( ConfigSeqAccess :: new ( self . config , & self . key ) ?) ,
70
- path,
71
- ) ,
70
+ CV :: List ( _, path) => ( visitor. visit_seq ( ConfigSeqAccess :: new ( self . clone ( ) ) ?) , path) ,
72
71
CV :: Table ( _, path) => (
73
- visitor. visit_map ( ConfigMapAccess :: new_map ( self . config , self . key . clone ( ) ) ?) ,
72
+ visitor. visit_map ( ConfigMapAccess :: new_map ( self . clone ( ) ) ?) ,
74
73
path,
75
74
) ,
76
75
CV :: Boolean ( b, path) => ( visitor. visit_bool ( b) , path) ,
77
76
} ;
78
77
let ( res, path) = res;
79
- return res
80
- . map_err ( |e| e. with_key_context ( & self . key . to_config ( ) , Definition :: Path ( path) ) ) ;
78
+ return res. map_err ( |e| e. with_key_context ( & self . key , Definition :: Path ( path) ) ) ;
81
79
}
82
- Err ( ConfigError :: missing ( & self . key . to_config ( ) ) )
80
+ Err ( ConfigError :: missing ( & self . key ) )
83
81
}
84
82
85
83
deserialize_method ! ( deserialize_bool, visit_bool, get_bool_priv) ;
@@ -107,35 +105,41 @@ impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
107
105
108
106
fn deserialize_struct < V > (
109
107
self ,
110
- _name : & ' static str ,
108
+ name : & ' static str ,
111
109
fields : & ' static [ & ' static str ] ,
112
110
visitor : V ,
113
111
) -> Result < V :: Value , Self :: Error >
114
112
where
115
113
V : de:: Visitor < ' de > ,
116
114
{
117
- visitor. visit_map ( ConfigMapAccess :: new_struct ( self . config , self . key , fields) ?)
115
+ if name == value:: NAME && fields == value:: FIELDS {
116
+ return visitor. visit_map ( ValueDeserializer {
117
+ hits : 0 ,
118
+ deserializer : self ,
119
+ } ) ;
120
+ }
121
+ visitor. visit_map ( ConfigMapAccess :: new_struct ( self , fields) ?)
118
122
}
119
123
120
124
fn deserialize_map < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
121
125
where
122
126
V : de:: Visitor < ' de > ,
123
127
{
124
- visitor. visit_map ( ConfigMapAccess :: new_map ( self . config , self . key ) ?)
128
+ visitor. visit_map ( ConfigMapAccess :: new_map ( self ) ?)
125
129
}
126
130
127
131
fn deserialize_seq < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
128
132
where
129
133
V : de:: Visitor < ' de > ,
130
134
{
131
- visitor. visit_seq ( ConfigSeqAccess :: new ( self . config , & self . key ) ?)
135
+ visitor. visit_seq ( ConfigSeqAccess :: new ( self ) ?)
132
136
}
133
137
134
138
fn deserialize_tuple < V > ( self , _len : usize , visitor : V ) -> Result < V :: Value , Self :: Error >
135
139
where
136
140
V : de:: Visitor < ' de > ,
137
141
{
138
- visitor. visit_seq ( ConfigSeqAccess :: new ( self . config , & self . key ) ?)
142
+ visitor. visit_seq ( ConfigSeqAccess :: new ( self ) ?)
139
143
}
140
144
141
145
fn deserialize_tuple_struct < V > (
@@ -147,7 +151,7 @@ impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
147
151
where
148
152
V : de:: Visitor < ' de > ,
149
153
{
150
- visitor. visit_seq ( ConfigSeqAccess :: new ( self . config , & self . key ) ?)
154
+ visitor. visit_seq ( ConfigSeqAccess :: new ( self ) ?)
151
155
}
152
156
153
157
fn deserialize_newtype_struct < V > (
@@ -169,7 +173,7 @@ impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
169
173
. to_string ( ) ;
170
174
visitor. visit_newtype_struct ( path. into_deserializer ( ) )
171
175
}
172
- None => Err ( ConfigError :: missing ( & self . key . to_config ( ) ) ) ,
176
+ None => Err ( ConfigError :: missing ( & self . key ) ) ,
173
177
}
174
178
} else {
175
179
visitor. visit_newtype_struct ( self )
@@ -185,70 +189,76 @@ impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
185
189
}
186
190
187
191
struct ConfigMapAccess < ' config > {
188
- config : & ' config Config ,
189
- key : ConfigKey ,
190
- set_iter : <HashSet < ConfigKeyPart > as IntoIterator >:: IntoIter ,
191
- next : Option < ConfigKeyPart > ,
192
+ de : Deserializer < ' config > ,
193
+ set_iter : <HashSet < KeyKind > as IntoIterator >:: IntoIter ,
194
+ next : Option < KeyKind > ,
195
+ }
196
+
197
+ #[ derive( PartialEq , Eq , Hash ) ]
198
+ enum KeyKind {
199
+ Normal ( String ) ,
200
+ CaseSensitive ( String ) ,
192
201
}
193
202
194
203
impl < ' config > ConfigMapAccess < ' config > {
195
- fn new_map (
196
- config : & ' config Config ,
197
- key : ConfigKey ,
198
- ) -> Result < ConfigMapAccess < ' config > , ConfigError > {
204
+ fn new_map ( de : Deserializer < ' config > ) -> Result < ConfigMapAccess < ' config > , ConfigError > {
199
205
let mut set = HashSet :: new ( ) ;
200
- if let Some ( mut v) = config. get_table ( & key. to_config ( ) ) ? {
206
+ if let Some ( mut v) = de . config . get_table ( de . key . as_config_key ( ) ) ? {
201
207
// `v: Value<HashMap<String, CV>>`
202
208
for ( key, _value) in v. val . drain ( ) {
203
- set. insert ( ConfigKeyPart :: CasePart ( key) ) ;
209
+ set. insert ( KeyKind :: CaseSensitive ( key) ) ;
204
210
}
205
211
}
206
- if config. cli_unstable ( ) . advanced_env {
212
+ if de . config . cli_unstable ( ) . advanced_env {
207
213
// `CARGO_PROFILE_DEV_OVERRIDES_`
208
- let env_pattern = format ! ( "{}_" , key. to_env ( ) ) ;
209
- for env_key in config. env . keys ( ) {
214
+ let env_pattern = format ! ( "{}_" , de . key. as_env_key ( ) ) ;
215
+ for env_key in de . config . env . keys ( ) {
210
216
if env_key. starts_with ( & env_pattern) {
211
217
// `CARGO_PROFILE_DEV_OVERRIDES_bar_OPT_LEVEL = 3`
212
218
let rest = & env_key[ env_pattern. len ( ) ..] ;
213
219
// `rest = bar_OPT_LEVEL`
214
220
let part = rest. splitn ( 2 , '_' ) . next ( ) . unwrap ( ) ;
215
221
// `part = "bar"`
216
- set. insert ( ConfigKeyPart :: CasePart ( part. to_string ( ) ) ) ;
222
+ set. insert ( KeyKind :: CaseSensitive ( part. to_string ( ) ) ) ;
217
223
}
218
224
}
219
225
}
220
226
Ok ( ConfigMapAccess {
221
- config,
222
- key,
227
+ de,
223
228
set_iter : set. into_iter ( ) ,
224
229
next : None ,
225
230
} )
226
231
}
227
232
228
233
fn new_struct (
229
- config : & ' config Config ,
230
- key : ConfigKey ,
234
+ de : Deserializer < ' config > ,
231
235
fields : & ' static [ & ' static str ] ,
232
236
) -> Result < ConfigMapAccess < ' config > , ConfigError > {
233
237
let mut set = HashSet :: new ( ) ;
234
238
for field in fields {
235
- set. insert ( ConfigKeyPart :: Part ( field. to_string ( ) ) ) ;
239
+ set. insert ( KeyKind :: Normal ( field. to_string ( ) ) ) ;
236
240
}
237
- if let Some ( mut v) = config. get_table ( & key. to_config ( ) ) ? {
241
+
242
+ // Assume that if we're deserializing a struct it exhaustively lists all
243
+ // possible fields on this key that we're *supposed* to use, so take
244
+ // this opportunity to warn about any keys that aren't recognized as
245
+ // fields and warn about them.
246
+ if let Some ( mut v) = de. config . get_table ( de. key . as_config_key ( ) ) ? {
238
247
for ( t_key, value) in v. val . drain ( ) {
239
- let part = ConfigKeyPart :: Part ( t_key) ;
240
- if !set. contains ( & part) {
241
- config. shell ( ) . warn ( format ! (
242
- "unused key `{}` in config file `{}`" ,
243
- key. join( part) . to_config( ) ,
244
- value. definition_path( ) . display( )
245
- ) ) ?;
248
+ if set. contains ( & KeyKind :: Normal ( t_key. to_string ( ) ) ) {
249
+ continue ;
246
250
}
251
+ de. config . shell ( ) . warn ( format ! (
252
+ "unused key `{}.{}` in config file `{}`" ,
253
+ de. key. as_config_key( ) ,
254
+ t_key,
255
+ value. definition_path( ) . display( )
256
+ ) ) ?;
247
257
}
248
258
}
259
+
249
260
Ok ( ConfigMapAccess {
250
- config,
251
- key,
261
+ de,
252
262
set_iter : set. into_iter ( ) ,
253
263
next : None ,
254
264
} )
@@ -264,9 +274,12 @@ impl<'de, 'config> de::MapAccess<'de> for ConfigMapAccess<'config> {
264
274
{
265
275
match self . set_iter . next ( ) {
266
276
Some ( key) => {
267
- let de_key = key. to_config ( ) ;
277
+ let name = match & key {
278
+ KeyKind :: Normal ( s) | KeyKind :: CaseSensitive ( s) => s. as_str ( ) ,
279
+ } ;
280
+ let result = seed. deserialize ( name. into_deserializer ( ) ) . map ( Some ) ;
268
281
self . next = Some ( key) ;
269
- seed . deserialize ( de_key . into_deserializer ( ) ) . map ( Some )
282
+ return result ;
270
283
}
271
284
None => Ok ( None ) ,
272
285
}
@@ -276,12 +289,16 @@ impl<'de, 'config> de::MapAccess<'de> for ConfigMapAccess<'config> {
276
289
where
277
290
V : de:: DeserializeSeed < ' de > ,
278
291
{
279
- let next_key = self . next . take ( ) . expect ( "next field missing" ) ;
280
- let next_key = self . key . join ( next_key) ;
281
- seed. deserialize ( Deserializer {
282
- config : self . config ,
283
- key : next_key,
284
- } )
292
+ match self . next . take ( ) . expect ( "next field missing" ) {
293
+ KeyKind :: Normal ( key) => self . de . key . push ( & key) ,
294
+ KeyKind :: CaseSensitive ( key) => self . de . key . push_sensitive ( & key) ,
295
+ }
296
+ let result = seed. deserialize ( Deserializer {
297
+ config : self . de . config ,
298
+ key : self . de . key . clone ( ) ,
299
+ } ) ;
300
+ self . de . key . pop ( ) ;
301
+ return result;
285
302
}
286
303
}
287
304
@@ -290,34 +307,32 @@ struct ConfigSeqAccess {
290
307
}
291
308
292
309
impl ConfigSeqAccess {
293
- fn new ( config : & Config , key : & ConfigKey ) -> Result < ConfigSeqAccess , ConfigError > {
310
+ fn new ( de : Deserializer < ' _ > ) -> Result < ConfigSeqAccess , ConfigError > {
294
311
let mut res = Vec :: new ( ) ;
295
- if let Some ( v) = config. get_list ( & key. to_config ( ) ) ? {
312
+ if let Some ( v) = de . config . get_list ( de . key . as_config_key ( ) ) ? {
296
313
for ( s, path) in v. val {
297
314
res. push ( ( s, Definition :: Path ( path) ) ) ;
298
315
}
299
316
}
300
317
301
- if config. cli_unstable ( ) . advanced_env {
318
+ if de . config . cli_unstable ( ) . advanced_env {
302
319
// Parse an environment string as a TOML array.
303
- let env_key = key. to_env ( ) ;
304
- let def = Definition :: Environment ( env_key. clone ( ) ) ;
305
- if let Some ( v) = config. env . get ( & env_key) {
320
+ if let Some ( v) = de. config . env . get ( de. key . as_env_key ( ) ) {
321
+ let def = Definition :: Environment ( de. key . as_env_key ( ) . to_string ( ) ) ;
306
322
if !( v. starts_with ( '[' ) && v. ends_with ( ']' ) ) {
307
323
return Err ( ConfigError :: new (
308
324
format ! ( "should have TOML list syntax, found `{}`" , v) ,
309
325
def,
310
326
) ) ;
311
327
}
312
- let temp_key = key. last ( ) . to_env ( ) ;
313
- let toml_s = format ! ( "{}={}" , temp_key, v) ;
328
+ let toml_s = format ! ( "value={}" , v) ;
314
329
let toml_v: toml:: Value = toml:: de:: from_str ( & toml_s) . map_err ( |e| {
315
330
ConfigError :: new ( format ! ( "could not parse TOML list: {}" , e) , def. clone ( ) )
316
331
} ) ?;
317
332
let values = toml_v
318
333
. as_table ( )
319
334
. unwrap ( )
320
- . get ( & temp_key )
335
+ . get ( "value" )
321
336
. unwrap ( )
322
337
. as_array ( )
323
338
. expect ( "env var was not array" ) ;
@@ -353,3 +368,47 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
353
368
}
354
369
}
355
370
}
371
+
372
+ struct ValueDeserializer < ' config > {
373
+ hits : u32 ,
374
+ deserializer : Deserializer < ' config > ,
375
+ }
376
+
377
+ impl < ' de , ' config > de:: MapAccess < ' de > for ValueDeserializer < ' config > {
378
+ type Error = ConfigError ;
379
+
380
+ fn next_key_seed < K > ( & mut self , seed : K ) -> Result < Option < K :: Value > , Self :: Error >
381
+ where
382
+ K : de:: DeserializeSeed < ' de > ,
383
+ {
384
+ self . hits += 1 ;
385
+ match self . hits {
386
+ 1 => seed
387
+ . deserialize ( value:: VALUE_FIELD . into_deserializer ( ) )
388
+ . map ( Some ) ,
389
+ 2 => seed
390
+ . deserialize ( value:: DEFINITION_FIELD . into_deserializer ( ) )
391
+ . map ( Some ) ,
392
+ _ => Ok ( None ) ,
393
+ }
394
+ }
395
+
396
+ fn next_value_seed < V > ( & mut self , seed : V ) -> Result < V :: Value , Self :: Error >
397
+ where
398
+ V : de:: DeserializeSeed < ' de > ,
399
+ {
400
+ if self . hits == 1 {
401
+ seed. deserialize ( Deserializer {
402
+ config : self . deserializer . config ,
403
+ key : self . deserializer . key . clone ( ) ,
404
+ } )
405
+ } else {
406
+ // let env = self.deserializer.key.to_env();
407
+ // if self.deserializer.config.env.contains_key(&env) {
408
+ // } else {
409
+ // }
410
+ // if let someself.deserializer.config.get_env(&self.deserializer.key)
411
+ panic ! ( )
412
+ }
413
+ }
414
+ }
0 commit comments