#![no_std]
#![deny(rust_2018_idioms)]
#![warn(clippy::missing_safety_doc, missing_docs)]
mod alloc;
mod allocators;
mod brand;
mod containers;
mod layout;
mod lock;
mod r#static;
mod strategy;
pub use alloc::Alloc;
pub use allocators::{Arena, Array};
pub use brand::Brand;
pub use containers::export::*;
pub use layout::{Align, Layout};
pub use r#static::Static;
pub(crate) use strategy::FAILURE_MESSAGE;
pub use strategy::{Abort, Fallible, Optional, Panic, Strategy};
#[cfg(feature = "platform")]
mod platform;
#[cfg(feature = "platform")]
pub use platform::{platform, PlatformAllocator};
#[cfg(feature = "global")]
pub mod global;
#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum Error {
OutOfMemory,
InvalidLayout,
WrongAllocator,
#[cfg(feature = "global")]
NoGlobalAllocator,
#[cfg(feature = "platform")]
PlatformError,
IoError(recore::io::Error),
Other,
}
recore::fmt::derive!(Debug for enum Error {
OutOfMemory,
InvalidLayout,
WrongAllocator,
#[cfg(feature = "global")]
NoGlobalAllocator,
#[cfg(feature = "platform")]
PlatformError,
IoError(e),
Other,
});
pub unsafe trait Allocator {
fn brand(&self) -> &Brand;
fn alloc_bytes(&self, layout: Layout) -> Result<Alloc<'_, u8>, Error>;
fn dealloc_bytes<'this>(&'this self, alloc: Alloc<'this, u8>);
fn dangling(&self, align: Align) -> Alloc<'_, u8>;
fn total_size(&self) -> Option<usize> { None }
fn remaining_size(&self) -> Option<usize> { None }
fn alloc_zeroed(&self, layout: Layout) -> Result<Alloc<'_, u8>, Error> {
let new = self.alloc_bytes(layout)?;
unsafe { new.ptr().cast::<u8>().write_bytes(0, layout.size) };
Ok(new)
}
fn realloc<'this>(
&'this self,
alloc: Alloc<'this, u8>,
layout: Layout,
) -> Result<Alloc<'this, u8>, Error> {
if alloc.allocator().brand() != self.brand() {
return Err(Error::WrongAllocator);
}
if alloc.layout().size > layout.size {
self.grow(alloc, layout)
} else {
self.shrink(alloc, layout)
}
}
fn grow<'this>(
&'this self,
alloc: Alloc<'this, u8>,
layout: Layout,
) -> Result<Alloc<'this, u8>, Error> {
if alloc.allocator().brand() != self.brand() {
return Err(Error::WrongAllocator);
}
if layout.size <= alloc.size() && layout.align <= alloc.align() {
return Ok(alloc);
}
let new = self.alloc_bytes(layout)?;
let size = new.size().min(alloc.size());
unsafe { new.ptr().cast::<u8>().copy_from(alloc.ptr().cast(), size) };
Ok(new)
}
fn shrink<'this>(
&'this self,
alloc: Alloc<'this, u8>,
layout: Layout,
) -> Result<Alloc<'this, u8>, Error> {
if alloc.allocator().brand() != self.brand() {
return Err(Error::WrongAllocator);
}
if layout.size >= alloc.size() && layout.align <= alloc.align() {
return Ok(alloc);
}
let new = self.alloc_bytes(layout)?;
let size = new.size().min(alloc.size());
unsafe { new.ptr().cast::<u8>().copy_from(alloc.ptr().cast(), size) };
Ok(new)
}
}
pub unsafe trait AllocatorExt: Allocator {
fn alloc<T>(&self) -> Result<Alloc<'_, T>, Error> {
self.alloc_bytes(Layout::of::<T>())
.map(|alloc| alloc.cast())
}
fn dealloc<'this, T>(&'this self, alloc: Alloc<'this, T>) {
self.dealloc_bytes(alloc.cast())
}
fn alloc_with<T>(&self, data: T) -> Result<Alloc<'_, T>, (T, Error)> {
let mut ptr = match self.alloc::<T>() {
Ok(ptr) => ptr,
Err(e) => return Err((data, e)),
};
ptr.write(data);
Ok(ptr)
}
fn as_dyn(&self) -> &dyn Allocator
where
Self: Sized,
{
self
}
}
unsafe impl<A: Allocator + ?Sized> AllocatorExt for A {}
unsafe impl<A: Allocator + ?Sized> Allocator for &A {
fn brand(&self) -> &Brand {
(*self).brand()
}
fn alloc_bytes(&self, layout: Layout) -> Result<Alloc<'_, u8>, Error> {
(*self).alloc_bytes(layout)
}
fn dealloc_bytes<'this>(&'this self, alloc: Alloc<'this, u8>) {
(*self).dealloc_bytes(alloc)
}
fn dangling(&self, align: Align) -> Alloc<'_, u8> {
(*self).dangling(align)
}
fn alloc_zeroed(&self, layout: Layout) -> Result<Alloc<'_, u8>, Error> {
(*self).alloc_zeroed(layout)
}
fn realloc<'this>(
&'this self,
alloc: Alloc<'this, u8>,
layout: Layout,
) -> Result<Alloc<'this, u8>, Error> {
(*self).realloc(alloc, layout)
}
fn grow<'this>(
&'this self,
alloc: Alloc<'this, u8>,
layout: Layout,
) -> Result<Alloc<'this, u8>, Error> {
(*self).grow(alloc, layout)
}
fn shrink<'this>(
&'this self,
alloc: Alloc<'this, u8>,
layout: Layout,
) -> Result<Alloc<'this, u8>, Error> {
(*self).shrink(alloc, layout)
}
}