#![feature(core, static_assert)]
#![deny(warnings)]
use std::{mem, raw, intrinsics};
use std::slice::bytes;
pub use self::UnpackedAtom::{Dynamic, Inline, Static};
pub const DYNAMIC_TAG: u8 = 0u8;
pub const INLINE_TAG: u8 = 1u8; pub const STATIC_TAG: u8 = 2u8;
pub const MAX_INLINE_LEN: usize = 7;
#[allow(missing_copy_implementations)]
pub enum UnpackedAtom {
Dynamic(*mut ()),
Inline(u8, [u8; 7]),
Static(u32),
}
const STATIC_SHIFT_BITS: usize = 32;
#[inline(always)]
unsafe fn inline_atom_slice(x: &u64) -> raw::Slice<u8> {
#[static_assert]
const _IS_LITTLE_ENDIAN: bool = cfg!(target_endian = "little");
let x: *const u64 = x;
raw::Slice {
data: (x as *const u8).offset(1),
len: 7,
}
}
pub fn pack_static(n: u32) -> u64 {
(STATIC_TAG as u64) | ((n as u64) << STATIC_SHIFT_BITS)
}
impl UnpackedAtom {
#[inline(always)]
pub unsafe fn pack(self) -> u64 {
match self {
Static(n) => pack_static(n),
Dynamic(p) => {
let n = p as u64;
debug_assert!(0 == n & 0xf);
n
}
Inline(len, buf) => {
debug_assert!((len as usize) <= MAX_INLINE_LEN);
let mut data: u64 = (INLINE_TAG as u64) | ((len as u64) << 4);
{
let dest: &mut [u8] = mem::transmute(inline_atom_slice(&mut data));
bytes::copy_memory(&buf[..], dest);
}
data
}
}
}
#[inline(always)]
pub unsafe fn from_packed(data: u64) -> UnpackedAtom {
#[static_assert]
const _DYNAMIC_IS_UNTAGGED: bool = DYNAMIC_TAG == 0;
match (data & 0xf) as u8 {
DYNAMIC_TAG => Dynamic(data as *mut ()),
STATIC_TAG => Static((data >> STATIC_SHIFT_BITS) as u32),
INLINE_TAG => {
let len = ((data & 0xf0) >> 4) as usize;
debug_assert!(len <= MAX_INLINE_LEN);
let mut buf: [u8; 7] = [0; 7];
let src: &[u8] = mem::transmute(inline_atom_slice(&data));
bytes::copy_memory(src, &mut buf[..]);
Inline(len as u8, buf)
},
_ => panic!("impossible"),
}
}
}
#[inline(always)]
pub unsafe fn from_packed_dynamic(data: u64) -> Option<*mut ()> {
if (DYNAMIC_TAG as u64) == (data & 0xf) {
Some(data as *mut ())
} else {
None
}
}
#[inline(always)]
pub unsafe fn inline_orig_bytes<'a>(data: &'a u64) -> &'a [u8] {
match UnpackedAtom::from_packed(*data) {
Inline(len, _) => {
let src: &[u8] = mem::transmute(inline_atom_slice(data));
&src[..(len as usize)]
}
_ => intrinsics::unreachable(),
}
}