use std::mem; use std::io::Write;
const EMPTY: *mut () = 0x1 as *mut ();
macro_rules! try_option {
($expr:expr) => (match $expr {
Some(val) => val,
None => { return None }
})
}
#[inline]
pub fn encode<T: Abomonation>(typed: &T, bytes: &mut Vec<u8>) {
unsafe {
let start = bytes.len(); let slice = std::slice::from_raw_parts(mem::transmute(typed), mem::size_of::<T>());
bytes.write_all(slice).unwrap(); let result: &mut T = mem::transmute(bytes.as_mut_ptr().offset(start as isize));
result.embalm();
typed.entomb(bytes);
}
}
#[inline]
pub fn decode<T: Abomonation>(bytes: &mut [u8]) -> Option<(&T, &mut [u8])> {
if bytes.len() < mem::size_of::<T>() { None }
else {
let (split1, split2) = bytes.split_at_mut(mem::size_of::<T>());
let result: &mut T = unsafe { mem::transmute(split1.get_unchecked_mut(0)) };
if let Some(remaining) = unsafe { result.exhume(split2) } {
Some((result, remaining))
}
else {
None
}
}
}
#[inline]
pub fn verify<T: Abomonation>(bytes: &[u8]) -> Option<(&T,&[u8])> {
let result: &T = unsafe { mem::transmute(bytes.get_unchecked(0)) };
result.verify(&bytes[mem::size_of::<T>()..]).map(|x| (result, x))
}
pub trait Abomonation {
#[inline] unsafe fn entomb(&self, _writer: &mut Vec<u8>) { }
#[inline] unsafe fn embalm(&mut self) { }
#[inline] unsafe fn exhume<'a,'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> { Some(bytes) }
#[inline] fn verify<'a,'b>(&'a self, bytes: &'b [u8]) -> Option<&'b [u8]> { Some(bytes) }
}
#[macro_export]
macro_rules! unsafe_abomonate {
($t:ty) => { impl Abomonation for $t { } };
($t:ty : $($field:ident),*) => {
impl Abomonation for $t {
#[inline] unsafe fn entomb(&self, _writer: &mut Vec<u8>) {
$( self.$field.entomb(_writer); )*
}
#[inline] unsafe fn embalm(&mut self) {
$( self.$field.embalm(); )*
}
#[inline] unsafe fn exhume<'a,'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
$( let temp = bytes; bytes = if let Some(bytes) = self.$field.exhume(temp) { bytes} else { return None }; )*
Some(bytes)
}
#[inline] fn verify<'a,'b>(&'a self, mut bytes: &'b [u8]) -> Option<&'b [u8]> {
$( let temp = bytes; bytes = if let Some(bytes) = self.$field.verify(temp) { bytes} else { return None }; )*
Some(bytes)
}
}
}
}
impl Abomonation for u8 { }
impl Abomonation for u16 { }
impl Abomonation for u32 { }
impl Abomonation for u64 { }
impl Abomonation for i8 { }
impl Abomonation for i16 { }
impl Abomonation for i32 { }
impl Abomonation for i64 { }
impl Abomonation for f32 { }
impl Abomonation for f64 { }
impl Abomonation for bool { }
impl Abomonation for () {}
impl<T: Abomonation> Abomonation for Option<T> {
#[inline] unsafe fn embalm(&mut self) {
if let &mut Some(ref mut inner) = self {
inner.embalm();
}
}
#[inline] unsafe fn entomb(&self, bytes: &mut Vec<u8>) {
if let &Some(ref inner) = self {
inner.entomb(bytes);
}
}
#[inline] unsafe fn exhume<'a, 'b>(&'a mut self, mut bytes: &'b mut[u8]) -> Option<&'b mut [u8]> {
if let &mut Some(ref mut inner) = self {
let tmp = bytes; bytes = try_option!(inner.exhume(tmp));
}
Some(bytes)
}
#[inline] fn verify<'a, 'b>(&'a self, mut bytes: &'b [u8]) -> Option<&'b [u8]> {
if let &Some(ref inner) = self {
let tmp = bytes; bytes = try_option!(inner.verify(tmp));
}
Some(bytes)
}
}
impl<T1: Abomonation, T2: Abomonation> Abomonation for (T1, T2) {
#[inline] unsafe fn embalm(&mut self) { self.0.embalm(); self.1.embalm(); }
#[inline] unsafe fn entomb(&self, bytes: &mut Vec<u8>) { self.0.entomb(bytes); self.1.entomb(bytes); }
#[inline] unsafe fn exhume<'a,'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
let tmp = bytes; bytes = try_option!(self.0.exhume(tmp));
let tmp = bytes; bytes = try_option!(self.1.exhume(tmp));
Some(bytes)
}
#[inline] fn verify<'a,'b>(&'a self, mut bytes: &'b [u8]) -> Option<&'b [u8]> {
let tmp = bytes; bytes = try_option!(self.0.verify(tmp));
let tmp = bytes; bytes = try_option!(self.1.verify(tmp));
Some(bytes)
}
}
impl<T1: Abomonation, T2: Abomonation, T3: Abomonation> Abomonation for (T1, T2, T3) {
#[inline] unsafe fn embalm(&mut self) { self.0.embalm(); self.1.embalm(); self.2.embalm(); }
#[inline] unsafe fn entomb(&self, bytes: &mut Vec<u8>) { self.0.entomb(bytes); self.1.entomb(bytes); self.2.entomb(bytes); }
#[inline] unsafe fn exhume<'a,'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
let tmp = bytes; bytes = try_option!(self.0.exhume(tmp));
let tmp = bytes; bytes = try_option!(self.1.exhume(tmp));
let tmp = bytes; bytes = try_option!(self.2.exhume(tmp));
Some(bytes)
}
#[inline] fn verify<'a,'b>(&'a self, mut bytes: &'b [u8]) -> Option<&'b [u8]> {
let tmp = bytes; bytes = try_option!(self.0.verify(tmp));
let tmp = bytes; bytes = try_option!(self.1.verify(tmp));
let tmp = bytes; bytes = try_option!(self.2.verify(tmp));
Some(bytes)
}
}
impl<T1: Abomonation, T2: Abomonation, T3: Abomonation, T4: Abomonation> Abomonation for (T1, T2, T3, T4) {
#[inline] unsafe fn embalm(&mut self) { self.0.embalm(); self.1.embalm(); self.2.embalm(); self.3.embalm(); }
#[inline] unsafe fn entomb(&self, bytes: &mut Vec<u8>) { self.0.entomb(bytes); self.1.entomb(bytes); self.2.entomb(bytes); self.3.entomb(bytes); }
#[inline] unsafe fn exhume<'a,'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
let tmp = bytes; bytes = try_option!(self.0.exhume(tmp));
let tmp = bytes; bytes = try_option!(self.1.exhume(tmp));
let tmp = bytes; bytes = try_option!(self.2.exhume(tmp));
let tmp = bytes; bytes = try_option!(self.3.exhume(tmp));
Some(bytes)
}
#[inline] fn verify<'a,'b>(&'a self, mut bytes: &'b [u8]) -> Option<&'b [u8]> {
let tmp = bytes; bytes = try_option!(self.0.verify(tmp));
let tmp = bytes; bytes = try_option!(self.1.verify(tmp));
let tmp = bytes; bytes = try_option!(self.2.verify(tmp));
let tmp = bytes; bytes = try_option!(self.3.verify(tmp));
Some(bytes)
}
}
impl Abomonation for String {
#[inline]
unsafe fn embalm(&mut self) {
std::ptr::write(self, String::from_raw_parts(EMPTY as *mut u8, self.len(), self.len()));
}
#[inline]
unsafe fn entomb(&self, bytes: &mut Vec<u8>) {
bytes.write_all(self.as_bytes()).unwrap();
}
#[inline]
unsafe fn exhume<'a,'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
if self.len() > bytes.len() { None }
else {
let (mine, rest) = bytes.split_at_mut(self.len());
std::ptr::write(self, String::from_raw_parts(mem::transmute(mine.as_ptr()), self.len(), self.len()));
Some(rest)
}
}
#[inline]
fn verify<'a,'b>(&'a self, bytes: &'b [u8]) -> Option<&'b [u8]> {
if self.len() <= bytes.len() && self.as_bytes().as_ptr() == bytes.as_ptr() {
return Some(&bytes[self.len()..])
}
else {
None
}
}
}
impl<T: Abomonation> Abomonation for Vec<T> {
#[inline]
unsafe fn embalm(&mut self) {
std::ptr::write(self, Vec::from_raw_parts(EMPTY as *mut T, self.len(), self.len()));
}
#[inline]
unsafe fn entomb(&self, bytes: &mut Vec<u8>) {
let position = bytes.len();
bytes.write_all(typed_to_bytes(&self[..])).unwrap();
for element in bytes_to_typed::<T>(&mut bytes[position..], self.len()) { element.embalm(); }
for element in self.iter() { element.entomb(bytes); }
}
#[inline]
unsafe fn exhume<'a,'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
let binary_len = self.len() * mem::size_of::<T>();
if binary_len > bytes.len() { None }
else {
let (mine, mut rest) = bytes.split_at_mut(binary_len);
let slice = std::slice::from_raw_parts_mut(mine.as_mut_ptr() as *mut T, self.len());
std::ptr::write(self, Vec::from_raw_parts(slice.as_mut_ptr(), self.len(), self.len()));
for element in self.iter_mut() {
let temp = rest; rest = try_option!(element.exhume(temp));
}
Some(rest)
}
}
#[inline]
fn verify<'a,'b>(&'a self, bytes: &'b [u8]) -> Option<&'b [u8]> {
let binary_len = self.len() * mem::size_of::<T>();
if binary_len > bytes.len() { None }
else {
let mut rest = &bytes[binary_len..];
if unsafe { mem::transmute::<*const T,*const u8>((&self[..]).as_ptr()) } != bytes.as_ptr() { return None }
for element in self.iter() {
let temp = rest; rest = try_option!(element.verify(temp));
}
Some(rest)
}
}
}
impl<'c, T: Abomonation> Abomonation for &'c [T] {
#[inline]
unsafe fn embalm(&mut self) {
std::ptr::write(self, std::slice::from_raw_parts(EMPTY as *mut T, self.len()));
}
#[inline]
unsafe fn entomb(&self, bytes: &mut Vec<u8>) {
let position = bytes.len();
bytes.write_all(typed_to_bytes(self)).unwrap();
for element in bytes_to_typed::<T>(&mut bytes[position..], self.len()) { element.embalm(); }
for element in self.iter() { element.entomb(bytes); }
}
#[inline]
unsafe fn exhume<'a,'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
let binary_len = self.len() * mem::size_of::<T>();
if binary_len > bytes.len() { None }
else {
let (mine, mut rest) = bytes.split_at_mut(binary_len);
let slice = std::slice::from_raw_parts_mut(mine.as_mut_ptr() as *mut T, self.len());
for element in slice.iter_mut() {
let temp = rest;
rest = try_option!(element.exhume(temp));
}
*self = slice;
Some(rest)
}
}
#[inline]
fn verify<'a,'b>(&'a self, bytes: &'b [u8]) -> Option<&'b [u8]> {
let binary_len = self.len() * mem::size_of::<T>();
if binary_len > bytes.len() { None }
else {
let mut rest = &bytes[binary_len..];
if unsafe { mem::transmute::<*const T,*const u8>((&self[..]).as_ptr()) } != bytes.as_ptr() { return None }
for element in self.iter() {
let temp = rest;
rest = try_option!(element.verify(temp));
}
Some(rest)
}
}
}
impl<T: Abomonation> Abomonation for Box<T> {
#[inline]
unsafe fn embalm(&mut self) {
std::ptr::write(self, mem::transmute(EMPTY as *mut T));
}
#[inline]
unsafe fn entomb(&self, bytes: &mut Vec<u8>) {
let position = bytes.len();
bytes.write_all(std::slice::from_raw_parts(mem::transmute(&**self), mem::size_of::<T>())).unwrap();
bytes_to_typed::<T>(&mut bytes[position..], 1)[0].embalm();
(**self).entomb(bytes);
}
#[inline]
unsafe fn exhume<'a,'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
let binary_len = mem::size_of::<T>();
if binary_len > bytes.len() { None }
else {
let (mine, mut rest) = bytes.split_at_mut(binary_len);
std::ptr::write(self, mem::transmute(mine.as_mut_ptr() as *mut T));
let temp = rest; rest = try_option!((**self).exhume(temp));
Some(rest)
}
}
#[inline]
fn verify<'a,'b>(&'a self, bytes: &'b [u8]) -> Option<&'b [u8]> {
let binary_len = mem::size_of::<T>();
if binary_len > bytes.len() { None }
else {
let mut rest = &bytes[binary_len..];
if unsafe { mem::transmute::<*const T,*const u8>(&**self) } != bytes.as_ptr() { return None }
let temp = rest; rest = try_option!((**self).verify(temp));
Some(rest)
}
}
}
#[inline] unsafe fn typed_to_bytes<T>(slice: &[T]) -> &[u8] {
std::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len() * mem::size_of::<T>())
}
#[inline] unsafe fn bytes_to_typed<T>(slice: &mut [u8], len: usize) -> &mut [T] {
std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut T, len)
}