@@ -4,15 +4,22 @@ use crate::util::config::value;
44use crate :: util:: config:: { Config , ConfigError , ConfigKey } ;
55use crate :: util:: config:: { ConfigValue as CV , Definition , Value } ;
66use serde:: { de, de:: IntoDeserializer } ;
7- use std:: collections:: HashSet ;
87use std:: vec;
98
109/// Serde deserializer used to convert config values to a target type using
1110/// `Config::get`.
1211#[ derive( Clone ) ]
13- pub ( crate ) struct Deserializer < ' config > {
14- pub ( crate ) config : & ' config Config ,
15- pub ( crate ) key : ConfigKey ,
12+ pub ( super ) struct Deserializer < ' config > {
13+ pub ( super ) config : & ' config Config ,
14+ /// The current key being deserialized.
15+ pub ( super ) key : ConfigKey ,
16+ /// Whether or not this key part is allowed to be an inner table. For
17+ /// example, `profile.dev.build-override` needs to check if
18+ /// CARGO_PROFILE_DEV_BUILD_OVERRIDE_ prefixes exist. But
19+ /// CARGO_BUILD_TARGET should not check for prefixes because it would
20+ /// collide with CARGO_BUILD_TARGET_DIR. See `ConfigMapAccess` for
21+ /// details.
22+ pub ( super ) env_prefix_ok : bool ,
1623}
1724
1825macro_rules! deserialize_method {
@@ -109,7 +116,7 @@ impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
109116 where
110117 V : de:: Visitor < ' de > ,
111118 {
112- if self . config . has_key ( & self . key ) {
119+ if self . config . has_key ( & self . key , self . env_prefix_ok ) {
113120 visitor. visit_some ( self )
114121 } else {
115122 // Treat missing values as `None`.
@@ -179,8 +186,10 @@ impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
179186
180187struct ConfigMapAccess < ' config > {
181188 de : Deserializer < ' config > ,
182- set_iter : <HashSet < KeyKind > as IntoIterator >:: IntoIter ,
183- next : Option < KeyKind > ,
189+ /// The fields that this map should deserialize.
190+ fields : Vec < KeyKind > ,
191+ /// Current field being deserialized.
192+ field_index : usize ,
184193}
185194
186195#[ derive( Debug , PartialEq , Eq , Hash ) ]
@@ -191,50 +200,53 @@ enum KeyKind {
191200
192201impl < ' config > ConfigMapAccess < ' config > {
193202 fn new_map ( de : Deserializer < ' config > ) -> Result < ConfigMapAccess < ' config > , ConfigError > {
194- let mut set = HashSet :: new ( ) ;
203+ let mut fields = Vec :: new ( ) ;
195204 if let Some ( mut v) = de. config . get_table ( & de. key ) ? {
196205 // `v: Value<HashMap<String, CV>>`
197206 for ( key, _value) in v. val . drain ( ) {
198- set . insert ( KeyKind :: CaseSensitive ( key) ) ;
207+ fields . push ( KeyKind :: CaseSensitive ( key) ) ;
199208 }
200209 }
201210 if de. config . cli_unstable ( ) . advanced_env {
202211 // `CARGO_PROFILE_DEV_PACKAGE_`
203- let env_pattern = format ! ( "{}_" , de. key. as_env_key( ) ) ;
212+ let env_prefix = format ! ( "{}_" , de. key. as_env_key( ) ) ;
204213 for env_key in de. config . env . keys ( ) {
205- if env_key. starts_with ( & env_pattern ) {
214+ if env_key. starts_with ( & env_prefix ) {
206215 // `CARGO_PROFILE_DEV_PACKAGE_bar_OPT_LEVEL = 3`
207- let rest = & env_key[ env_pattern . len ( ) ..] ;
216+ let rest = & env_key[ env_prefix . len ( ) ..] ;
208217 // `rest = bar_OPT_LEVEL`
209218 let part = rest. splitn ( 2 , '_' ) . next ( ) . unwrap ( ) ;
210219 // `part = "bar"`
211- set . insert ( KeyKind :: CaseSensitive ( part. to_string ( ) ) ) ;
220+ fields . push ( KeyKind :: CaseSensitive ( part. to_string ( ) ) ) ;
212221 }
213222 }
214223 }
215224 Ok ( ConfigMapAccess {
216225 de,
217- set_iter : set . into_iter ( ) ,
218- next : None ,
226+ fields ,
227+ field_index : 0 ,
219228 } )
220229 }
221230
222231 fn new_struct (
223232 de : Deserializer < ' config > ,
224233 fields : & ' static [ & ' static str ] ,
225234 ) -> Result < ConfigMapAccess < ' config > , ConfigError > {
226- let mut set = HashSet :: new ( ) ;
227- for field in fields {
228- set . insert ( KeyKind :: Normal ( field. to_string ( ) ) ) ;
229- }
235+ let fields : Vec < KeyKind > = fields
236+ . iter ( )
237+ . map ( |field| KeyKind :: Normal ( field. to_string ( ) ) )
238+ . collect ( ) ;
230239
231240 // Assume that if we're deserializing a struct it exhaustively lists all
232241 // possible fields on this key that we're *supposed* to use, so take
233242 // this opportunity to warn about any keys that aren't recognized as
234243 // fields and warn about them.
235244 if let Some ( mut v) = de. config . get_table ( & de. key ) ? {
236245 for ( t_key, value) in v. val . drain ( ) {
237- if set. contains ( & KeyKind :: Normal ( t_key. to_string ( ) ) ) {
246+ if fields. iter ( ) . any ( |k| match k {
247+ KeyKind :: Normal ( s) => s == & t_key,
248+ KeyKind :: CaseSensitive ( s) => s == & t_key,
249+ } ) {
238250 continue ;
239251 }
240252 de. config . shell ( ) . warn ( format ! (
@@ -248,8 +260,8 @@ impl<'config> ConfigMapAccess<'config> {
248260
249261 Ok ( ConfigMapAccess {
250262 de,
251- set_iter : set . into_iter ( ) ,
252- next : None ,
263+ fields ,
264+ field_index : 0 ,
253265 } )
254266 }
255267}
@@ -261,30 +273,61 @@ impl<'de, 'config> de::MapAccess<'de> for ConfigMapAccess<'config> {
261273 where
262274 K : de:: DeserializeSeed < ' de > ,
263275 {
264- match self . set_iter . next ( ) {
265- Some ( key) => {
266- let name = match & key {
267- KeyKind :: Normal ( s) | KeyKind :: CaseSensitive ( s) => s. as_str ( ) ,
268- } ;
269- let result = seed. deserialize ( name. into_deserializer ( ) ) . map ( Some ) ;
270- self . next = Some ( key) ;
271- result
272- }
273- None => Ok ( None ) ,
276+ if self . field_index >= self . fields . len ( ) {
277+ return Ok ( None ) ;
274278 }
279+ let field = match & self . fields [ self . field_index ] {
280+ KeyKind :: Normal ( s) | KeyKind :: CaseSensitive ( s) => s. as_str ( ) ,
281+ } ;
282+ seed. deserialize ( field. into_deserializer ( ) ) . map ( Some )
275283 }
276284
277285 fn next_value_seed < V > ( & mut self , seed : V ) -> Result < V :: Value , Self :: Error >
278286 where
279287 V : de:: DeserializeSeed < ' de > ,
280288 {
281- match self . next . take ( ) . expect ( "next field missing" ) {
282- KeyKind :: Normal ( key) => self . de . key . push ( & key) ,
283- KeyKind :: CaseSensitive ( key) => self . de . key . push_sensitive ( & key) ,
284- }
289+ let field = & self . fields [ self . field_index ] ;
290+ self . field_index += 1 ;
291+ // Set this as the current key in the deserializer.
292+ let field = match field {
293+ KeyKind :: Normal ( field) => {
294+ self . de . key . push ( & field) ;
295+ field
296+ }
297+ KeyKind :: CaseSensitive ( field) => {
298+ self . de . key . push_sensitive ( & field) ;
299+ field
300+ }
301+ } ;
302+ // Env vars that are a prefix of another with a dash/underscore cannot
303+ // be supported by our serde implementation, so check for them here.
304+ // Example:
305+ // CARGO_BUILD_TARGET
306+ // CARGO_BUILD_TARGET_DIR
307+ // or
308+ // CARGO_PROFILE_DEV_DEBUG
309+ // CARGO_PROFILE_DEV_DEBUG_ASSERTIONS
310+ // The `deserialize_option` method does not know the type of the field.
311+ // If the type is an Option<struct> (like
312+ // `profile.dev.build-override`), then it needs to check for env vars
313+ // starting with CARGO_FOO_BAR_. This is a problem for keys like
314+ // CARGO_BUILD_TARGET because checking for a prefix would incorrectly
315+ // match CARGO_BUILD_TARGET_DIR. `deserialize_option` would have no
316+ // choice but to call `visit_some()` which would then fail if
317+ // CARGO_BUILD_TARGET isn't set. So we check for these prefixes and
318+ // disallow them here.
319+ let env_prefix = format ! ( "{}_" , field) . replace ( '-' , "_" ) ;
320+ let env_prefix_ok = !self . fields . iter ( ) . any ( |field| {
321+ let field = match field {
322+ KeyKind :: Normal ( s) | KeyKind :: CaseSensitive ( s) => s. as_str ( ) ,
323+ } ;
324+ field. replace ( '-' , "_" ) . starts_with ( & env_prefix)
325+ } ) ;
326+
285327 let result = seed. deserialize ( Deserializer {
286328 config : self . de . config ,
287329 key : self . de . key . clone ( ) ,
330+ env_prefix_ok,
288331 } ) ;
289332 self . de . key . pop ( ) ;
290333 result
0 commit comments