@@ -425,8 +425,6 @@ impl<'de, 'gctx> de::MapAccess<'de> for ConfigMapAccess<'gctx> {
425425}
426426
427427struct ConfigSeqAccess {
428- /// The config key to the sequence.
429- key : ConfigKey ,
430428 list_iter : vec:: IntoIter < CV > ,
431429}
432430
@@ -447,7 +445,6 @@ impl ConfigSeqAccess {
447445 de. gctx . get_env_list ( & de. key , & mut res) ?;
448446
449447 Ok ( ConfigSeqAccess {
450- key : de. key ,
451448 list_iter : res. into_iter ( ) ,
452449 } )
453450 }
@@ -461,13 +458,7 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
461458 T : de:: DeserializeSeed < ' de > ,
462459 {
463460 match self . list_iter . next ( ) {
464- // TODO: add `def` to error?
465- Some ( val @ CV :: String ( ..) ) => {
466- // This might be a String or a Value<String>.
467- // ArrayItemDeserializer will handle figuring out which one it is.
468- seed. deserialize ( ArrayItemDeserializer :: new ( val) ) . map ( Some )
469- }
470- Some ( val) => Err ( ConfigError :: expected ( & self . key , "list of string" , & val) ) ,
461+ Some ( val) => seed. deserialize ( ArrayItemDeserializer :: new ( val) ) . map ( Some ) ,
471462 None => Ok ( None ) ,
472463 }
473464 }
@@ -482,11 +473,10 @@ enum ValueSource<'gctx> {
482473 } ,
483474 /// A [`ConfigValue`](CV).
484475 ///
485- /// This is used for situations where you can't address a string via a TOML key,
486- /// such as a string inside an array.
487- /// The [`ConfigSeqAccess`] doesn't know if the type it should deserialize to
488- /// is a `String` or `Value<String>`,
489- /// so [`ArrayItemDeserializer`] needs to be able to handle both.
476+ /// This is used for situations where you can't address type via a TOML key,
477+ /// such as a value inside an array.
478+ /// The [`ConfigSeqAccess`] doesn't know what type it should deserialize to
479+ /// so [`ArrayItemDeserializer`] needs to be able to handle all of them.
490480 ConfigValue ( CV ) ,
491481}
492482
@@ -605,10 +595,8 @@ impl<'de, 'gctx> de::MapAccess<'de> for ValueDeserializer<'gctx> {
605595
606596/// A deserializer for individual [`ConfigValue`](CV) items in arrays
607597///
608- /// This deserializer is only implemented to handle deserializing a String
609- /// inside a sequence (like `Vec<String>` or `Vec<Value<String>>`).
610- /// `Value<String>` is handled by `deserialize_struct` in [`ValueDeserializer`],
611- /// and the plain `String` is handled by all the other functions here.
598+ /// It is implemented to handle any types inside a sequence, like `Vec<String>`,
599+ /// `Vec<Value<i32>>`, or even `Vev<HashMap<String, Vec<bool>>>`.
612600#[ derive( Clone ) ]
613601struct ArrayItemDeserializer {
614602 cv : CV ,
@@ -618,32 +606,11 @@ impl ArrayItemDeserializer {
618606 fn new ( cv : CV ) -> Self {
619607 Self { cv }
620608 }
621-
622- fn into_inner ( self ) -> String {
623- match self . cv {
624- CV :: String ( s, _def) => s,
625- _ => unreachable ! ( "string expected" ) ,
626- }
627- }
628609}
629610
630611impl < ' de > de:: Deserializer < ' de > for ArrayItemDeserializer {
631612 type Error = ConfigError ;
632613
633- fn deserialize_str < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
634- where
635- V : de:: Visitor < ' de > ,
636- {
637- visitor. visit_str ( & self . into_inner ( ) )
638- }
639-
640- fn deserialize_string < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
641- where
642- V : de:: Visitor < ' de > ,
643- {
644- visitor. visit_string ( self . into_inner ( ) )
645- }
646-
647614 fn deserialize_struct < V > (
648615 self ,
649616 name : & ' static str ,
@@ -660,31 +627,136 @@ impl<'de> de::Deserializer<'de> for ArrayItemDeserializer {
660627 if name == value:: NAME && fields == value:: FIELDS {
661628 return visitor. visit_map ( ValueDeserializer :: with_cv ( self . cv ) ) ;
662629 }
663- unimplemented ! ( "only strings and Value can be deserialized from a sequence" ) ;
630+ visitor . visit_map ( ArrayItemMapAccess :: with_struct ( self . cv , fields ) )
664631 }
665632
666633 fn deserialize_any < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
667634 where
668635 V : de:: Visitor < ' de > ,
669636 {
670- visitor. visit_string ( self . into_inner ( ) )
637+ match self . cv {
638+ CV :: String ( s, _) => visitor. visit_string ( s) ,
639+ CV :: Integer ( i, _) => visitor. visit_i64 ( i) ,
640+ CV :: Boolean ( b, _) => visitor. visit_bool ( b) ,
641+ l @ CV :: List ( _, _) => visitor. visit_seq ( ArrayItemSeqAccess :: new ( l) ) ,
642+ t @ CV :: Table ( _, _) => visitor. visit_map ( ArrayItemMapAccess :: new ( t) ) ,
643+ }
644+ }
645+
646+ // Forward everything to deserialize_any
647+ serde:: forward_to_deserialize_any! {
648+ bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
649+ bytes byte_buf map option unit newtype_struct
650+ ignored_any unit_struct tuple_struct tuple enum identifier
651+ }
652+ }
653+
654+ /// Sequence access for nested arrays within [`ArrayItemDeserializer`]
655+ struct ArrayItemSeqAccess {
656+ items : vec:: IntoIter < CV > ,
657+ }
658+
659+ impl ArrayItemSeqAccess {
660+ fn new ( cv : CV ) -> Self {
661+ let items = match cv {
662+ CV :: List ( list, _) => list. into_iter ( ) ,
663+ _ => unreachable ! ( "must be a list" ) ,
664+ } ;
665+ Self { items }
671666 }
667+ }
668+
669+ impl < ' de > de:: SeqAccess < ' de > for ArrayItemSeqAccess {
670+ type Error = ConfigError ;
672671
673- fn deserialize_ignored_any < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
672+ fn next_element_seed < T > ( & mut self , seed : T ) -> Result < Option < T :: Value > , Self :: Error >
674673 where
675- V : de:: Visitor < ' de > ,
674+ T : de:: DeserializeSeed < ' de > ,
676675 {
677- visitor. visit_unit ( )
676+ match self . items . next ( ) {
677+ Some ( cv) => {
678+ let deserializer = ArrayItemDeserializer :: new ( cv) ;
679+ seed. deserialize ( deserializer) . map ( Some )
680+ }
681+ None => Ok ( None ) ,
682+ }
678683 }
684+ }
679685
680- serde:: forward_to_deserialize_any! {
681- i8 i16 i32 i64
682- u8 u16 u32 u64
683- option
684- newtype_struct seq tuple tuple_struct map enum bool
685- f32 f64 char bytes
686- byte_buf unit unit_struct
687- identifier
686+ /// Map access for nested tables within [`ArrayItemDeserializer`]
687+ struct ArrayItemMapAccess {
688+ cv : CV ,
689+ keys : vec:: IntoIter < String > ,
690+ current_key : Option < String > ,
691+ }
692+
693+ impl ArrayItemMapAccess {
694+ fn new ( cv : CV ) -> Self {
695+ let keys = match & cv {
696+ CV :: Table ( map, _) => map. keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) . into_iter ( ) ,
697+ _ => unreachable ! ( "must be a map" ) ,
698+ } ;
699+ Self {
700+ cv,
701+ keys,
702+ current_key : None ,
703+ }
704+ }
705+
706+ fn with_struct ( cv : CV , given_fields : & [ & str ] ) -> Self {
707+ // TODO: We might want to warn unused fields,
708+ // like what we did in ConfigMapAccess::new_struct
709+ let keys = given_fields
710+ . into_iter ( )
711+ . map ( |s| s. to_string ( ) )
712+ . collect :: < Vec < _ > > ( )
713+ . into_iter ( ) ;
714+ Self {
715+ cv,
716+ keys,
717+ current_key : None ,
718+ }
719+ }
720+ }
721+
722+ impl < ' de > de:: MapAccess < ' de > for ArrayItemMapAccess {
723+ type Error = ConfigError ;
724+
725+ fn next_key_seed < K > ( & mut self , seed : K ) -> Result < Option < K :: Value > , Self :: Error >
726+ where
727+ K : de:: DeserializeSeed < ' de > ,
728+ {
729+ match self . keys . next ( ) {
730+ Some ( key) => {
731+ self . current_key = Some ( key. clone ( ) ) ;
732+ seed. deserialize ( key. into_deserializer ( ) ) . map ( Some )
733+ }
734+ None => Ok ( None ) ,
735+ }
736+ }
737+
738+ fn next_value_seed < V > ( & mut self , seed : V ) -> Result < V :: Value , Self :: Error >
739+ where
740+ V : de:: DeserializeSeed < ' de > ,
741+ {
742+ let key = self . current_key . take ( ) . unwrap ( ) ;
743+ match & self . cv {
744+ CV :: Table ( map, _) => {
745+ if let Some ( cv) = map. get ( & key) {
746+ let deserializer = ArrayItemDeserializer :: new ( cv. clone ( ) ) ;
747+ seed. deserialize ( deserializer)
748+ } else {
749+ Err ( ConfigError :: new (
750+ format ! ( "missing config key `{key}`" ) ,
751+ self . cv . definition ( ) . clone ( ) ,
752+ ) )
753+ }
754+ }
755+ _ => Err ( ConfigError :: new (
756+ "expected table" . to_string ( ) ,
757+ self . cv . definition ( ) . clone ( ) ,
758+ ) ) ,
759+ }
688760 }
689761}
690762
0 commit comments