2121//!
2222//! [`ConfigValue`]: CV
2323
24+ use crate :: util:: context:: key:: ArrayItemKeyPath ;
2425use crate :: util:: context:: value;
2526use crate :: util:: context:: { ConfigError , ConfigKey , GlobalContext } ;
2627use crate :: util:: context:: { ConfigValue as CV , Definition , Value } ;
@@ -425,12 +426,13 @@ impl<'de, 'gctx> de::MapAccess<'de> for ConfigMapAccess<'gctx> {
425426 }
426427}
427428
428- struct ConfigSeqAccess {
429- list_iter : vec:: IntoIter < CV > ,
429+ struct ConfigSeqAccess < ' gctx > {
430+ de : Deserializer < ' gctx > ,
431+ list_iter : std:: iter:: Enumerate < vec:: IntoIter < CV > > ,
430432}
431433
432- impl ConfigSeqAccess {
433- fn new ( de : Deserializer < ' _ > ) -> Result < ConfigSeqAccess , ConfigError > {
434+ impl ConfigSeqAccess < ' _ > {
435+ fn new ( de : Deserializer < ' _ > ) -> Result < ConfigSeqAccess < ' _ > , ConfigError > {
434436 let mut res = Vec :: new ( ) ;
435437
436438 match de. gctx . get_cv ( & de. key ) ? {
@@ -446,27 +448,44 @@ impl ConfigSeqAccess {
446448 de. gctx . get_env_list ( & de. key , & mut res) ?;
447449
448450 Ok ( ConfigSeqAccess {
449- list_iter : res. into_iter ( ) ,
451+ de,
452+ list_iter : res. into_iter ( ) . enumerate ( ) ,
450453 } )
451454 }
452455}
453456
454- impl < ' de > de:: SeqAccess < ' de > for ConfigSeqAccess {
457+ impl < ' de , ' gctx > de:: SeqAccess < ' de > for ConfigSeqAccess < ' gctx > {
455458 type Error = ConfigError ;
456459
457460 fn next_element_seed < T > ( & mut self , seed : T ) -> Result < Option < T :: Value > , Self :: Error >
458461 where
459462 T : de:: DeserializeSeed < ' de > ,
460463 {
461464 match self . list_iter . next ( ) {
462- Some ( val) => seed. deserialize ( ArrayItemDeserializer :: new ( val) ) . map ( Some ) ,
465+ Some ( ( i, cv) ) => {
466+ let mut key_path = ArrayItemKeyPath :: new ( self . de . key . clone ( ) ) ;
467+ let definition = Some ( cv. definition ( ) . clone ( ) ) ;
468+ let de = ArrayItemDeserializer {
469+ cv,
470+ key_path : & mut key_path,
471+ } ;
472+ seed. deserialize ( de)
473+ . map_err ( |e| {
474+ // This along with ArrayItemKeyPath provide a better error context of the
475+ // ConfigValue definition + the key path within an array item that native
476+ // TOML key path can't express. For example, `foo.bar[3].baz`.
477+ key_path. push_index ( i) ;
478+ e. with_array_item_key_context ( & key_path, definition)
479+ } )
480+ . map ( Some )
481+ }
463482 None => Ok ( None ) ,
464483 }
465484 }
466485}
467486
468487/// Source of data for [`ValueDeserializer`]
469- enum ValueSource < ' gctx > {
488+ enum ValueSource < ' gctx , ' err > {
470489 /// The deserializer used to actually deserialize a Value struct.
471490 Deserializer {
472491 de : Deserializer < ' gctx > ,
@@ -478,11 +497,14 @@ enum ValueSource<'gctx> {
478497 /// such as a value inside an array.
479498 /// The [`ConfigSeqAccess`] doesn't know what type it should deserialize to
480499 /// so [`ArrayItemDeserializer`] needs to be able to handle all of them.
481- ConfigValue ( CV ) ,
500+ ConfigValue {
501+ cv : CV ,
502+ key_path : & ' err mut ArrayItemKeyPath ,
503+ } ,
482504}
483505
484- impl < ' gctx > ValueSource < ' gctx > {
485- fn with_deserializer ( de : Deserializer < ' gctx > ) -> Result < ValueSource < ' gctx > , ConfigError > {
506+ impl < ' gctx , ' err > ValueSource < ' gctx , ' err > {
507+ fn with_deserializer ( de : Deserializer < ' gctx > ) -> Result < ValueSource < ' gctx , ' err > , ConfigError > {
486508 // Figure out where this key is defined.
487509 let definition = {
488510 let env = de. key . as_env_key ( ) ;
@@ -507,8 +529,8 @@ impl<'gctx> ValueSource<'gctx> {
507529 Ok ( Self :: Deserializer { de, definition } )
508530 }
509531
510- fn with_cv ( cv : CV ) -> Self {
511- Self :: ConfigValue ( cv )
532+ fn with_cv ( cv : CV , key_path : & ' err mut ArrayItemKeyPath ) -> ValueSource < ' gctx , ' err > {
533+ ValueSource :: ConfigValue { cv , key_path }
512534 }
513535}
514536
@@ -519,25 +541,25 @@ impl<'gctx> ValueSource<'gctx> {
519541/// fields into the location that this configuration value was defined in.
520542///
521543/// See more comments in `value.rs` for the protocol used here.
522- struct ValueDeserializer < ' gctx > {
544+ struct ValueDeserializer < ' gctx , ' err > {
523545 hits : u32 ,
524- source : ValueSource < ' gctx > ,
546+ source : ValueSource < ' gctx , ' err > ,
525547}
526548
527- impl < ' gctx > ValueDeserializer < ' gctx > {
528- fn new ( source : ValueSource < ' gctx > ) -> ValueDeserializer < ' gctx > {
549+ impl < ' gctx , ' err > ValueDeserializer < ' gctx , ' err > {
550+ fn new ( source : ValueSource < ' gctx , ' err > ) -> ValueDeserializer < ' gctx , ' err > {
529551 Self { hits : 0 , source }
530552 }
531553
532554 fn definition ( & self ) -> & Definition {
533555 match & self . source {
534556 ValueSource :: Deserializer { definition, .. } => definition,
535- ValueSource :: ConfigValue ( cv ) => cv. definition ( ) ,
557+ ValueSource :: ConfigValue { cv , .. } => cv. definition ( ) ,
536558 }
537559 }
538560}
539561
540- impl < ' de , ' gctx > de:: MapAccess < ' de > for ValueDeserializer < ' gctx > {
562+ impl < ' de , ' gctx , ' err > de:: MapAccess < ' de > for ValueDeserializer < ' gctx , ' err > {
541563 type Error = ConfigError ;
542564
543565 fn next_key_seed < K > ( & mut self , seed : K ) -> Result < Option < K :: Value > , Self :: Error >
@@ -563,12 +585,16 @@ impl<'de, 'gctx> de::MapAccess<'de> for ValueDeserializer<'gctx> {
563585 // If this is the first time around we deserialize the `value` field
564586 // which is the actual deserializer
565587 if self . hits == 1 {
566- return match & self . source {
588+ return match & mut self . source {
567589 ValueSource :: Deserializer { de, definition } => seed
568590 . deserialize ( de. clone ( ) )
569591 . map_err ( |e| e. with_key_context ( & de. key , Some ( definition. clone ( ) ) ) ) ,
570- ValueSource :: ConfigValue ( cv) => {
571- seed. deserialize ( ArrayItemDeserializer :: new ( cv. clone ( ) ) )
592+ ValueSource :: ConfigValue { cv, key_path } => {
593+ let de = ArrayItemDeserializer {
594+ cv : cv. clone ( ) ,
595+ key_path,
596+ } ;
597+ seed. deserialize ( de)
572598 }
573599 } ;
574600 }
@@ -598,18 +624,12 @@ impl<'de, 'gctx> de::MapAccess<'de> for ValueDeserializer<'gctx> {
598624///
599625/// It is implemented to handle any types inside a sequence, like `Vec<String>`,
600626/// `Vec<Value<i32>>`, or even `Vev<HashMap<String, Vec<bool>>>`.
601- #[ derive( Clone ) ]
602- struct ArrayItemDeserializer {
627+ struct ArrayItemDeserializer < ' err > {
603628 cv : CV ,
629+ key_path : & ' err mut ArrayItemKeyPath ,
604630}
605631
606- impl ArrayItemDeserializer {
607- fn new ( cv : CV ) -> Self {
608- Self { cv }
609- }
610- }
611-
612- impl < ' de > de:: Deserializer < ' de > for ArrayItemDeserializer {
632+ impl < ' de , ' err > de:: Deserializer < ' de > for ArrayItemDeserializer < ' err > {
613633 type Error = ConfigError ;
614634
615635 fn deserialize_struct < V > (
@@ -626,10 +646,14 @@ impl<'de> de::Deserializer<'de> for ArrayItemDeserializer {
626646 //
627647 // See more comments in `value.rs` for the protocol used here.
628648 if name == value:: NAME && fields == value:: FIELDS {
629- let source = ValueSource :: with_cv ( self . cv ) ;
649+ let source = ValueSource :: with_cv ( self . cv , self . key_path ) ;
630650 return visitor. visit_map ( ValueDeserializer :: new ( source) ) ;
631651 }
632- visitor. visit_map ( ArrayItemMapAccess :: with_struct ( self . cv , fields) )
652+ visitor. visit_map ( ArrayItemMapAccess :: with_struct (
653+ self . cv ,
654+ fields,
655+ self . key_path ,
656+ ) )
633657 }
634658
635659 fn deserialize_any < V > ( self , visitor : V ) -> Result < V :: Value , Self :: Error >
@@ -640,8 +664,8 @@ impl<'de> de::Deserializer<'de> for ArrayItemDeserializer {
640664 CV :: String ( s, _) => visitor. visit_string ( s) ,
641665 CV :: Integer ( i, _) => visitor. visit_i64 ( i) ,
642666 CV :: Boolean ( b, _) => visitor. visit_bool ( b) ,
643- l @ CV :: List ( _, _) => visitor. visit_seq ( ArrayItemSeqAccess :: new ( l) ) ,
644- t @ CV :: Table ( _, _) => visitor. visit_map ( ArrayItemMapAccess :: new ( t) ) ,
667+ l @ CV :: List ( _, _) => visitor. visit_seq ( ArrayItemSeqAccess :: new ( l, self . key_path ) ) ,
668+ t @ CV :: Table ( _, _) => visitor. visit_map ( ArrayItemMapAccess :: new ( t, self . key_path ) ) ,
645669 }
646670 }
647671
@@ -654,46 +678,53 @@ impl<'de> de::Deserializer<'de> for ArrayItemDeserializer {
654678}
655679
656680/// Sequence access for nested arrays within [`ArrayItemDeserializer`]
657- struct ArrayItemSeqAccess {
658- items : vec:: IntoIter < CV > ,
681+ struct ArrayItemSeqAccess < ' err > {
682+ items : std:: iter:: Enumerate < vec:: IntoIter < CV > > ,
683+ key_path : & ' err mut ArrayItemKeyPath ,
659684}
660685
661- impl ArrayItemSeqAccess {
662- fn new ( cv : CV ) -> Self {
686+ impl < ' err > ArrayItemSeqAccess < ' err > {
687+ fn new ( cv : CV , key_path : & ' err mut ArrayItemKeyPath ) -> ArrayItemSeqAccess < ' err > {
663688 let items = match cv {
664- CV :: List ( list, _) => list. into_iter ( ) ,
689+ CV :: List ( list, _) => list. into_iter ( ) . enumerate ( ) ,
665690 _ => unreachable ! ( "must be a list" ) ,
666691 } ;
667- Self { items }
692+ Self { items, key_path }
668693 }
669694}
670695
671- impl < ' de > de:: SeqAccess < ' de > for ArrayItemSeqAccess {
696+ impl < ' de , ' err > de:: SeqAccess < ' de > for ArrayItemSeqAccess < ' err > {
672697 type Error = ConfigError ;
673698
674699 fn next_element_seed < T > ( & mut self , seed : T ) -> Result < Option < T :: Value > , Self :: Error >
675700 where
676701 T : de:: DeserializeSeed < ' de > ,
677702 {
678703 match self . items . next ( ) {
679- Some ( cv) => {
680- let deserializer = ArrayItemDeserializer :: new ( cv) ;
681- seed. deserialize ( deserializer) . map ( Some )
704+ Some ( ( i, cv) ) => {
705+ let de = ArrayItemDeserializer {
706+ cv,
707+ key_path : self . key_path ,
708+ } ;
709+ seed. deserialize ( de)
710+ . inspect_err ( |_| self . key_path . push_index ( i) )
711+ . map ( Some )
682712 }
683713 None => Ok ( None ) ,
684714 }
685715 }
686716}
687717
688718/// Map access for nested tables within [`ArrayItemDeserializer`]
689- struct ArrayItemMapAccess {
719+ struct ArrayItemMapAccess < ' err > {
690720 cv : CV ,
691721 keys : vec:: IntoIter < String > ,
692722 current_key : Option < String > ,
723+ key_path : & ' err mut ArrayItemKeyPath ,
693724}
694725
695- impl ArrayItemMapAccess {
696- fn new ( cv : CV ) -> Self {
726+ impl < ' err > ArrayItemMapAccess < ' err > {
727+ fn new ( cv : CV , key_path : & ' err mut ArrayItemKeyPath ) -> Self {
697728 let keys = match & cv {
698729 CV :: Table ( map, _) => map. keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) . into_iter ( ) ,
699730 _ => unreachable ! ( "must be a map" ) ,
@@ -702,10 +733,11 @@ impl ArrayItemMapAccess {
702733 cv,
703734 keys,
704735 current_key : None ,
736+ key_path,
705737 }
706738 }
707739
708- fn with_struct ( cv : CV , given_fields : & [ & str ] ) -> Self {
740+ fn with_struct ( cv : CV , given_fields : & [ & str ] , key_path : & ' err mut ArrayItemKeyPath ) -> Self {
709741 // TODO: We might want to warn unused fields,
710742 // like what we did in ConfigMapAccess::new_struct
711743 let keys = given_fields
@@ -717,11 +749,12 @@ impl ArrayItemMapAccess {
717749 cv,
718750 keys,
719751 current_key : None ,
752+ key_path,
720753 }
721754 }
722755}
723756
724- impl < ' de > de:: MapAccess < ' de > for ArrayItemMapAccess {
757+ impl < ' de , ' err > de:: MapAccess < ' de > for ArrayItemMapAccess < ' err > {
725758 type Error = ConfigError ;
726759
727760 fn next_key_seed < K > ( & mut self , seed : K ) -> Result < Option < K :: Value > , Self :: Error >
@@ -745,8 +778,12 @@ impl<'de> de::MapAccess<'de> for ArrayItemMapAccess {
745778 match & self . cv {
746779 CV :: Table ( map, _) => {
747780 if let Some ( cv) = map. get ( & key) {
748- let deserializer = ArrayItemDeserializer :: new ( cv. clone ( ) ) ;
749- seed. deserialize ( deserializer)
781+ let de = ArrayItemDeserializer {
782+ cv : cv. clone ( ) ,
783+ key_path : self . key_path ,
784+ } ;
785+ seed. deserialize ( de)
786+ . inspect_err ( |_| self . key_path . push_key ( key) )
750787 } else {
751788 Err ( ConfigError :: new (
752789 format ! ( "missing config key `{key}`" ) ,
0 commit comments