@@ -9,14 +9,27 @@ use serde::{
9
9
Deserialize , Deserializer ,
10
10
} ;
11
11
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
13
15
#[ 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 > > > ) ;
15
17
16
18
impl 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
18
22
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 < _ > > ( ) )
20
33
}
21
34
22
35
/// Return true if the underlying map is empty
@@ -39,16 +52,17 @@ impl Clone for StrMap {
39
52
StrMap ( self . 0 . clone ( ) )
40
53
}
41
54
}
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 {
44
58
StrMap ( Arc :: new ( inner) )
45
59
}
46
60
}
47
61
48
62
/// A read only reference to `StrMap` key and value slice pairings
49
63
pub struct StrMapIter < ' a > {
50
64
data : & ' a StrMap ,
51
- keys : Keys < ' a , String , String > ,
65
+ keys : Keys < ' a , String , Vec < String > > ,
52
66
}
53
67
54
68
impl < ' a > Iterator for StrMapIter < ' a > {
@@ -60,6 +74,15 @@ impl<'a> Iterator for StrMapIter<'a> {
60
74
}
61
75
}
62
76
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
+
63
86
impl < ' de > Deserialize < ' de > for StrMap {
64
87
fn deserialize < D > ( deserializer : D ) -> Result < StrMap , D :: Error >
65
88
where
@@ -78,9 +101,17 @@ impl<'de> Deserialize<'de> for StrMap {
78
101
where
79
102
A : MapAccess < ' de > ,
80
103
{
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
+ ) ;
84
115
}
85
116
Ok ( StrMap ( Arc :: new ( inner) ) )
86
117
}
@@ -103,17 +134,26 @@ mod tests {
103
134
#[ test]
104
135
fn str_map_get ( ) {
105
136
let mut data = HashMap :: new ( ) ;
106
- data. insert ( "foo" . into ( ) , "bar" . into ( ) ) ;
137
+ data. insert ( "foo" . into ( ) , vec ! [ "bar" . into( ) ] ) ;
107
138
let strmap = StrMap ( data. into ( ) ) ;
108
139
assert_eq ! ( strmap. get( "foo" ) , Some ( "bar" ) ) ;
109
140
assert_eq ! ( strmap. get( "bar" ) , None ) ;
110
141
}
111
142
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
+
112
152
#[ test]
113
153
fn str_map_iter ( ) {
114
154
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( ) ] ) ;
117
157
let strmap = StrMap ( data. into ( ) ) ;
118
158
let mut values = strmap. iter ( ) . map ( |( _, v) | v) . collect :: < Vec < _ > > ( ) ;
119
159
values. sort ( ) ;
0 commit comments