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