use std::mem; use std::io::Write; use std::io::Result as IOResult;
use std::marker::PhantomData;
use std::num::*;
pub mod abomonated;
#[inline]
pub unsafe fn encode<T: Abomonation, W: Write>(typed: &T, write: &mut W) -> IOResult<()> {
let slice = std::slice::from_raw_parts(mem::transmute(typed), mem::size_of::<T>());
write.write_all(slice)?;
typed.entomb(write)?;
Ok(())
}
#[inline]
pub unsafe 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 = mem::transmute(split1.get_unchecked_mut(0));
if let Some(remaining) = result.exhume(split2) {
Some((result, remaining))
}
else {
None
}
}
}
#[inline]
pub fn measure<T: Abomonation>(typed: &T) -> usize {
mem::size_of::<T>() + typed.extent()
}
pub trait Abomonation {
#[inline(always)] unsafe fn entomb<W: Write>(&self, _write: &mut W) -> IOResult<()> { Ok(()) }
#[inline(always)] unsafe fn exhume<'a,'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> { Some(bytes) }
#[inline(always)] fn extent(&self) -> usize { 0 }
}
#[macro_export]
#[deprecated(since="0.5", note="please use the abomonation_derive crate")]
macro_rules! unsafe_abomonate {
($t:ty) => {
impl Abomonation for $t { }
};
($t:ty : $($field:ident),*) => {
impl Abomonation for $t {
#[inline] unsafe fn entomb<W: ::std::io::Write>(&self, write: &mut W) -> ::std::io::Result<()> {
$( self.$field.entomb(write)?; )*
Ok(())
}
#[inline] unsafe fn exhume<'a,'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
$( let temp = bytes; bytes = self.$field.exhume(temp)?; )*
Some(bytes)
}
#[inline] fn extent(&self) -> usize {
let mut size = 0;
$( size += self.$field.extent(); )*
size
}
}
};
}
macro_rules! tuple_abomonate {
( $($name:ident)+) => (
impl<$($name: Abomonation),*> Abomonation for ($($name,)*) {
#[allow(non_snake_case)]
#[inline(always)] unsafe fn entomb<WRITE: Write>(&self, write: &mut WRITE) -> IOResult<()> {
let ($(ref $name,)*) = *self;
$($name.entomb(write)?;)*
Ok(())
}
#[allow(non_snake_case)]
#[inline(always)] unsafe fn exhume<'a,'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
let ($(ref mut $name,)*) = *self;
$( let temp = bytes; bytes = $name.exhume(temp)?; )*
Some(bytes)
}
#[allow(non_snake_case)]
#[inline(always)] fn extent(&self) -> usize {
let mut size = 0;
let ($(ref $name,)*) = *self;
$( size += $name.extent(); )*
size
}
}
);
}
impl Abomonation for u8 { }
impl Abomonation for u16 { }
impl Abomonation for u32 { }
impl Abomonation for u64 { }
impl Abomonation for u128 { }
impl Abomonation for usize { }
impl Abomonation for i8 { }
impl Abomonation for i16 { }
impl Abomonation for i32 { }
impl Abomonation for i64 { }
impl Abomonation for i128 { }
impl Abomonation for isize { }
impl Abomonation for NonZeroU8 { }
impl Abomonation for NonZeroU16 { }
impl Abomonation for NonZeroU32 { }
impl Abomonation for NonZeroU64 { }
impl Abomonation for NonZeroU128 { }
impl Abomonation for NonZeroUsize { }
impl Abomonation for NonZeroI8 { }
impl Abomonation for NonZeroI16 { }
impl Abomonation for NonZeroI32 { }
impl Abomonation for NonZeroI64 { }
impl Abomonation for NonZeroI128 { }
impl Abomonation for NonZeroIsize { }
impl Abomonation for f32 { }
impl Abomonation for f64 { }
impl Abomonation for bool { }
impl Abomonation for () { }
impl Abomonation for char { }
impl Abomonation for ::std::time::Duration { }
impl<T> Abomonation for PhantomData<T> {}
impl<T: Abomonation> Abomonation for Option<T> {
#[inline(always)] unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
if let &Some(ref inner) = self {
inner.entomb(write)?;
}
Ok(())
}
#[inline(always)] 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 = inner.exhume(tmp)?;
}
Some(bytes)
}
#[inline] fn extent(&self) -> usize {
self.as_ref().map(|inner| inner.extent()).unwrap_or(0)
}
}
impl<T: Abomonation, E: Abomonation> Abomonation for Result<T, E> {
#[inline(always)] unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
match self {
&Ok(ref inner) => inner.entomb(write)?,
&Err(ref inner) => inner.entomb(write)?,
};
Ok(())
}
#[inline(always)] unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut[u8]) -> Option<&'b mut [u8]> {
match self {
&mut Ok(ref mut inner) => inner.exhume(bytes),
&mut Err(ref mut inner) => inner.exhume(bytes),
}
}
#[inline] fn extent(&self) -> usize {
match self {
&Ok(ref inner) => inner.extent(),
&Err(ref inner) => inner.extent(),
}
}
}
tuple_abomonate!(A);
tuple_abomonate!(A B);
tuple_abomonate!(A B C);
tuple_abomonate!(A B C D);
tuple_abomonate!(A B C D E);
tuple_abomonate!(A B C D E F);
tuple_abomonate!(A B C D E F G);
tuple_abomonate!(A B C D E F G H);
tuple_abomonate!(A B C D E F G H I);
tuple_abomonate!(A B C D E F G H I J);
tuple_abomonate!(A B C D E F G H I J K);
tuple_abomonate!(A B C D E F G H I J K L);
tuple_abomonate!(A B C D E F G H I J K L M);
tuple_abomonate!(A B C D E F G H I J K L M N);
tuple_abomonate!(A B C D E F G H I J K L M N O);
tuple_abomonate!(A B C D E F G H I J K L M N O P);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD AE);
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD AE AF);
macro_rules! array_abomonate {
($size:expr) => (
impl<T: Abomonation> Abomonation for [T; $size] {
#[inline(always)]
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
for element in self { element.entomb(write)?; }
Ok(())
}
#[inline(always)]
unsafe fn exhume<'a, 'b>(&'a mut self, mut bytes: &'b mut[u8]) -> Option<&'b mut [u8]> {
for element in self {
let tmp = bytes; bytes = element.exhume(tmp)?;
}
Some(bytes)
}
#[inline(always)] fn extent(&self) -> usize {
let mut size = 0;
for element in self {
size += element.extent();
}
size
}
}
)
}
array_abomonate!(0);
array_abomonate!(1);
array_abomonate!(2);
array_abomonate!(3);
array_abomonate!(4);
array_abomonate!(5);
array_abomonate!(6);
array_abomonate!(7);
array_abomonate!(8);
array_abomonate!(9);
array_abomonate!(10);
array_abomonate!(11);
array_abomonate!(12);
array_abomonate!(13);
array_abomonate!(14);
array_abomonate!(15);
array_abomonate!(16);
array_abomonate!(17);
array_abomonate!(18);
array_abomonate!(19);
array_abomonate!(20);
array_abomonate!(21);
array_abomonate!(22);
array_abomonate!(23);
array_abomonate!(24);
array_abomonate!(25);
array_abomonate!(26);
array_abomonate!(27);
array_abomonate!(28);
array_abomonate!(29);
array_abomonate!(30);
array_abomonate!(31);
array_abomonate!(32);
impl Abomonation for String {
#[inline]
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
write.write_all(self.as_bytes())?;
Ok(())
}
#[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 extent(&self) -> usize {
self.len()
}
}
impl<T: Abomonation> Abomonation for Vec<T> {
#[inline]
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
write.write_all(typed_to_bytes(&self[..]))?;
for element in self.iter() { element.entomb(write)?; }
Ok(())
}
#[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 = element.exhume(temp)?;
}
Some(rest)
}
}
#[inline]
fn extent(&self) -> usize {
let mut sum = mem::size_of::<T>() * self.len();
for element in self.iter() {
sum += element.extent();
}
sum
}
}
impl<T: Abomonation> Abomonation for Box<T> {
#[inline]
unsafe fn entomb<W: Write>(&self, bytes: &mut W) -> IOResult<()> {
bytes.write_all(std::slice::from_raw_parts(mem::transmute(&**self), mem::size_of::<T>()))?;
(**self).entomb(bytes)?;
Ok(())
}
#[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 = (**self).exhume(temp)?;
Some(rest)
}
}
#[inline] fn extent(&self) -> usize {
mem::size_of::<T>() + (&**self).extent()
}
}
#[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>())
}
mod network {
use Abomonation;
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, IpAddr, Ipv4Addr, Ipv6Addr};
impl Abomonation for IpAddr { }
impl Abomonation for Ipv4Addr { }
impl Abomonation for Ipv6Addr { }
impl Abomonation for SocketAddr { }
impl Abomonation for SocketAddrV4 { }
impl Abomonation for SocketAddrV6 { }
}