pub unsafe trait Allocator {
    // Required methods
    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);

    // Provided methods
    fn allocate_zeroed(
        &self,
        layout: Layout
    ) -> Result<NonNull<[u8]>, AllocError> { ... }
    unsafe fn grow(
        &self,
        ptr: NonNull<u8>,
        old_layout: Layout,
        new_layout: Layout
    ) -> Result<NonNull<[u8]>, AllocError> { ... }
    unsafe fn grow_zeroed(
        &self,
        ptr: NonNull<u8>,
        old_layout: Layout,
        new_layout: Layout
    ) -> Result<NonNull<[u8]>, AllocError> { ... }
    unsafe fn shrink(
        &self,
        ptr: NonNull<u8>,
        old_layout: Layout,
        new_layout: Layout
    ) -> Result<NonNull<[u8]>, AllocError> { ... }
    fn by_ref(&self) -> &Self
       where Self: Sized { ... }
}
Expand description

An implementation of Allocator can allocate, grow, shrink, and deallocate arbitrary blocks of data described via Layout.

Allocator is designed to be implemented on ZSTs, references, or smart pointers because having an allocator like MyAlloc([u8; N]) cannot be moved, without updating the pointers to the allocated memory.

Unlike GlobalAlloc, zero-sized allocations are allowed in Allocator. If an underlying allocator does not support this (like jemalloc) or return a null pointer (such as libc::malloc), this must be caught by the implementation.

Currently allocated memory

Some of the methods require that a memory block be currently allocated via an allocator. This means that:

  • the starting address for that memory block was previously returned by allocate, grow, or shrink, and

  • the memory block has not been subsequently deallocated, where blocks are either deallocated directly by being passed to deallocate or were changed by being passed to grow or shrink that returns Ok. If grow or shrink have returned Err, the passed pointer remains valid.

Memory fitting

Some of the methods require that a layout fit a memory block. What it means for a layout to “fit” a memory block means (or equivalently, for a memory block to “fit” a layout) is that the following conditions must hold:

  • The block must be allocated with the same alignment as layout.align(), and

  • The provided layout.size() must fall in the range min ..= max, where:

    • min is the size of the layout most recently used to allocate the block, and
    • max is the latest actual size returned from allocate, grow, or shrink.

Safety

  • Memory blocks returned from an allocator must point to valid memory and retain their validity until the instance and all of its clones are dropped,

  • cloning or moving the allocator must not invalidate memory blocks returned from this allocator. A cloned allocator must behave like the same allocator, and

  • any pointer to a memory block which is currently allocated may be passed to any other method of the allocator.

Required Methods§

source

fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>

Attempts to allocate a block of memory.

On success, returns a NonNull<[u8]> meeting the size and alignment guarantees of layout.

The returned block may have a larger size than specified by layout.size(), and may or may not have its contents initialized.

Errors

Returning Err indicates that either memory is exhausted or layout does not meet allocator’s size or alignment constraints.

Implementations are encouraged to return Err on memory exhaustion rather than panicking or aborting, but this is not a strict requirement. (Specifically: it is legal to implement this trait atop an underlying native allocation library that aborts on memory exhaustion.)

Clients wishing to abort computation in response to an allocation error are encouraged to call the handle_alloc_error function, rather than directly invoking panic! or similar.

source

unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)

Deallocates the memory referenced by ptr.

Safety
  • ptr must denote a block of memory currently allocated via this allocator, and
  • layout must fit that block of memory.

Provided Methods§

source

fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>

Behaves like allocate, but also ensures that the returned memory is zero-initialized.

Errors

Returning Err indicates that either memory is exhausted or layout does not meet allocator’s size or alignment constraints.

Implementations are encouraged to return Err on memory exhaustion rather than panicking or aborting, but this is not a strict requirement. (Specifically: it is legal to implement this trait atop an underlying native allocation library that aborts on memory exhaustion.)

Clients wishing to abort computation in response to an allocation error are encouraged to call the handle_alloc_error function, rather than directly invoking panic! or similar.

source

unsafe fn grow( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>

Attempts to extend the memory block.

Returns a new NonNull<[u8]> containing a pointer and the actual size of the allocated memory. The pointer is suitable for holding data described by new_layout. To accomplish this, the allocator may extend the allocation referenced by ptr to fit the new layout.

If this returns Ok, then ownership of the memory block referenced by ptr has been transferred to this allocator. Any access to the old ptr is Undefined Behavior, even if the allocation was grown in-place. The newly returned pointer is the only valid pointer for accessing this memory now.

If this method returns Err, then ownership of the memory block has not been transferred to this allocator, and the contents of the memory block are unaltered.

Safety
  • ptr must denote a block of memory currently allocated via this allocator.
  • old_layout must fit that block of memory (The new_layout argument need not fit it.).
  • new_layout.size() must be greater than or equal to old_layout.size().

Note that new_layout.align() need not be the same as old_layout.align().

Errors

Returns Err if the new layout does not meet the allocator’s size and alignment constraints of the allocator, or if growing otherwise fails.

Implementations are encouraged to return Err on memory exhaustion rather than panicking or aborting, but this is not a strict requirement. (Specifically: it is legal to implement this trait atop an underlying native allocation library that aborts on memory exhaustion.)

Clients wishing to abort computation in response to an allocation error are encouraged to call the handle_alloc_error function, rather than directly invoking panic! or similar.

source

unsafe fn grow_zeroed( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>

Behaves like grow, but also ensures that the new contents are set to zero before being returned.

The memory block will contain the following contents after a successful call to grow_zeroed:

  • Bytes 0..old_layout.size() are preserved from the original allocation.
  • Bytes old_layout.size()..old_size will either be preserved or zeroed, depending on the allocator implementation. old_size refers to the size of the memory block prior to the grow_zeroed call, which may be larger than the size that was originally requested when it was allocated.
  • Bytes old_size..new_size are zeroed. new_size refers to the size of the memory block returned by the grow_zeroed call.
Safety
  • ptr must denote a block of memory currently allocated via this allocator.
  • old_layout must fit that block of memory (The new_layout argument need not fit it.).
  • new_layout.size() must be greater than or equal to old_layout.size().

Note that new_layout.align() need not be the same as old_layout.align().

Errors

Returns Err if the new layout does not meet the allocator’s size and alignment constraints of the allocator, or if growing otherwise fails.

Implementations are encouraged to return Err on memory exhaustion rather than panicking or aborting, but this is not a strict requirement. (Specifically: it is legal to implement this trait atop an underlying native allocation library that aborts on memory exhaustion.)

Clients wishing to abort computation in response to an allocation error are encouraged to call the handle_alloc_error function, rather than directly invoking panic! or similar.

source

unsafe fn shrink( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>

Attempts to shrink the memory block.

Returns a new NonNull<[u8]> containing a pointer and the actual size of the allocated memory. The pointer is suitable for holding data described by new_layout. To accomplish this, the allocator may shrink the allocation referenced by ptr to fit the new layout.

If this returns Ok, then ownership of the memory block referenced by ptr has been transferred to this allocator. Any access to the old ptr is Undefined Behavior, even if the allocation was shrunk in-place. The newly returned pointer is the only valid pointer for accessing this memory now.

If this method returns Err, then ownership of the memory block has not been transferred to this allocator, and the contents of the memory block are unaltered.

Safety
  • ptr must denote a block of memory currently allocated via this allocator.
  • old_layout must fit that block of memory (The new_layout argument need not fit it.).
  • new_layout.size() must be smaller than or equal to old_layout.size().

Note that new_layout.align() need not be the same as old_layout.align().

Errors

Returns Err if the new layout does not meet the allocator’s size and alignment constraints of the allocator, or if shrinking otherwise fails.

Implementations are encouraged to return Err on memory exhaustion rather than panicking or aborting, but this is not a strict requirement. (Specifically: it is legal to implement this trait atop an underlying native allocation library that aborts on memory exhaustion.)

Clients wishing to abort computation in response to an allocation error are encouraged to call the handle_alloc_error function, rather than directly invoking panic! or similar.

source

fn by_ref(&self) -> &Selfwhere Self: Sized,

Creates a “by reference” adapter for this instance of Allocator.

The returned adapter also implements Allocator and will simply borrow this.

Implementations on Foreign Types§

source§

impl<A> Allocator for &Awhere A: Allocator + ?Sized,

source§

fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>

source§

fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>

source§

unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)

source§

unsafe fn grow( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>

source§

unsafe fn grow_zeroed( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>

source§

unsafe fn shrink( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>

Implementors§