Skip to content

Instantly share code, notes, and snippets.

@reem
Created October 1, 2014 04:20
Show Gist options
  • Save reem/27fb134d2554572b21f8 to your computer and use it in GitHub Desktop.
Save reem/27fb134d2554572b21f8 to your computer and use it in GitHub Desktop.
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