use core::alloc::Allocator;
use core::alloc::AllocError;
use core::alloc::Layout;
use core::ptr::NonNull;
use core::ptr::null_mut;
use core::ptr::slice_from_raw_parts_mut;
use crate::global::dealloc;
use crate::global::realloc;
use crate::System;
unsafe impl Allocator for System {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!(crate::is_inited());
let p = unsafe { realloc(null_mut(), layout.size()) };
if p.is_null() {
Err(AllocError)
} else {
let p = slice_from_raw_parts_mut(p.cast(), layout.size());
Ok(unsafe { NonNull::new_unchecked(p) })
}
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, _layout: Layout) {
debug_assert!(crate::is_inited());
unsafe { dealloc(ptr.as_ptr().cast()) };
}
unsafe fn grow(&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout)
-> Result<NonNull<[u8]>, AllocError> {
debug_assert!(
new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"
);
debug_assert!(crate::is_inited());
let new_ptr: *mut u8 = realloc(ptr.as_ptr().cast(), new_layout.size()).cast();
let new_ptr = if new_ptr.is_null() {
return Err(AllocError);
} else {
let new_ptr = slice_from_raw_parts_mut(new_ptr, new_layout.size());
unsafe { NonNull::new_unchecked(new_ptr) }
};
if ptr != new_ptr.as_non_null_ptr() {
unsafe {
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size());
self.deallocate(ptr, old_layout);
}
}
Ok(new_ptr)
}
unsafe fn grow_zeroed(&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout)
-> Result<NonNull<[u8]>, AllocError> {
debug_assert!(
new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"
);
debug_assert!(crate::is_inited());
let new_ptr = self.grow(ptr, old_layout, new_layout)?;
let size = new_layout.size() - old_layout.size();
let ext = ptr.add(old_layout.size());
unsafe { ext.as_ptr().write_bytes(0, size) }
Ok(new_ptr)
}
unsafe fn shrink(&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout)
-> Result<NonNull<[u8]>, AllocError> {
debug_assert!(
new_layout.size() <= old_layout.size(),
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
);
debug_assert!(crate::is_inited());
let new_ptr: *mut u8 = realloc(ptr.as_ptr().cast(), new_layout.size()).cast();
let new_ptr = if new_ptr.is_null() {
let new_ptr = self.allocate(new_layout)?;
unsafe {
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size());
self.deallocate(ptr, old_layout);
}
new_ptr
} else {
let new_ptr = slice_from_raw_parts_mut(new_ptr, new_layout.size());
unsafe { NonNull::new_unchecked(new_ptr) }
};
Ok(new_ptr)
}
}
#[cfg(test)]
#[cfg(not(feature = "global"))]
mod tests {
#![allow(unexpected_cfgs)]
use super::*;
#[test]
#[cfg_attr(feature = "static-link", ignore = "for static-mut only")]
fn not_inited() {
#[cfg(not(feature = "static-link"))]
unsafe {
crate::REALLOC = crate::fake as crate::Realloc;
};
assert!(!crate::is_inited());
}
#[test]
#[cfg_attr(debug_assertions, should_panic)]
#[cfg_attr(feature = "static-link", ignore = "for static-mut only")]
fn allocate_not_inited() {
#[cfg(not(feature = "static-link"))]
unsafe {
crate::REALLOC = crate::fake as crate::Realloc;
};
assert!(!crate::is_inited());
let l = unsafe { Layout::from_size_align_unchecked(size_of::<usize>(), align_of::<usize>()) };
assert!(System.allocate(l).is_err())
}
#[test]
#[cfg_attr(not(fake_alloc), ignore = "set RUSTFLAGS='--cfg=fake_alloc' to enable.")]
fn inited_fake() {
crate::tests::init_fake();
assert!(crate::is_inited());
}
#[test]
#[cfg_attr(not(fake_alloc), ignore = "set RUSTFLAGS='--cfg=fake_alloc' to enable.")]
fn allocate_fake() {
crate::tests::init_fake();
let l = unsafe { Layout::from_size_align_unchecked(size_of::<usize>(), align_of::<usize>()) };
assert!(System.allocate(l).is_err())
}
}