[−][src]Struct static_alloc::Slab
An allocator whose memory resource has static storage duration.
The type parameter T
is used only to annotate the required size and alignment of the region
and has no futher use. Note that in particular there is no safe way to retrieve or unwrap an
inner instance even if the Slab
was not constructed as a shared global static. Nevertheless,
Usage as global allocator
You can use the stable rust attribute to use an instance of this type as the global allocator.
use static_alloc::Slab; #[global_allocator] static A: Slab<[u8; 1 << 16]> = Slab::uninit(); fn main() { }
Take care, some runtime features of Rust will allocator some memory before or after your own code. In particular, it was found to be be tricky to find out more on the usage of the builtin test framework which seemingly allocates some structures per test.
Usage as a non-dropping local allocator
It is also possible to use a Slab
as a stack local allocator or a specialized allocator. The
interface offers some utilities for allocating values from references to shared or unshared
instances directly. Note: this will never call the Drop
implementation of the allocated
type. In particular, it would almost surely not be safe to Pin
the values.
use static_alloc::Slab; let local: Slab<[u64; 3]> = Slab::uninit(); let one = local.leak(0_u64).unwrap(); let two = local.leak(1_u64).unwrap(); let three = local.leak(2_u64).unwrap(); // Exhausted the space. assert!(local.leak(3_u64).is_err());
Mind that the supplied type parameter influenced both size and alignment and a [u8; 24]
does not guarantee being able to allocation three u64
even though most targets have a minimum
alignment requirement of 16 and it works fine on those.
// Just enough space for `u128` but no alignment requirement. let local: Slab<[u8; 16]> = Slab::uninit(); // May or may not return an err. let _ = local.leak(0_u128);
Instead use the type parameter to Slab
as a hint for the best alignment.
// Enough space and align for `u128`. let local: Slab<[u128; 1]> = Slab::uninit(); assert!(local.leak(0_u128).is_ok());
Usage as a (local) bag of bits
It is of course entirely possible to use a local instance instead of a single global allocator.
For example you could utilize the pointer interface directly to build a #[no_std]
dynamic
data structure in an environment without extern lib alloc
. This feature was the original
motivation behind the crate but no such data structures are provided here so a quick sketch of
the idea must do:
use core::alloc; use static_alloc::Slab; #[repr(align(4096))] struct PageTable { // some non-trivial type. } impl PageTable { pub unsafe fn new(into: *mut u8) -> &'static mut Self { // ... } } // Allocator for pages for page tables. Provides 64 pages. When the // program/kernel is provided as an ELF the bootloader reserves // memory for us as part of the loading process that we can use // purely for page tables. Replaces asm `paging: .BYTE <size>;` static Paging: Slab<[u8; 1 << 18]> = Slab::uninit(); fn main() { let layout = alloc::Layout::new::<PageTable>(); let memory = Paging.alloc(layout).unwrap(); let table = unsafe { PageTable::new(memory.as_ptr()) }; }
A similar structure would of course work to allocate some non-'static' objects from a temporary
Slab`.
More insights
WIP: May want to wrap moving values into an allocate region into a safe abstraction with correct lifetimes. This would include slices.
Methods
impl<T> Slab<T>
[src]
pub const fn uninit() -> Self
[src]
Make a new allocatable slab of certain byte size and alignment.
The storage will contain uninitialized bytes.
pub fn zeroed() -> Self
[src]
Make a new allocatable slab of certain byte size and alignment.
The storage will contain zeroed bytes. This is not yet available
as a const fn
which currently limits its potential usefulness
but there is no good reason not to provide it regardless.
pub const fn new(storage: T) -> Self
[src]
Make a new allocatable slab provided with some bytes it can hand out.
Note that storage
will never be dropped and there is no way to get it back.
pub fn alloc(&self, layout: Layout) -> Option<NonNull<u8>>
[src]
Allocate a region of memory.
This is a safe alternative to GlobalAlloc::alloc.
Panics
This function will panic if the requested layout has a size of 0
. For the use in a
GlobalAlloc
this is explicitely forbidden to request and would allow any behaviour but we
instead strictly check it.
pub fn leak<V>(&self, val: V) -> Result<&mut V, NewError<V>>
[src]
Allocate a value for the lifetime of the allocator.
The value is leaked in the sense that
- the drop implementation of the allocated value is never called;
- reusing the memory for another allocation in the same
Slab
requires manual unsafe code to handle dropping and reinitialization.
However, it does not mean that the underlying memory used for the allocated value is never
reclaimed. If the Slab
itself is a stack value then it will get reclaimed together with
it.
Safety notice
It is important to understand that it is undefined behaviour to reuse the allocation for
the whole lifetime of the returned reference. That is, dropping the allocation in-place
while the reference is still within its lifetime comes with the exact same unsafety caveats
as ManuallyDrop::drop
.
#[derive(Debug, Default)] struct FooBar { // ... } let local: Slab<[FooBar; 3]> = Slab::uninit(); let one = local.leak(FooBar::default()).unwrap(); // Dangerous but justifiable. let one = unsafe { // Ensures there is no current mutable borrow. core::ptr::drop_in_place(&mut *one); };
Usage
use static_alloc::Slab; let local: Slab<[u64; 3]> = Slab::uninit(); let one = local.leak(0_u64).unwrap(); assert_eq!(*one, 0); *one = 42;
Limitations
Only sized values can be allocated in this manner for now, unsized values are blocked on
stabilization of ptr::slice_from_raw_parts
. We can not otherwise get a fat pointer to
the allocated region.
Trait Implementations
impl<T> Sync for Slab<T>
[src]
impl<T> GlobalAlloc for Slab<T>
[src]
unsafe fn alloc(&self, layout: Layout) -> *mut u8
[src]
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout)
[src]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8
1.28.0[src]
Behaves like alloc
, but also ensures that the contents are set to zero before being returned. Read more
unsafe fn realloc(
&self,
ptr: *mut u8,
layout: Layout,
new_size: usize
) -> *mut u8
1.28.0[src]
&self,
ptr: *mut u8,
layout: Layout,
new_size: usize
) -> *mut u8
Shrink or grow a block of memory to the given new_size
. The block is described by the given ptr
pointer and layout
. Read more
Auto Trait Implementations
Blanket Implementations
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T> From<T> for T
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,