@@ -441,18 +441,34 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
441441 {
442442 match self . list_iter . next ( ) {
443443 // TODO: add `def` to error?
444- Some ( CV :: String ( value , def ) ) => {
444+ Some ( val @ CV :: String ( .. ) ) => {
445445 // This might be a String or a Value<String>.
446- // ValueDeserializer will handle figuring out which one it is.
447- let maybe_value_de = ValueDeserializer :: new_with_string ( value, def) ;
448- seed. deserialize ( maybe_value_de) . map ( Some )
446+ // ArrayItemDeserializer will handle figuring out which one it is.
447+ seed. deserialize ( ArrayItemDeserializer :: new ( val) ) . map ( Some )
449448 }
450449 Some ( val) => Err ( ConfigError :: expected ( & self . key , "list of string" , & val) ) ,
451450 None => Ok ( None ) ,
452451 }
453452 }
454453}
455454
455+ /// Source of data for [`ValueDeserializer`]
456+ enum ValueSource < ' gctx > {
457+ /// The deserializer used to actually deserialize a Value struct.
458+ Deserializer {
459+ de : Deserializer < ' gctx > ,
460+ definition : Definition ,
461+ } ,
462+ /// A [`ConfigValue`](CV).
463+ ///
464+ /// This is used for situations where you can't address a string via a TOML key,
465+ /// such as a string inside an array.
466+ /// The [`ConfigSeqAccess`] doesn't know if the type it should deserialize to
467+ /// is a `String` or `Value<String>`,
468+ /// so [`ArrayItemDeserializer`] needs to be able to handle both.
469+ ConfigValue ( CV ) ,
470+ }
471+
456472/// This is a deserializer that deserializes into a `Value<T>` for
457473/// configuration.
458474///
@@ -462,18 +478,7 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
462478/// See more comments in `value.rs` for the protocol used here.
463479struct ValueDeserializer < ' gctx > {
464480 hits : u32 ,
465- definition : Definition ,
466- /// The deserializer, used to actually deserialize a Value struct.
467- /// This is `None` if deserializing a string.
468- de : Option < Deserializer < ' gctx > > ,
469- /// A string value to deserialize.
470- ///
471- /// This is used for situations where you can't address a string via a
472- /// TOML key, such as a string inside an array. The `ConfigSeqAccess`
473- /// doesn't know if the type it should deserialize to is a `String` or
474- /// `Value<String>`, so `ValueDeserializer` needs to be able to handle
475- /// both.
476- str_value : Option < String > ,
481+ source : ValueSource < ' gctx > ,
477482}
478483
479484impl < ' gctx > ValueDeserializer < ' gctx > {
@@ -498,20 +503,24 @@ impl<'gctx> ValueDeserializer<'gctx> {
498503 ( _, None ) => env_def,
499504 }
500505 } ;
506+
501507 Ok ( ValueDeserializer {
502508 hits : 0 ,
503- definition,
504- de : Some ( de) ,
505- str_value : None ,
509+ source : ValueSource :: Deserializer { de, definition } ,
506510 } )
507511 }
508512
509- fn new_with_string ( s : String , definition : Definition ) -> ValueDeserializer < ' gctx > {
513+ fn with_cv ( cv : CV ) -> ValueDeserializer < ' gctx > {
510514 ValueDeserializer {
511515 hits : 0 ,
512- definition,
513- de : None ,
514- str_value : Some ( s) ,
516+ source : ValueSource :: ConfigValue ( cv) ,
517+ }
518+ }
519+
520+ fn definition ( & self ) -> & Definition {
521+ match & self . source {
522+ ValueSource :: Deserializer { definition, .. } => definition,
523+ ValueSource :: ConfigValue ( cv) => cv. definition ( ) ,
515524 }
516525 }
517526}
@@ -542,19 +551,19 @@ impl<'de, 'gctx> de::MapAccess<'de> for ValueDeserializer<'gctx> {
542551 // If this is the first time around we deserialize the `value` field
543552 // which is the actual deserializer
544553 if self . hits == 1 {
545- if let Some ( de ) = & self . de {
546- return seed
554+ return match & self . source {
555+ ValueSource :: Deserializer { de , definition } => seed
547556 . deserialize ( de. clone ( ) )
548- . map_err ( |e| e. with_key_context ( & de. key , Some ( self . definition . clone ( ) ) ) ) ;
549- } else {
550- return seed
551- . deserialize ( self . str_value . as_ref ( ) . unwrap ( ) . clone ( ) . into_deserializer ( ) ) ;
552- }
557+ . map_err ( |e| e. with_key_context ( & de. key , Some ( definition. clone ( ) ) ) ) ,
558+ ValueSource :: ConfigValue ( cv ) => {
559+ seed. deserialize ( ArrayItemDeserializer :: new ( cv . clone ( ) ) )
560+ }
561+ } ;
553562 }
554563
555564 // ... otherwise we're deserializing the `definition` field, so we need
556565 // to figure out where the field we just deserialized was defined at.
557- match & self . definition {
566+ match self . definition ( ) {
558567 Definition :: Path ( path) => {
559568 seed. deserialize ( Tuple2Deserializer ( 0i32 , path. to_string_lossy ( ) ) )
560569 }
@@ -572,25 +581,45 @@ impl<'de, 'gctx> de::MapAccess<'de> for ValueDeserializer<'gctx> {
572581 }
573582}
574583
575- // Deserializer is only implemented to handle deserializing a String inside a
576- // sequence (like `Vec<String>` or `Vec<Value<String>>`). `Value<String>` is
577- // handled by deserialize_struct, and the plain `String` is handled by all the
578- // other functions here.
579- impl < ' de , ' gctx > de:: Deserializer < ' de > for ValueDeserializer < ' gctx > {
584+ /// A deserializer for individual [`ConfigValue`](CV) items in arrays
585+ ///
586+ /// This deserializer is only implemented to handle deserializing a String
587+ /// inside a sequence (like `Vec<String>` or `Vec<Value<String>>`).
588+ /// `Value<String>` is handled by `deserialize_struct` in [`ValueDeserializer`],
589+ /// and the plain `String` is handled by all the other functions here.
590+ #[ derive( Clone ) ]
591+ struct ArrayItemDeserializer {
592+ cv : CV ,
593+ }
594+
595+ impl ArrayItemDeserializer {
596+ fn new ( cv : CV ) -> Self {
597+ Self { cv }
598+ }
599+
600+ fn into_inner ( self ) -> String {
601+ match self . cv {
602+ CV :: String ( s, _def) => s,
603+ _ => unreachable ! ( "string expected" ) ,
604+ }
605+ }
606+ }
607+
608+ impl < ' de > de:: Deserializer < ' de > for ArrayItemDeserializer {
580609 type Error = ConfigError ;
581610
582611 fn deserialize_str < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
583612 where
584613 V : de:: Visitor < ' de > ,
585614 {
586- visitor. visit_str ( & self . str_value . expect ( "string expected" ) )
615+ visitor. visit_str ( & self . into_inner ( ) )
587616 }
588617
589618 fn deserialize_string < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
590619 where
591620 V : de:: Visitor < ' de > ,
592621 {
593- visitor. visit_string ( self . str_value . expect ( "string expected" ) )
622+ visitor. visit_string ( self . into_inner ( ) )
594623 }
595624
596625 fn deserialize_struct < V > (
@@ -607,7 +636,7 @@ impl<'de, 'gctx> de::Deserializer<'de> for ValueDeserializer<'gctx> {
607636 //
608637 // See more comments in `value.rs` for the protocol used here.
609638 if name == value:: NAME && fields == value:: FIELDS {
610- return visitor. visit_map ( self ) ;
639+ return visitor. visit_map ( ValueDeserializer :: with_cv ( self . cv ) ) ;
611640 }
612641 unimplemented ! ( "only strings and Value can be deserialized from a sequence" ) ;
613642 }
@@ -616,7 +645,7 @@ impl<'de, 'gctx> de::Deserializer<'de> for ValueDeserializer<'gctx> {
616645 where
617646 V : de:: Visitor < ' de > ,
618647 {
619- visitor. visit_string ( self . str_value . expect ( "string expected" ) )
648+ visitor. visit_string ( self . into_inner ( ) )
620649 }
621650
622651 fn deserialize_ignored_any < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
0 commit comments