Created
October 1, 2014 04:20
-
-
Save reem/27fb134d2554572b21f8 to your computer and use it in GitHub Desktop.
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
use std::str::{mod, SendStr, Slice, Owned}; | |
use std::collections::hashmap::{HashMap, Entries, Occupied, Vacant}; | |
use std::cell::UnsafeCell; | |
use std::sync; | |
use std::mem; | |
use std::io; | |
pub trait Marker { | |
pub fn name(Option<Self>) -> &'static str; | |
} | |
pub trait Header<M: Marker> { | |
pub fn parse(&[Vec<u8>]) -> Option<Self>; | |
pub fn format<W: Writer>(&self, &mut W) -> IoResult<()>; | |
} | |
struct HeaderView<'a, M: Marker> { | |
item: &'a HeaderItem | |
} | |
impl<'a, M: Marker> HeaderView<'a, M> { | |
pub fn read_as<'r, H: Header<M>>(&'r self) -> Option<HeaderReadGuard<'r, H>> { | |
self.item.read_as::<H>() | |
} | |
pub fn write_as<'r, H: Header<M>>(&'r mut self) -> Option<HeaderWriteGuard<'r, H>> { | |
self.item.write_as::<H>() | |
} | |
} | |
struct HeaderReadGuard<'a, H> { | |
lock: sync::raw::RWLockReadGuard<'a>, | |
data: &'a H | |
} | |
struct HeaderWriteGuard<'a, H> { | |
lock: sync::raw::RWLockWriteGuard<'a>, | |
data: &'a H | |
} | |
impl<'a, H> HeaderReadGuard<'a, H> { | |
fn new(lock: sync::raw::RWLockReadGuard<'a>, header: &'a H) -> HeaderReadGuard<'a, H> { | |
HeaderReadGuard { lock: lock, data: data } | |
} | |
} | |
impl<'a, H> HeaderWriteGuard<'a, H> { | |
fn new(lock: sync::raw::RWLockWriteGuard<'a>, header: &'a H) -> HeaderWriteGuard<'a, H> { | |
HeaderWriteGuard { lock: lock, data: data } | |
} | |
} | |
struct HeaderItem { | |
cell: UnsafeCell<RawHeaderItem>, | |
lock: sync::raw::RWLock | |
} | |
// Invariants: | |
// - raw = None means typed is Some | |
// - typed = None means raw is Some and valid | |
// - raw = Some and typed = Some means raw is valid | |
// - raw = None and typed = Some means raw is invalid | |
struct RawHeaderItem { | |
raw: Option<Vec<Vec<u8>>>, | |
typed: Option<Box<Header<Erased> + Send + Sync>> | |
} | |
impl HeaderItem { | |
pub fn read_as<H: Header<M>>(&self) -> Option<HeaderReadGuard<H>> { | |
// Take out a lock so that we have permission to read from RawHeaderItem. | |
let read = self.lock.read(); | |
// Safe because we have a read lock on the data. | |
let raw_item = self.cell.get() as *const RawHeaderItem; | |
// Find out if we have work to do. | |
match unsafe { raw_item.try_typed::<M, H>() } { | |
// If we have a typed representation of the correct type, we are good. | |
Some(ref typed) => return Some(HeaderReadGuard::new(read, typed)), | |
// If not, we have work to do, so find out what. | |
_ => {} | |
}; | |
drop(read); let write = self.lock.write(); | |
let raw_item = self.cell.get(); | |
// The second check here is not redundant because another thread could have | |
// written while we were waiting for the write lock. | |
unsafe { raw_item.get_typed() }.map(|typed| HeaderReadGuard::new(write, typed)) | |
} | |
pub fn write_as<H: Header<M>>(&mut self) -> Option<HeaderWriteGuard<H>> { | |
// We need exclusive access no matter what, so get it. | |
let lock = self.lock.write(); | |
let raw_item = self.cell.get(); | |
unsafe { raw_item.get_typed_mut() }.map(|typed| HeaderWriteGuard::new(write, typed)) | |
} | |
} | |
impl RawHeaderItem { | |
fn get_raw(&mut self) -> &[Vec<u8>] { | |
if self.raw.is_none() { | |
self.raw = format(self.typed.as_ref()); | |
} | |
self.raw.as_ref().unwrap().as_slice() | |
} | |
fn get_raw_mut(&mut self) -> &mut Vec<Vec<u8>> { | |
if self.raw.is_some() { | |
self.typed = None; | |
} else { | |
self.raw = Some(format(self.typed.as_ref())); | |
} | |
self.raw.as_mut().unwrap(); | |
} | |
fn get_typed<M: Marker, H: Header<M>>(&mut self) -> Option<&H> { | |
match self.typed { | |
Some(ref typed) if typed.is::<H>() => return unsafe { Some(typed.downcast_ref_unchecked()) }, | |
_ => {} | |
}; | |
*typed = Header::parse(self.get_raw().unwrap()).map(erase); | |
typed.map(|typed| unsafe { typed.downcast_ref_unchecked() }) | |
} | |
fn get_typed_mut<M: Marker, H: Header<M>>(&mut self) -> Option<&mut H> { | |
// Invalidate the raw representation. | |
self.raw = None; | |
match self.try_typed_mut() { | |
typed @ Some(_) => typed, | |
_ => {} | |
} | |
*self.typed = Header::parse(self.get_raw().unwrap()).map(erase); | |
self.typed.map(|typed| unsafe { typed.downcast_mut_unchecked() }) | |
} | |
fn try_typed_mut<M: Marker, H: Header<M>>(&mut self) -> Option<&mut H> { | |
match self.typed { | |
Some(ref mut typed) if typed.is::<H>() => return unsafe { Some(typed.downcast_mut_unchecked()) }, | |
_ => {} | |
}; | |
} | |
fn try_typed<M: Marker, H: Header<M>>(&self) -> Option<&H> { | |
match self.typed { | |
Some(ref typed) if typed.is::<H>() => return unsafe { Some(typed.downcast_ref_unchecked()) }, | |
_ => {} | |
}; | |
} | |
} | |
struct Erased; impl Marker for Erased { pub fn name(_: Option<Erased>) -> &'static str { "" } } | |
fn format(typed: Option<&Box<Header<Erased> + Send + Sync>>) -> Vec<Vec<u8>> { | |
let mut raw = io::MemWriter::new(); | |
// Unwrap is correct because typed and raw cannot both be None. | |
vec![self.typed.as_ref().unwrap() | |
// This unwrap is correct because Header::format is not allowed | |
// to throw an Error not generated by the Writer, which will not | |
// error. | |
.format(&mut raw).unwrap() | |
// Get the underlying Vec from the MemWriter. | |
.unwrap()] | |
} | |
fn erase<M: Marker, H: Header<M>>(header: H) -> Box<Header<Erased> + Send + Sync> { | |
let header: Box<Header<M> + Send + Sync> = box header; | |
mem::transmute(header) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment