#![feature(
alloc,
coerce_unsized,
core_intrinsics,
heap_api,
placement_new_protocol,
placement_in_syntax,
raw,
unsize
)]
use std::any::Any;
use std::borrow::{Borrow, BorrowMut};
use std::error::Error;
use std::fmt;
use std::marker::Unsize;
use std::mem;
use std::ops::Place as StdPlace;
use std::ops::{CoerceUnsized, Deref, DerefMut, InPlace, Placer};
use alloc::heap;
extern crate alloc;
mod scoped;
pub use scoped::ScopedAllocator;
pub unsafe trait Allocator {
fn allocate_val<'a, T>(&'a self, val: T) -> Result<Allocated<'a, T, Self>, (AllocatorError, T)>
where Self: Sized
{
use std::ptr;
let (size, align) = (mem::size_of::<T>(), mem::align_of::<T>());
match unsafe { self.allocate_raw(size, align) } {
Ok(ptr) => {
let item = ptr as *mut T;
unsafe { ptr::write(item, val) };
Ok(Allocated {
item: item,
allocator: self,
size: size,
align: align,
})
}
Err(e) => Err((e, val)),
}
}
fn allocate<'a, T>(&'a self) -> Result<Place<'a, T, Self>, AllocatorError>
where Self: Sized
{
let (size, align) = (mem::size_of::<T>(), mem::align_of::<T>());
match unsafe { self.allocate_raw(size, align) } {
Ok(ptr) => {
Ok(Place {
ptr: ptr as *mut T,
allocator: self,
finalized: false,
})
}
Err(e) => Err(e),
}
}
unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<*mut u8, AllocatorError>;
unsafe fn deallocate_raw(&self, ptr: *mut u8, size: usize, align: usize);
}
#[derive(Debug, Eq, PartialEq)]
pub enum AllocatorError {
OutOfMemory,
AllocatorSpecific(String),
}
impl fmt::Display for AllocatorError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.description())
}
}
impl Error for AllocatorError {
fn description(&self) -> &str {
use AllocatorError::*;
match *self {
OutOfMemory => {
"Allocator out of memory."
}
AllocatorSpecific(ref reason) => {
reason
}
}
}
}
#[derive(Debug)]
pub struct HeapAllocator;
const HEAP: &'static HeapAllocator = &HeapAllocator;
unsafe impl Allocator for HeapAllocator {
unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<*mut u8, AllocatorError> {
let ptr = if size != 0 {
heap::allocate(size, align)
} else {
heap::EMPTY as *mut u8
};
if ptr.is_null() {
Err(AllocatorError::OutOfMemory)
} else {
Ok(ptr)
}
}
unsafe fn deallocate_raw(&self, ptr: *mut u8, size: usize, align: usize) {
heap::deallocate(ptr, size, align)
}
}
pub struct Allocated<'a, T: 'a + ?Sized, A: 'a + Allocator> {
item: *mut T,
allocator: &'a A,
size: usize,
align: usize,
}
impl<'a, T: ?Sized, A: Allocator> Deref for Allocated<'a, T, A> {
type Target = T;
fn deref<'b>(&'b self) -> &'b T {
unsafe { mem::transmute(self.item) }
}
}
impl<'a, T: ?Sized, A: Allocator> DerefMut for Allocated<'a, T, A> {
fn deref_mut<'b>(&'b mut self) -> &'b mut T {
unsafe { mem::transmute(self.item) }
}
}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Allocated<'a, U, A>> for Allocated<'a, T, A> {}
impl<'a, A: Allocator> Allocated<'a, Any, A> {
pub fn downcast<T: Any>(self) -> Result<Allocated<'a, T, A>, Allocated<'a, Any, A>> {
use std::raw::TraitObject;
if self.is::<T>() {
let obj: TraitObject = unsafe { mem::transmute(self.item as *mut Any) };
let new_allocated = Allocated {
item: unsafe { mem::transmute(obj.data) },
allocator: self.allocator,
size: self.size,
align: self.align,
};
mem::forget(self);
Ok(new_allocated)
} else {
Err(self)
}
}
}
impl<'a, T: ?Sized, A: Allocator> Borrow<T> for Allocated<'a, T, A> {
fn borrow(&self) -> &T {
&**self
}
}
impl<'a, T: ?Sized, A: Allocator> BorrowMut<T> for Allocated<'a, T, A> {
fn borrow_mut(&mut self) -> &mut T {
&mut **self
}
}
impl<'a, T: ?Sized, A: Allocator> Drop for Allocated<'a, T, A> {
#[inline]
fn drop(&mut self) {
use std::intrinsics::drop_in_place;
unsafe {
drop_in_place(self.item);
self.allocator.deallocate_raw(self.item as *mut u8, self.size, self.align);
}
}
}
pub struct Place<'a, T: 'a, A: 'a + Allocator> {
allocator: &'a A,
ptr: *mut T,
finalized: bool
}
impl<'a, T: 'a, A: 'a + Allocator> Placer<T> for Place<'a, T, A> {
type Place = Self;
fn make_place(self) -> Self { self }
}
impl<'a, T: 'a, A: 'a + Allocator> InPlace<T> for Place<'a, T, A> {
type Owner = Allocated<'a, T, A>;
unsafe fn finalize(mut self) -> Self::Owner {
self.finalized = true;
Allocated {
item: self.ptr,
allocator: self.allocator,
size: mem::size_of::<T>(),
align: mem::align_of::<T>(),
}
}
}
impl<'a, T: 'a, A: 'a + Allocator> StdPlace<T> for Place<'a, T, A> {
fn pointer(&mut self) -> *mut T {
self.ptr
}
}
impl<'a, T: 'a, A: 'a + Allocator> Drop for Place<'a, T, A> {
#[inline]
fn drop(&mut self) {
use std::intrinsics::drop_in_place;
if !self.finalized { unsafe {
let (size, align) = (mem::size_of::<T>(), mem::align_of::<T>());
drop_in_place(self.ptr);
self.allocator.deallocate_raw(self.ptr as *mut u8, size, align);
} }
}
}