Created
February 5, 2015 02:56
-
-
Save reem/1ee3162ace6bcdeab239 to your computer and use it in GitHub Desktop.
Simplified Headers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(core, alloc)] | |
use std::fmt; | |
use std::rc::Rc; | |
use std::any::{Any, TypeId}; | |
use std::collections::HashMap; | |
use std::ops::Deref; | |
pub trait HeaderFormat: fmt::Debug + Any { | |
fn fmt_header(&self, &mut fmt::Formatter) -> fmt::Result; | |
} | |
pub trait HeaderParse { | |
fn parse_header(&[String]) -> Option<Self>; | |
} | |
pub trait Header: HeaderFormat + HeaderParse {} | |
impl<H: HeaderFormat + HeaderParse> Header for H {} | |
pub trait HeaderMarker: fmt::Debug { | |
type Header: Header; | |
fn header_name(&self) -> &str; | |
} | |
impl HeaderFormat { | |
#[inline] | |
fn is<T: 'static>(&self) -> bool { | |
self.get_type_id() == TypeId::of::<T>() | |
} | |
#[inline] | |
fn downcast_ref<T: 'static>(&self) -> Option<&T> { | |
use std::mem::transmute; | |
use std::raw::TraitObject; | |
if self.is::<T>() { | |
unsafe { | |
Some(transmute(transmute::<_, TraitObject>(self).data)) | |
} | |
} else { | |
None | |
} | |
} | |
#[inline] | |
fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> { | |
use std::mem::transmute; | |
use std::raw::TraitObject; | |
if self.is::<T>() { | |
unsafe { | |
Some(transmute(transmute::<_, TraitObject>(self).data)) | |
} | |
} else { | |
None | |
} | |
} | |
} | |
#[doc(hidden)] | |
pub trait HeaderClone { | |
fn clone_box(&self) -> Box<HeaderFormat>; | |
} | |
impl<T: HeaderFormat + Clone> HeaderClone for T { | |
#[inline] | |
fn clone_box(&self) -> Box<HeaderFormat> { | |
Box::new(self.clone()) | |
} | |
} | |
impl Clone for Box<HeaderFormat> { | |
#[inline] | |
fn clone(&self) -> Box<HeaderFormat> { | |
self.clone_box() | |
} | |
} | |
impl HeaderFormat for Box<HeaderFormat> { | |
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
(**self).fmt_header(f) | |
} | |
} | |
type RcHeader = Rc<Box<HeaderFormat>>; | |
pub struct Headers { | |
headers: HashMap<String, RcHeader> | |
} | |
impl Headers { | |
#[inline] | |
pub fn new() -> Headers { | |
Headers { | |
headers: HashMap::new() | |
} | |
} | |
pub fn from_raw<R: Reader>(_: &mut R) -> Headers { | |
let headers = Headers::new(); | |
// TODO: Insert each header from the reader as Raw | |
headers | |
} | |
pub fn get<M: HeaderMarker>(&self, marker: M) -> Option<HeaderRef<M::Header>> | |
where M::Header: Header { | |
self.headers.get(marker.header_name()).and_then(|header| { | |
if header.is::<M::Header>() { | |
Some(HeaderRef::new(header.clone())) | |
} else { | |
HeaderRef::convert(header.clone()) | |
} | |
}) | |
} | |
pub fn get_mut<M: HeaderMarker>(&mut self, marker: M) -> Option<&mut M::Header> | |
where M::Header: Header { | |
self.headers.get_mut(marker.header_name()).and_then(|header| { | |
let header_ref = header.make_unique(); | |
reparse::<M::Header>(header_ref).ok() | |
.and_then(move |_| header_ref.downcast_mut()) | |
}) | |
} | |
pub fn insert<M: HeaderMarker>(&mut self, marker: M, value: M::Header) | |
where M::Header: Header { | |
let value: RcHeader = Rc::new(Box::new(value)); | |
self.headers.insert(marker.header_name().to_string(), value); | |
} | |
} | |
pub struct HeaderRef<H> { | |
counter: RcHeader | |
} | |
impl<H: Header> HeaderRef<H> { | |
fn new(header: RcHeader) -> HeaderRef<H> { | |
HeaderRef { | |
counter: header | |
} | |
} | |
fn convert(mut header: RcHeader) -> Option<HeaderRef<H>> { | |
reparse::<H>(header.make_unique()).map(move |_| { | |
HeaderRef::new(header) | |
}).ok() | |
} | |
} | |
impl<H: Header> Deref for HeaderRef<H> { | |
type Target = H; | |
fn deref(&self) -> &H { | |
self.counter.downcast_ref::<H>().expect("Incorrect HeaderRef") | |
} | |
} | |
fn reparse<H: Header>(from: &mut Box<HeaderFormat>) -> Result<(), ()> { | |
struct HeaderDisplayer<'a>(&'a HeaderFormat); | |
impl<'a> fmt::Display for HeaderDisplayer<'a> { | |
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
self.0.fmt_header(fmt) | |
} | |
} | |
// TODO: Proper re-parsing logic. | |
let formatted = vec![format!("{}", HeaderDisplayer(&*from))]; | |
let parsed = <H as HeaderParse>::parse_header(&formatted); | |
match parsed { | |
Some(data) => { *from = Box::new(data) as Box<HeaderFormat>; }, | |
None => return Err(()) | |
} | |
Ok(()) | |
} | |
pub mod marker { | |
use HeaderMarker; | |
#[derive(Debug, Clone, Copy)] | |
pub struct Raw<'a>(pub &'a str); | |
impl<'a> HeaderMarker for Raw<'a> { | |
type Header = ::common::Raw; | |
fn header_name(&self) -> &str { self.0 } | |
} | |
} | |
pub mod common { | |
use {HeaderFormat, HeaderParse}; | |
use std::fmt; | |
#[derive(Debug, Clone)] | |
pub struct Raw(pub Vec<String>); | |
impl HeaderFormat for Raw { | |
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
// TODO: Format correctly | |
fmt::Debug::fmt(self, fmt) | |
} | |
} | |
impl HeaderParse for Raw { | |
fn parse_header(raw: &[String]) -> Option<Raw> { | |
Some(Raw(raw.to_vec())) | |
} | |
} | |
} | |
fn main() {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment