//! The default Rust allocator.

use core::prelude::*;
use core::mem;
use core::num::Int;
use core::intrinsics;
use alloc::heap;
pub use allocator::{Allocator};

pub struct RustAlloc;
impl Copy for RustAlloc {}

impl Allocator for RustAlloc {
    unsafe fn alloc<T>(&mut self, items: uint) -> Option<*mut T> { #![inline]
        let bytes = as_bytes!(items);
        let p: *mut T = heap::allocate(items, mem::align_of::<T>()) as *mut T;
        nullcheck!(p);
        Some(p)
    }

    // Apparently liballoc has no `calloc`.

    unsafe fn realloc<T>(&mut self, buf: &mut *mut T, current: uint, exact: uint) -> Option<uint> { #![inline]
        let currentbytes = as_bytes!(current);
        let exactbytes = as_bytes!(exact);
        let align = mem::align_of::<T>();
        let usable = heap::usable_size(exactbytes, align) / mem::size_of::<T>();

        let p = heap::reallocate((*buf) as *mut u8, currentbytes, exactbytes, align) as *mut T;
        nullcheck!(p);
        *buf = p;
        Some(usable)
    }

    unsafe fn free<T>(&mut self, buf: *mut T, items: uint) { #![inline]
        let p = buf as *mut u8;
        let size = items * mem::size_of::<T>();
        let align = mem::align_of::<T>();
        heap::deallocate(p, size, align)
    }
}