Skip to content

Commit df75687

Browse files
committed
feat(headers): adds re-parsing ability when getting typed headers
BREAKING CHANGE: added requirement that all HeaderFormat implementations must also be fmt::Debug. This likely as easy as slapping #[derive(Debug)] on to any custom headers.
1 parent 9e07708 commit df75687

File tree

10 files changed

+258
-240
lines changed

10 files changed

+258
-240
lines changed

Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,4 @@ openssl = "*"
1919
rustc-serialize = "*"
2020
time = "*"
2121
unicase = "*"
22-
unsafe-any = "*"
2322
url = "*"

benches/client.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl Write for MockStream {
5050
}
5151
}
5252

53-
#[derive(Clone)]
53+
#[derive(Clone, Debug)]
5454
struct Foo;
5555

5656
impl hyper::header::Header for Foo {

src/header/cell.rs

-41
This file was deleted.

src/header/common/authorization.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl<S: Scheme + 'static> HeaderFormat for Authorization<S> where <S as FromStr>
5454
}
5555

5656
/// An Authorization scheme to be used in the header.
57-
pub trait Scheme: FromStr + Clone + Send + Sync {
57+
pub trait Scheme: FromStr + fmt::Debug + Clone + Send + Sync {
5858
/// An optional Scheme name.
5959
///
6060
/// For example, `Basic asdf` has the name `Basic`. The Option<Self> is

src/header/internals/cell.rs

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
use std::any::{Any, TypeId};
2+
use std::cell::UnsafeCell;
3+
use std::collections::HashMap;
4+
use std::fmt;
5+
use std::mem;
6+
use std::ops::Deref;
7+
8+
pub struct OptCell<T>(UnsafeCell<Option<T>>);
9+
10+
impl<T> OptCell<T> {
11+
#[inline]
12+
pub fn new(val: Option<T>) -> OptCell<T> {
13+
OptCell(UnsafeCell::new(val))
14+
}
15+
16+
#[inline]
17+
pub fn set(&self, val: T) {
18+
unsafe {
19+
let opt = self.0.get();
20+
debug_assert!((*opt).is_none());
21+
*opt = Some(val)
22+
}
23+
}
24+
25+
#[inline]
26+
pub unsafe fn get_mut(&mut self) -> &mut T {
27+
let opt = &mut *self.0.get();
28+
opt.as_mut().unwrap()
29+
}
30+
}
31+
32+
impl<T> Deref for OptCell<T> {
33+
type Target = Option<T>;
34+
#[inline]
35+
fn deref<'a>(&'a self) -> &'a Option<T> {
36+
unsafe { &*self.0.get() }
37+
}
38+
}
39+
40+
impl<T: Clone> Clone for OptCell<T> {
41+
#[inline]
42+
fn clone(&self) -> OptCell<T> {
43+
OptCell::new((**self).clone())
44+
}
45+
}
46+
47+
pub struct PtrMapCell<V: ?Sized>(UnsafeCell<PtrMap<Box<V>>>);
48+
49+
#[derive(Clone, Debug)]
50+
enum PtrMap<T> {
51+
Empty,
52+
One(TypeId, T),
53+
Many(HashMap<TypeId, T>)
54+
}
55+
56+
impl<V: ?Sized + fmt::Debug + Any + 'static> PtrMapCell<V> {
57+
#[inline]
58+
pub fn new() -> PtrMapCell<V> {
59+
PtrMapCell(UnsafeCell::new(PtrMap::Empty))
60+
}
61+
62+
#[inline]
63+
pub fn get(&self, key: TypeId) -> Option<&V> {
64+
let map = unsafe { &*self.0.get() };
65+
match *map {
66+
PtrMap::Empty => None,
67+
PtrMap::One(id, ref v) => if id == key {
68+
Some(v)
69+
} else {
70+
None
71+
},
72+
PtrMap::Many(ref hm) => hm.get(&key)
73+
}.map(|val| &**val)
74+
}
75+
76+
#[inline]
77+
pub fn get_mut(&mut self, key: TypeId) -> Option<&mut V> {
78+
let mut map = unsafe { &mut *self.0.get() };
79+
match *map {
80+
PtrMap::Empty => None,
81+
PtrMap::One(id, ref mut v) => if id == key {
82+
Some(v)
83+
} else {
84+
None
85+
},
86+
PtrMap::Many(ref mut hm) => hm.get_mut(&key)
87+
}.map(|val| &mut **val)
88+
}
89+
90+
#[inline]
91+
pub unsafe fn insert(&self, key: TypeId, val: Box<V>) {
92+
let mut map = &mut *self.0.get();
93+
match *map {
94+
PtrMap::Empty => *map = PtrMap::One(key, val),
95+
PtrMap::One(..) => {
96+
let one = mem::replace(map, PtrMap::Empty);
97+
match one {
98+
PtrMap::One(id, one) => {
99+
debug_assert!(id != key);
100+
let mut hm = HashMap::with_capacity(2);
101+
hm.insert(id, one);
102+
hm.insert(key, val);
103+
mem::replace(map, PtrMap::Many(hm));
104+
},
105+
_ => unreachable!()
106+
}
107+
},
108+
PtrMap::Many(ref mut hm) => { hm.insert(key, val); }
109+
}
110+
}
111+
112+
#[inline]
113+
pub unsafe fn one(&self) -> &V {
114+
let map = &*self.0.get();
115+
match *map {
116+
PtrMap::One(_, ref one) => one,
117+
_ => panic!("not PtrMap::One value, {:?}", *map)
118+
}
119+
}
120+
}
121+
122+
impl<V: ?Sized + fmt::Debug + Any + 'static> Clone for PtrMapCell<V> where Box<V>: Clone {
123+
#[inline]
124+
fn clone(&self) -> PtrMapCell<V> {
125+
let cell = PtrMapCell::new();
126+
unsafe {
127+
*cell.0.get() = (&*self.0.get()).clone()
128+
}
129+
cell
130+
}
131+
}

src/header/internals/item.rs

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use std::any::TypeId;
2+
use std::fmt;
3+
use std::str::from_utf8;
4+
5+
use super::cell::{OptCell, PtrMapCell};
6+
use header::{Header, HeaderFormat};
7+
8+
9+
#[derive(Clone)]
10+
pub struct Item {
11+
raw: OptCell<Vec<Vec<u8>>>,
12+
typed: PtrMapCell<HeaderFormat + Send + Sync>
13+
}
14+
15+
impl Item {
16+
#[inline]
17+
pub fn new_raw(data: Vec<Vec<u8>>) -> Item {
18+
Item {
19+
raw: OptCell::new(Some(data)),
20+
typed: PtrMapCell::new(),
21+
}
22+
}
23+
24+
#[inline]
25+
pub fn new_typed(ty: Box<HeaderFormat + Send + Sync>) -> Item {
26+
let map = PtrMapCell::new();
27+
unsafe { map.insert((&*ty).get_type_id(), ty); }
28+
Item {
29+
raw: OptCell::new(None),
30+
typed: map,
31+
}
32+
}
33+
34+
#[inline]
35+
pub fn mut_raw(&mut self) -> &mut Vec<Vec<u8>> {
36+
self.typed = PtrMapCell::new();
37+
unsafe {
38+
self.raw.get_mut()
39+
}
40+
}
41+
42+
pub fn raw(&self) -> &[Vec<u8>] {
43+
if let Some(ref raw) = *self.raw {
44+
return &raw[..];
45+
}
46+
47+
let raw = vec![unsafe { self.typed.one() }.to_string().into_bytes()];
48+
self.raw.set(raw);
49+
50+
let raw = self.raw.as_ref().unwrap();
51+
&raw[..]
52+
}
53+
54+
pub fn typed<H: Header + HeaderFormat>(&self) -> Option<&H> {
55+
let tid = TypeId::of::<H>();
56+
match self.typed.get(tid) {
57+
Some(val) => Some(val),
58+
None => {
59+
match parse::<H>(self.raw.as_ref().expect("item.raw must exist")) {
60+
Some(typed) => {
61+
unsafe { self.typed.insert(tid, typed); }
62+
self.typed.get(tid)
63+
},
64+
None => None
65+
}
66+
}
67+
}.map(|typed| unsafe { typed.downcast_ref_unchecked() })
68+
}
69+
70+
pub fn typed_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
71+
let tid = TypeId::of::<H>();
72+
if self.typed.get_mut(tid).is_none() {
73+
match parse::<H>(self.raw.as_ref().expect("item.raw must exist")) {
74+
Some(typed) => {
75+
unsafe { self.typed.insert(tid, typed); }
76+
},
77+
None => ()
78+
}
79+
}
80+
self.typed.get_mut(tid).map(|typed| unsafe { typed.downcast_mut_unchecked() })
81+
}
82+
}
83+
84+
#[inline]
85+
fn parse<H: Header + HeaderFormat>(raw: &Vec<Vec<u8>>) -> Option<Box<HeaderFormat + Send + Sync>> {
86+
Header::parse_header(&raw[..]).map(|h: H| box h as Box<HeaderFormat + Send + Sync>)
87+
}
88+
89+
impl fmt::Display for Item {
90+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
91+
match *self.raw {
92+
Some(ref raw) => {
93+
for part in raw.iter() {
94+
match from_utf8(&part[..]) {
95+
Ok(s) => try!(fmt.write_str(s)),
96+
Err(e) => {
97+
error!("raw header value is not utf8. header={:?}, error={:?}", part, e);
98+
return Err(fmt::Error);
99+
}
100+
}
101+
}
102+
Ok(())
103+
},
104+
None => fmt::Display::fmt(&unsafe { self.typed.one() }, fmt)
105+
}
106+
}
107+
}

src/header/internals/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub use self::item::Item;
2+
3+
mod cell;
4+
mod item;

0 commit comments

Comments
 (0)