@@ -13,9 +13,9 @@ use std::raw::TraitObject;
13
13
use std:: str:: SendStr ;
14
14
use std:: collections:: HashMap ;
15
15
use std:: collections:: hash_map:: { Entries , Occupied , Vacant } ;
16
- use std:: sync:: RWLock ;
17
16
use std:: { hash, mem} ;
18
17
18
+ use mucell:: MuCell ;
19
19
use uany:: { UncheckedAnyDowncast , UncheckedAnyMutDowncast } ;
20
20
21
21
use http:: { mod, LineEnding } ;
@@ -96,7 +96,7 @@ fn header_name<T: Header>() -> &'static str {
96
96
/// A map of header fields on requests and responses.
97
97
#[ deriving( Clone ) ]
98
98
pub struct Headers {
99
- data : HashMap < CaseInsensitive , RWLock < Item > >
99
+ data : HashMap < CaseInsensitive , MuCell < Item > >
100
100
}
101
101
102
102
impl Headers {
@@ -116,12 +116,12 @@ impl Headers {
116
116
Some ( ( name, value) ) => {
117
117
debug ! ( "raw header: {}={}" , name, value[ ] . to_ascii( ) ) ;
118
118
let name = CaseInsensitive ( Owned ( name) ) ;
119
- let item = match headers. data . entry ( name) {
120
- Vacant ( entry) => entry. set ( RWLock :: new ( Item :: raw ( vec ! [ ] ) ) ) ,
119
+ let mut item = match headers. data . entry ( name) {
120
+ Vacant ( entry) => entry. set ( MuCell :: new ( Item :: raw ( vec ! [ ] ) ) ) ,
121
121
Occupied ( entry) => entry. into_mut ( )
122
122
} ;
123
123
124
- match & mut item. write ( ) . raw {
124
+ match & mut item. borrow_mut ( ) . raw {
125
125
& Some ( ref mut raw) => raw. push ( value) ,
126
126
// Unreachable
127
127
_ => { }
@@ -138,7 +138,7 @@ impl Headers {
138
138
/// The field is determined by the type of the value being set.
139
139
pub fn set < H : Header + HeaderFormat > ( & mut self , value : H ) {
140
140
self . data . insert ( CaseInsensitive ( Borrowed ( header_name :: < H > ( ) ) ) ,
141
- RWLock :: new ( Item :: typed ( box value as Box < HeaderFormat + Send + Sync > ) ) ) ;
141
+ MuCell :: new ( Item :: typed ( box value as Box < HeaderFormat + Send + Sync > ) ) ) ;
142
142
}
143
143
144
144
/// Access the raw value of a header.
@@ -157,15 +157,19 @@ impl Headers {
157
157
// FIXME(reem): Find a better way to do this lookup without find_equiv.
158
158
. get ( & CaseInsensitive ( Borrowed ( unsafe { mem:: transmute :: < & str , & str > ( name) } ) ) )
159
159
. and_then ( |item| {
160
- let lock = item. read ( ) ;
161
- if let Some ( ref raw) = lock. raw {
160
+ if let Some ( ref raw) = item. borrow ( ) . raw {
162
161
return unsafe { mem:: transmute ( Some ( raw[ ] ) ) } ;
163
162
}
164
163
165
- let mut lock = item. write ( ) ;
166
- let raw = vec ! [ lock. typed. as_ref( ) . unwrap( ) . to_string( ) . into_bytes( ) ] ;
167
- lock. raw = Some ( raw) ;
168
- unsafe { mem:: transmute ( Some ( lock. raw . as_ref ( ) . unwrap ( ) [ ] ) ) }
164
+ let worked = item. try_mutate ( |item| {
165
+ let raw = vec ! [ item. typed. as_ref( ) . unwrap( ) . to_string( ) . into_bytes( ) ] ;
166
+ item. raw = Some ( raw) ;
167
+ } ) ;
168
+ debug_assert ! ( worked, "item.try_mutate should return true" ) ;
169
+
170
+ let item = item. borrow ( ) ;
171
+ let raw = item. raw . as_ref ( ) . unwrap ( ) ;
172
+ unsafe { mem:: transmute ( Some ( raw[ ] ) ) }
169
173
} )
170
174
}
171
175
@@ -179,29 +183,31 @@ impl Headers {
179
183
/// headers.set_raw("content-length", vec!["5".as_bytes().to_vec()]);
180
184
/// ```
181
185
pub fn set_raw < K : IntoCow < ' static , String , str > > ( & mut self , name : K , value : Vec < Vec < u8 > > ) {
182
- self . data . insert ( CaseInsensitive ( name. into_cow ( ) ) , RWLock :: new ( Item :: raw ( value) ) ) ;
186
+ self . data . insert ( CaseInsensitive ( name. into_cow ( ) ) , MuCell :: new ( Item :: raw ( value) ) ) ;
183
187
}
184
188
185
189
/// Get a reference to the header field's value, if it exists.
186
190
pub fn get < H : Header + HeaderFormat > ( & self ) -> Option < & H > {
187
191
self . get_or_parse :: < H > ( ) . map ( |item| {
188
192
unsafe {
189
- mem:: transmute :: < & H , & H > ( downcast ( & * item. read ( ) ) )
193
+ mem:: transmute :: < & H , & H > ( downcast ( & * item. borrow ( ) ) )
190
194
}
191
195
} )
192
196
}
193
197
194
198
/// Get a mutable reference to the header field's value, if it exists.
195
199
pub fn get_mut < H : Header + HeaderFormat > ( & mut self ) -> Option < & mut H > {
196
- self . get_or_parse :: < H > ( ) . map ( |item| {
197
- unsafe {
198
- mem:: transmute :: < & mut H , & mut H > ( downcast_mut ( & mut * item. write ( ) ) )
199
- }
200
+ self . get_or_parse_mut :: < H > ( ) . map ( |item| {
201
+ unsafe { downcast_mut ( item. borrow_mut ( ) ) }
200
202
} )
201
203
}
202
204
203
- fn get_or_parse < H : Header + HeaderFormat > ( & self ) -> Option < & RWLock < Item > > {
204
- self . data . get ( & CaseInsensitive ( Borrowed ( header_name :: < H > ( ) ) ) ) . and_then ( |item| get_or_parse :: < H > ( item) )
205
+ fn get_or_parse < H : Header + HeaderFormat > ( & self ) -> Option < & MuCell < Item > > {
206
+ self . data . get ( & CaseInsensitive ( Borrowed ( header_name :: < H > ( ) ) ) ) . and_then ( get_or_parse :: < H > )
207
+ }
208
+
209
+ fn get_or_parse_mut < H : Header + HeaderFormat > ( & mut self ) -> Option < & mut MuCell < Item > > {
210
+ self . data . get_mut ( & CaseInsensitive ( Borrowed ( header_name :: < H > ( ) ) ) ) . and_then ( get_or_parse_mut :: < H > )
205
211
}
206
212
207
213
/// Returns a boolean of whether a certain header is in the map.
@@ -253,7 +259,7 @@ impl fmt::Show for Headers {
253
259
254
260
/// An `Iterator` over the fields in a `Headers` map.
255
261
pub struct HeadersItems < ' a > {
256
- inner : Entries < ' a , CaseInsensitive , RWLock < Item > >
262
+ inner : Entries < ' a , CaseInsensitive , MuCell < Item > >
257
263
}
258
264
259
265
impl < ' a > Iterator < HeaderView < ' a > > for HeadersItems < ' a > {
@@ -266,7 +272,7 @@ impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> {
266
272
}
267
273
268
274
/// Returned with the `HeadersItems` iterator.
269
- pub struct HeaderView < ' a > ( & ' a CaseInsensitive , & ' a RWLock < Item > ) ;
275
+ pub struct HeaderView < ' a > ( & ' a CaseInsensitive , & ' a MuCell < Item > ) ;
270
276
271
277
impl < ' a > HeaderView < ' a > {
272
278
/// Check if a HeaderView is a certain Header.
@@ -286,21 +292,21 @@ impl<'a> HeaderView<'a> {
286
292
pub fn value < H : Header + HeaderFormat > ( & self ) -> Option < & ' a H > {
287
293
get_or_parse :: < H > ( self . 1 ) . map ( |item| {
288
294
unsafe {
289
- mem:: transmute :: < & H , & H > ( downcast ( & * item. read ( ) ) )
295
+ mem:: transmute :: < & H , & H > ( downcast ( & * item. borrow ( ) ) )
290
296
}
291
297
} )
292
298
}
293
299
294
300
/// Get just the header value as a String.
295
301
#[ inline]
296
302
pub fn value_string ( & self ) -> String {
297
- ( * self . 1 . read ( ) ) . to_string ( )
303
+ ( * self . 1 . borrow ( ) ) . to_string ( )
298
304
}
299
305
}
300
306
301
307
impl < ' a > fmt:: Show for HeaderView < ' a > {
302
308
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
303
- write ! ( f, "{}: {}" , self . 0 , * self . 1 . read ( ) )
309
+ write ! ( f, "{}: {}" , self . 0 , * self . 1 . borrow ( ) )
304
310
}
305
311
}
306
312
@@ -343,8 +349,8 @@ impl Item {
343
349
344
350
}
345
351
346
- fn get_or_parse < H : Header + HeaderFormat > ( item : & RWLock < Item > ) -> Option < & RWLock < Item > > {
347
- match item. read ( ) . typed {
352
+ fn get_or_parse < H : Header + HeaderFormat > ( item : & MuCell < Item > ) -> Option < & MuCell < Item > > {
353
+ match item. borrow ( ) . typed {
348
354
Some ( ref typed) if typed. is :: < H > ( ) => return Some ( item) ,
349
355
Some ( ref typed) => {
350
356
warn ! ( "attempted to access {} as wrong type" , typed) ;
@@ -353,53 +359,55 @@ fn get_or_parse<H: Header + HeaderFormat>(item: &RWLock<Item>) -> Option<&RWLock
353
359
_ => ( )
354
360
}
355
361
356
- // Take out a write lock to do the parsing and mutation.
357
- let mut write = item . write ( ) ;
358
-
359
- // Since this lock can queue, it's possible another thread just
360
- // did the work for us.
361
- match write . typed {
362
- // Check they inserted the correct type and move on.
363
- Some ( ref typed ) if typed . is :: < H > ( ) => return Some ( item ) ,
362
+ let worked = item . try_mutate ( parse :: < H > ) ;
363
+ debug_assert ! ( worked , "item.try_mutate should return true" ) ;
364
+ if item . borrow ( ) . typed . is_some ( ) {
365
+ Some ( item )
366
+ } else {
367
+ None
368
+ }
369
+ }
364
370
365
- // Wrong type, another thread got here before us and parsed
366
- // as a different representation.
371
+ fn get_or_parse_mut < H : Header + HeaderFormat > ( item : & mut MuCell < Item > ) -> Option < & mut MuCell < Item > > {
372
+ let is_correct_type = match item. borrow ( ) . typed {
373
+ Some ( ref typed) if typed. is :: < H > ( ) => Some ( true ) ,
367
374
Some ( ref typed) => {
368
- debug ! ( "other thread was here first?" )
369
375
warn ! ( "attempted to access {} as wrong type" , typed) ;
370
- return None ;
371
- } ,
376
+ Some ( false )
377
+ }
378
+ _ => None
379
+ } ;
372
380
373
- // We are first in the queue or the only ones, so do the actual
374
- // work of parsing and mutation.
375
- _ => ( )
381
+ match is_correct_type {
382
+ Some ( true ) => return Some ( item) ,
383
+ Some ( false ) => return None ,
384
+ None => ( )
385
+ }
386
+
387
+ parse :: < H > ( item. borrow_mut ( ) ) ;
388
+ if item. borrow ( ) . typed . is_some ( ) {
389
+ Some ( item)
390
+ } else {
391
+ None
376
392
}
393
+ }
377
394
378
- let header = match write. raw {
395
+ fn parse < H : Header + HeaderFormat > ( item : & mut Item ) {
396
+ item. typed = match item. raw {
379
397
Some ( ref raw) => match Header :: parse_header ( raw[ ] ) {
380
- Some :: < H > ( h) => h ,
381
- None => return None
398
+ Some :: < H > ( h) => Some ( box h as Box < HeaderFormat + Send + Sync > ) ,
399
+ None => None
382
400
} ,
383
401
None => unreachable ! ( )
384
402
} ;
385
-
386
- // Mutate!
387
- write. typed = Some ( box header as Box < HeaderFormat + Send + Sync > ) ;
388
- Some ( item)
389
403
}
390
404
391
- fn downcast < H : Header + HeaderFormat > ( read : & Item ) -> & H {
392
- match read. typed {
393
- Some ( ref val) => unsafe { val. downcast_ref_unchecked ( ) } ,
394
- _ => unreachable ! ( )
395
- }
405
+ unsafe fn downcast < H : Header + HeaderFormat > ( item : & Item ) -> & H {
406
+ item. typed . as_ref ( ) . expect ( "item.typed must be set" ) . downcast_ref_unchecked ( )
396
407
}
397
408
398
- fn downcast_mut < H : Header + HeaderFormat > ( write : & mut Item ) -> & mut H {
399
- match write. typed {
400
- Some ( ref mut val) => unsafe { val. downcast_mut_unchecked ( ) } ,
401
- _ => unreachable ! ( )
402
- }
409
+ unsafe fn downcast_mut < H : Header + HeaderFormat > ( item : & mut Item ) -> & mut H {
410
+ item. typed . as_mut ( ) . expect ( "item.typed must be set" ) . downcast_mut_unchecked ( )
403
411
}
404
412
405
413
impl fmt:: Show for Item {
@@ -419,12 +427,6 @@ impl fmt::Show for Item {
419
427
}
420
428
}
421
429
422
- impl Clone for RWLock < Item > {
423
- fn clone ( & self ) -> RWLock < Item > {
424
- RWLock :: new ( self . read ( ) . clone ( ) )
425
- }
426
- }
427
-
428
430
impl fmt:: Show for Box < HeaderFormat + Send + Sync > {
429
431
fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> fmt:: Result {
430
432
( * * self ) . fmt_header ( fmt)
@@ -655,6 +657,32 @@ mod tests {
655
657
}
656
658
}
657
659
660
+ #[ bench]
661
+ fn bench_header_get ( b : & mut Bencher ) {
662
+ let mut headers = Headers :: new ( ) ;
663
+ headers. set ( ContentLength ( 11 ) ) ;
664
+ b. iter ( || assert_eq ! ( headers. get:: <ContentLength >( ) , Some ( & ContentLength ( 11 ) ) ) )
665
+ }
666
+
667
+ #[ bench]
668
+ fn bench_header_get_miss ( b : & mut Bencher ) {
669
+ let headers = Headers :: new ( ) ;
670
+ b. iter ( || assert ! ( headers. get:: <ContentLength >( ) . is_none( ) ) )
671
+ }
672
+
673
+ #[ bench]
674
+ fn bench_header_set ( b : & mut Bencher ) {
675
+ let mut headers = Headers :: new ( ) ;
676
+ b. iter ( || headers. set ( ContentLength ( 12 ) ) )
677
+ }
678
+
679
+ #[ bench]
680
+ fn bench_header_has ( b : & mut Bencher ) {
681
+ let mut headers = Headers :: new ( ) ;
682
+ headers. set ( ContentLength ( 11 ) ) ;
683
+ b. iter ( || assert ! ( headers. has:: <ContentLength >( ) ) )
684
+ }
685
+
658
686
#[ bench]
659
687
fn bench_header_view_is ( b : & mut Bencher ) {
660
688
let mut headers = Headers :: new ( ) ;
0 commit comments