use prelude::*;
use core::{ptr, cmp, mem, fmt};
#[must_use]
pub struct Block {
size: usize,
ptr: Pointer<u8>,
}
impl Block {
#[inline]
pub unsafe fn from_raw_parts(ptr: Pointer<u8>, size: usize) -> Block {
Block {
size: size,
ptr: ptr,
}
}
#[inline]
pub fn empty(ptr: Pointer<u8>) -> Block {
Block {
size: 0,
ptr: ptr,
}
}
#[inline]
pub fn empty_left(&self) -> Block {
Block::empty(self.ptr.clone())
}
#[inline]
#[allow(cast_possible_wrap)]
pub fn empty_right(&self) -> Block {
Block {
size: 0,
ptr: unsafe {
self.ptr.clone().offset(self.size as isize)
},
}
}
#[inline]
pub fn merge_right(&mut self, block: &mut Block) -> Result<(), ()> {
if block.is_empty() {
Ok(())
} else if self.left_to(block) {
self.size += block.pop().size;
Ok(())
} else { Err(()) }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.size == 0
}
pub fn size(&self) -> usize {
self.size
}
#[inline]
pub fn aligned_to(&self, align: usize) -> bool {
*self.ptr as usize % align == 0
}
#[inline]
pub fn copy_to(&self, block: &mut Block) {
log!(INTERNAL, "Copying {:?} to {:?}", *self, *block);
assert!(self.size <= block.size, "Block too small.");
unsafe {
ptr::copy_nonoverlapping(*self.ptr, *block.ptr, self.size);
}
}
pub fn sec_zero(&mut self) {
use core::intrinsics;
if cfg!(feature = "security") {
log!(INTERNAL, "Zeroing {:?}", *self);
unsafe {
intrinsics::volatile_set_memory(*self.ptr, 0, self.size);
}
}
}
#[inline]
pub fn pop(&mut self) -> Block {
unborrow!(mem::replace(self, Block::empty(self.ptr.clone())))
}
#[inline]
pub fn left_to(&self, to: &Block) -> bool {
self.size + *self.ptr as usize == *to.ptr as usize
}
#[inline]
#[allow(cast_possible_wrap)]
pub fn split(self, pos: usize) -> (Block, Block) {
assert!(pos <= self.size, "Split {} out of bound (size is {})!", pos, self.size);
(
Block {
size: pos,
ptr: self.ptr.clone(),
},
Block {
size: self.size - pos,
ptr: unsafe {
self.ptr.offset(pos as isize)
},
}
)
}
#[inline]
#[allow(cast_possible_wrap)]
pub fn align(&mut self, align: usize) -> Option<(Block, Block)> {
log!(INTERNAL, "Padding {:?} to align {}", self, align);
let aligner = (align - *self.ptr as usize % align) % align;
if aligner < self.size {
let old = self.pop();
Some((
Block {
size: aligner,
ptr: old.ptr.clone(),
},
Block {
size: old.size - aligner,
ptr: unsafe {
old.ptr.offset(aligner as isize)
},
}
))
} else {
log!(INTERNAL, "Unable to align block.");
None
}
}
#[inline]
pub fn mark_free(self) -> Block {
#[cfg(feature = "debugger")]
::shim::debug::mark_free(*self.ptr as *const u8, self.size);
self
}
#[inline]
pub fn mark_uninitialized(self) -> Block {
#[cfg(feature = "debugger")]
::shim::debug::mark_unintialized(*self.ptr as *const u8, self.size);
self
}
}
impl From<Block> for Pointer<u8> {
fn from(from: Block) -> Pointer<u8> {
from.ptr
}
}
impl PartialOrd for Block {
#[inline]
fn partial_cmp(&self, other: &Block) -> Option<cmp::Ordering> {
self.ptr.partial_cmp(&other.ptr)
}
}
impl Ord for Block {
#[inline]
fn cmp(&self, other: &Block) -> cmp::Ordering {
self.ptr.cmp(&other.ptr)
}
}
impl cmp::PartialEq for Block {
#[inline]
fn eq(&self, other: &Block) -> bool {
*self.ptr == *other.ptr
}
}
impl cmp::Eq for Block {}
impl fmt::Debug for Block {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "0x{:x}[{}]", *self.ptr as usize, self.size)
}
}
#[cfg(test)]
mod test {
use prelude::*;
#[test]
fn test_array() {
let arr = b"Lorem ipsum dolor sit amet";
let block = unsafe {
Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
};
let (mut lorem, mut rest) = block.split(5);
assert_eq!(lorem.size(), 5);
assert_eq!(lorem.size() + rest.size(), arr.len());
assert!(lorem < rest);
assert_eq!(lorem, lorem);
assert!(!rest.is_empty());
assert!(lorem.align(2).unwrap().1.aligned_to(2));
assert!(rest.align(15).unwrap().1.aligned_to(15));
assert_eq!(*Pointer::from(lorem) as usize + 5, *Pointer::from(rest) as usize);
}
#[test]
fn test_merge() {
let arr = b"Lorem ipsum dolor sit amet";
let block = unsafe {
Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
};
let (mut lorem, mut rest) = block.split(5);
lorem.merge_right(&mut rest).unwrap();
let mut tmp = rest.split(0).0;
assert!(tmp.is_empty());
lorem.split(2).0.merge_right(&mut tmp).unwrap();
}
#[test]
#[should_panic]
fn test_oob() {
let arr = b"lorem";
let block = unsafe {
Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
};
block.split(6);
}
#[test]
fn test_mutate() {
let mut arr = [0u8, 2, 0, 0, 255, 255];
let block = unsafe {
Block::from_raw_parts(Pointer::new(&mut arr[0] as *mut u8), 6)
};
let (a, mut b) = block.split(2);
a.copy_to(&mut b);
assert_eq!(arr, [0, 2, 0, 2, 255, 255]);
}
#[test]
fn test_empty_lr() {
let arr = b"Lorem ipsum dolor sit amet";
let block = unsafe {
Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
};
assert!(block.empty_left().is_empty());
assert!(block.empty_right().is_empty());
assert_eq!(*Pointer::from(block.empty_left()) as *const u8, arr.as_ptr());
assert_eq!(block.empty_right(), block.split(arr.len()).1);
}
}