@@ -9,14 +9,27 @@ use serde::{
99 Deserialize , Deserializer ,
1010} ;
1111
12- /// A read-only view into a map of string data
12+ /// A read-only view into a map of string data which may contain multiple values
13+ ///
14+ /// Internally data is always represented as many valued
1315#[ derive( Default , Debug , PartialEq ) ]
14- pub struct StrMap ( pub ( crate ) Arc < HashMap < String , String > > ) ;
16+ pub struct StrMap ( pub ( crate ) Arc < HashMap < String , Vec < String > > > ) ;
1517
1618impl StrMap {
17- /// Return a named value where available
19+ /// Return a named value where available.
20+ /// If there is more than one value associated with this name,
21+ /// the first one will be returned
1822 pub fn get ( & self , key : & str ) -> Option < & str > {
19- self . 0 . get ( key) . map ( |value| value. as_ref ( ) )
23+ self . 0
24+ . get ( key)
25+ . and_then ( |values| values. first ( ) . map ( |owned| owned. as_str ( ) ) )
26+ }
27+
28+ /// Return all values associated with name where available
29+ pub fn get_all ( & self , key : & str ) -> Option < Vec < & str > > {
30+ self . 0
31+ . get ( key)
32+ . map ( |values| values. iter ( ) . map ( |owned| owned. as_str ( ) ) . collect :: < Vec < _ > > ( ) )
2033 }
2134
2235 /// Return true if the underlying map is empty
@@ -39,16 +52,17 @@ impl Clone for StrMap {
3952 StrMap ( self . 0 . clone ( ) )
4053 }
4154}
42- impl From < HashMap < String , String > > for StrMap {
43- fn from ( inner : HashMap < String , String > ) -> Self {
55+
56+ impl From < HashMap < String , Vec < String > > > for StrMap {
57+ fn from ( inner : HashMap < String , Vec < String > > ) -> Self {
4458 StrMap ( Arc :: new ( inner) )
4559 }
4660}
4761
4862/// A read only reference to `StrMap` key and value slice pairings
4963pub struct StrMapIter < ' a > {
5064 data : & ' a StrMap ,
51- keys : Keys < ' a , String , String > ,
65+ keys : Keys < ' a , String , Vec < String > > ,
5266}
5367
5468impl < ' a > Iterator for StrMapIter < ' a > {
@@ -60,6 +74,15 @@ impl<'a> Iterator for StrMapIter<'a> {
6074 }
6175}
6276
77+ /// internal type used when deserializing StrMaps from
78+ /// potentially one or many valued maps
79+ #[ derive( serde_derive:: Deserialize ) ]
80+ #[ serde( untagged) ]
81+ enum OneOrMany {
82+ One ( String ) ,
83+ Many ( Vec < String > ) ,
84+ }
85+
6386impl < ' de > Deserialize < ' de > for StrMap {
6487 fn deserialize < D > ( deserializer : D ) -> Result < StrMap , D :: Error >
6588 where
@@ -78,9 +101,17 @@ impl<'de> Deserialize<'de> for StrMap {
78101 where
79102 A : MapAccess < ' de > ,
80103 {
81- let mut inner = HashMap :: new ( ) ;
82- while let Some ( ( key, value) ) = map. next_entry ( ) ? {
83- inner. insert ( key, value) ;
104+ let mut inner = map. size_hint ( ) . map ( HashMap :: with_capacity) . unwrap_or_else ( HashMap :: new) ;
105+ // values may either be String or Vec<String>
106+ // to handle both single and multi value data
107+ while let Some ( ( key, value) ) = map. next_entry :: < _ , OneOrMany > ( ) ? {
108+ inner. insert (
109+ key,
110+ match value {
111+ OneOrMany :: One ( one) => vec ! [ one] ,
112+ OneOrMany :: Many ( many) => many,
113+ } ,
114+ ) ;
84115 }
85116 Ok ( StrMap ( Arc :: new ( inner) ) )
86117 }
@@ -103,17 +134,26 @@ mod tests {
103134 #[ test]
104135 fn str_map_get ( ) {
105136 let mut data = HashMap :: new ( ) ;
106- data. insert ( "foo" . into ( ) , "bar" . into ( ) ) ;
137+ data. insert ( "foo" . into ( ) , vec ! [ "bar" . into( ) ] ) ;
107138 let strmap = StrMap ( data. into ( ) ) ;
108139 assert_eq ! ( strmap. get( "foo" ) , Some ( "bar" ) ) ;
109140 assert_eq ! ( strmap. get( "bar" ) , None ) ;
110141 }
111142
143+ #[ test]
144+ fn str_map_get_all ( ) {
145+ let mut data = HashMap :: new ( ) ;
146+ data. insert ( "foo" . into ( ) , vec ! [ "bar" . into( ) , "baz" . into( ) ] ) ;
147+ let strmap = StrMap ( data. into ( ) ) ;
148+ assert_eq ! ( strmap. get_all( "foo" ) , Some ( vec![ "bar" , "baz" ] ) ) ;
149+ assert_eq ! ( strmap. get_all( "bar" ) , None ) ;
150+ }
151+
112152 #[ test]
113153 fn str_map_iter ( ) {
114154 let mut data = HashMap :: new ( ) ;
115- data. insert ( "foo" . into ( ) , "bar" . into ( ) ) ;
116- data. insert ( "baz" . into ( ) , "boom" . into ( ) ) ;
155+ data. insert ( "foo" . into ( ) , vec ! [ "bar" . into( ) ] ) ;
156+ data. insert ( "baz" . into ( ) , vec ! [ "boom" . into( ) ] ) ;
117157 let strmap = StrMap ( data. into ( ) ) ;
118158 let mut values = strmap. iter ( ) . map ( |( _, v) | v) . collect :: < Vec < _ > > ( ) ;
119159 values. sort ( ) ;
0 commit comments