11//! Apply the HTTP method if the ETag matches.
22
3- use crate :: conditional:: MatchDirective ;
3+ use crate :: conditional:: ETag ;
44use crate :: headers:: { HeaderName , HeaderValue , Headers , ToHeaderValues , IF_MATCH } ;
55
66use std:: fmt:: { self , Debug , Write } ;
@@ -31,19 +31,23 @@ use std::slice;
3131///
3232/// let entries = IfMatch::from_headers(res)?.unwrap();
3333/// let mut entries = entries.iter();
34- /// assert_eq!(entries.next().unwrap(), ETag::new("0xcafebeef".to_string()));
35- /// assert_eq!(entries.next().unwrap(), ETag::new("0xbeefcafe".to_string()));
34+ /// assert_eq!(entries.next().unwrap(), & ETag::new("0xcafebeef".to_string()));
35+ /// assert_eq!(entries.next().unwrap(), & ETag::new("0xbeefcafe".to_string()));
3636/// #
3737/// # Ok(()) }
3838/// ```
3939pub struct IfMatch {
40- entries : Vec < MatchDirective > ,
40+ entries : Vec < ETag > ,
41+ wildcard : bool ,
4142}
4243
4344impl IfMatch {
4445 /// Create a new instance of `IfMatch`.
4546 pub fn new ( ) -> Self {
46- Self { entries : vec ! [ ] }
47+ Self {
48+ entries : vec ! [ ] ,
49+ wildcard : false ,
50+ }
4751 }
4852
4953 /// Create a new instance from headers.
@@ -54,17 +58,19 @@ impl IfMatch {
5458 None => return Ok ( None ) ,
5559 } ;
5660
61+ let mut wildcard = false ;
5762 for value in headers {
5863 for part in value. as_str ( ) . trim ( ) . split ( ',' ) {
59- // Try and parse a directive from a str. If the directive is
60- // unkown we skip it.
61- if let Some ( entry ) = MatchDirective :: from_str ( part ) ? {
62- entries . push ( entry ) ;
64+ let part = part . trim ( ) ;
65+ if part == "*" {
66+ wildcard = true ;
67+ continue ;
6368 }
69+ entries. push ( ETag :: from_str ( part) ?) ;
6470 }
6571 }
6672
67- Ok ( Some ( Self { entries } ) )
73+ Ok ( Some ( Self { entries, wildcard } ) )
6874 }
6975
7076 /// Sets the `If-Match` header.
@@ -80,11 +86,17 @@ impl IfMatch {
8086 /// Get the `HeaderValue`.
8187 pub fn value ( & self ) -> HeaderValue {
8288 let mut output = String :: new ( ) ;
83- for ( n, directive) in self . entries . iter ( ) . enumerate ( ) {
84- let directive: HeaderValue = directive. clone ( ) . into ( ) ;
89+ for ( n, etag) in self . entries . iter ( ) . enumerate ( ) {
8590 match n {
86- 0 => write ! ( output, "{}" , directive) . unwrap ( ) ,
87- _ => write ! ( output, ", {}" , directive) . unwrap ( ) ,
91+ 0 => write ! ( output, "{}" , etag. to_string( ) ) . unwrap ( ) ,
92+ _ => write ! ( output, ", {}" , etag. to_string( ) ) . unwrap ( ) ,
93+ } ;
94+ }
95+
96+ if self . wildcard {
97+ match output. len ( ) {
98+ 0 => write ! ( output, "*" ) . unwrap ( ) ,
99+ _ => write ! ( output, ", *" ) . unwrap ( ) ,
88100 } ;
89101 }
90102
@@ -93,10 +105,20 @@ impl IfMatch {
93105 }
94106
95107 /// Push a directive into the list of entries.
96- pub fn push ( & mut self , directive : impl Into < MatchDirective > ) {
108+ pub fn push ( & mut self , directive : impl Into < ETag > ) {
97109 self . entries . push ( directive. into ( ) ) ;
98110 }
99111
112+ /// Returns `true` if a wildcard directive was set.
113+ pub fn wildcard ( & self ) -> bool {
114+ self . wildcard
115+ }
116+
117+ /// Set the wildcard directive.
118+ pub fn set_wildcard ( & mut self , wildcard : bool ) {
119+ self . wildcard = wildcard
120+ }
121+
100122 /// An iterator visiting all server entries.
101123 pub fn iter ( & self ) -> Iter < ' _ > {
102124 Iter {
@@ -113,7 +135,7 @@ impl IfMatch {
113135}
114136
115137impl IntoIterator for IfMatch {
116- type Item = MatchDirective ;
138+ type Item = ETag ;
117139 type IntoIter = IntoIter ;
118140
119141 #[ inline]
@@ -125,7 +147,7 @@ impl IntoIterator for IfMatch {
125147}
126148
127149impl < ' a > IntoIterator for & ' a IfMatch {
128- type Item = & ' a MatchDirective ;
150+ type Item = & ' a ETag ;
129151 type IntoIter = Iter < ' a > ;
130152
131153 #[ inline]
@@ -135,7 +157,7 @@ impl<'a> IntoIterator for &'a IfMatch {
135157}
136158
137159impl < ' a > IntoIterator for & ' a mut IfMatch {
138- type Item = & ' a mut MatchDirective ;
160+ type Item = & ' a mut ETag ;
139161 type IntoIter = IterMut < ' a > ;
140162
141163 #[ inline]
@@ -147,11 +169,11 @@ impl<'a> IntoIterator for &'a mut IfMatch {
147169/// A borrowing iterator over entries in `IfMatch`.
148170#[ derive( Debug ) ]
149171pub struct IntoIter {
150- inner : std:: vec:: IntoIter < MatchDirective > ,
172+ inner : std:: vec:: IntoIter < ETag > ,
151173}
152174
153175impl Iterator for IntoIter {
154- type Item = MatchDirective ;
176+ type Item = ETag ;
155177
156178 fn next ( & mut self ) -> Option < Self :: Item > {
157179 self . inner . next ( )
@@ -166,11 +188,11 @@ impl Iterator for IntoIter {
166188/// A lending iterator over entries in `IfMatch`.
167189#[ derive( Debug ) ]
168190pub struct Iter < ' a > {
169- inner : slice:: Iter < ' a , MatchDirective > ,
191+ inner : slice:: Iter < ' a , ETag > ,
170192}
171193
172194impl < ' a > Iterator for Iter < ' a > {
173- type Item = & ' a MatchDirective ;
195+ type Item = & ' a ETag ;
174196
175197 fn next ( & mut self ) -> Option < Self :: Item > {
176198 self . inner . next ( )
@@ -185,11 +207,11 @@ impl<'a> Iterator for Iter<'a> {
185207/// A mutable iterator over entries in `IfMatch`.
186208#[ derive( Debug ) ]
187209pub struct IterMut < ' a > {
188- inner : slice:: IterMut < ' a , MatchDirective > ,
210+ inner : slice:: IterMut < ' a , ETag > ,
189211}
190212
191213impl < ' a > Iterator for IterMut < ' a > {
192- type Item = & ' a mut MatchDirective ;
214+ type Item = & ' a mut ETag ;
193215
194216 fn next ( & mut self ) -> Option < Self :: Item > {
195217 self . inner . next ( )
@@ -235,8 +257,33 @@ mod test {
235257
236258 let entries = IfMatch :: from_headers ( res) ?. unwrap ( ) ;
237259 let mut entries = entries. iter ( ) ;
238- assert_eq ! ( entries. next( ) . unwrap( ) , ETag :: new( "0xcafebeef" . to_string( ) ) ) ;
239- assert_eq ! ( entries. next( ) . unwrap( ) , ETag :: new( "0xbeefcafe" . to_string( ) ) ) ;
260+ assert_eq ! (
261+ entries. next( ) . unwrap( ) ,
262+ & ETag :: new( "0xcafebeef" . to_string( ) )
263+ ) ;
264+ assert_eq ! (
265+ entries. next( ) . unwrap( ) ,
266+ & ETag :: new( "0xbeefcafe" . to_string( ) )
267+ ) ;
268+ Ok ( ( ) )
269+ }
270+
271+ #[ test]
272+ fn wildcard ( ) -> crate :: Result < ( ) > {
273+ let mut entries = IfMatch :: new ( ) ;
274+ entries. push ( ETag :: new ( "0xcafebeef" . to_string ( ) ) ) ;
275+ entries. set_wildcard ( true ) ;
276+
277+ let mut res = Response :: new ( 200 ) ;
278+ entries. apply ( & mut res) ;
279+
280+ let entries = IfMatch :: from_headers ( res) ?. unwrap ( ) ;
281+ assert_eq ! ( entries. wildcard( ) , true ) ;
282+ let mut entries = entries. iter ( ) ;
283+ assert_eq ! (
284+ entries. next( ) . unwrap( ) ,
285+ & ETag :: new( "0xcafebeef" . to_string( ) )
286+ ) ;
240287 Ok ( ( ) )
241288 }
242289}
0 commit comments