realloc 0.1.0

A re-implementation of various ::alloc features
Documentation
use core::ptr::NonNull;

use crate::{Align, Allocator, Error, Layout};

/// An allocation returned from (and tied to) an [`Allocator`].
///
/// Cannot outlive its allocator, nor can it be freed in another.
pub struct Alloc<'alloc, T: ?Sized> {
    ptr: NonNull<T>,
    layout: Layout,
    allocator: &'alloc dyn Allocator,
}

impl<'alloc, T: ?Sized> Alloc<'alloc, T> {
    /// # Safety
    ///
    /// - `ptr` must have been allocated in `allocator`, and not have already
    ///   been deallocated.
    /// - `layout` must be the layout used to allocate `ptr`.
    /// - This must not be used to double-drop an allocation.
    pub unsafe fn new(ptr: NonNull<T>, layout: Layout, allocator: &'alloc dyn Allocator) -> Self {
        Self {
            ptr,
            layout,
            allocator,
        }
    }

    /// Returns the allocator internally associated with this allocation.   
    pub fn allocator(&self) -> &'alloc dyn Allocator {
        self.allocator
    }

    /// Get a `NonNull` to the object.
    ///
    /// Note that, when this is dropped, this pointer becomes invalid.
    pub fn ptr(&self) -> NonNull<T> {
        self.ptr
    }

    /// Get a raw pointer to the object.
    ///
    /// Note that, when this is dropped, this pointer becomes invalid.
    pub fn as_ptr(&self) -> *mut T {
        self.ptr.as_ptr()
    }

    /// A shortcut for `self.ptr().as_ref()`.
    ///
    /// # Safety
    ///
    /// See [`NonNull::as_ref`].
    pub unsafe fn as_ref(&self) -> &T {
        self.ptr.as_ref()
    }

    /// A shortcut for `self.ptr().as_mut()`.
    ///
    /// # Safety
    ///
    /// See [`NonNull::as_mut`].
    pub unsafe fn as_mut(&mut self) -> &mut T {
        self.ptr.as_mut()
    }

    /// Write a value into this pointer.
    ///
    /// Note that the old value is not dropped; see [`NonNull::write`].
    pub fn write(&mut self, data: T)
    where
        T: Sized,
    {
        // SAFETY: ptr is aligned and valid
        unsafe { self.ptr.write(data) };
    }

    /// Cast this pointer to another pointer.
    ///
    /// Note that using this pointer is invalid if
    /// `size_of::<Q>() > self.size()`. See [`NonNull::cast`].
    pub fn cast<Q>(self) -> Alloc<'alloc, Q> {
        let Self {
            ptr,
            layout,
            allocator,
        } = self;

        Alloc {
            ptr: ptr.cast(),
            layout,
            allocator,
        }
    }

    /// Cast this into a slice of all bytes in the allocation.
    ///
    /// Note that if the allocator returned a larger allocation than requested,
    /// this won't observe those bytes: it will only expose `self.size()` bytes.
    pub fn all_bytes(self) -> Alloc<'alloc, [u8]> {
        let Self {
            ptr,
            layout,
            allocator,
        } = self;

        let ptr = NonNull::slice_from_raw_parts(ptr.cast(), layout.size);

        Alloc {
            ptr,
            layout,
            allocator,
        }
    }

    /// Returns the layout this was allocated with.
    pub fn layout(&self) -> Layout {
        self.layout
    }

    /// Returns the size this was allocated with.
    ///
    /// Short for `self.layout().size`.
    pub fn size(&self) -> usize {
        self.layout.size
    }

    /// Returns the alignment this was allocated with.
    ///
    /// Short for `self.layout().align`.
    pub fn align(&self) -> Align {
        self.layout.align
    }

    /// Deallocate this allocation in its allocator.
    ///
    /// Shortcut for [`Allocator::dealloc`].
    pub fn dealloc(self) {
        self.allocator.dealloc_bytes(self.cast())
    }

    /// Reallocate this allocation in its allocator with a new layout.
    ///
    /// Shortcut for [`Allocator::realloc`].
    pub fn realloc(self, layout: Layout) -> Result<Alloc<'alloc, u8>, Error> {
        self.allocator.realloc(self.cast(), layout)
    }

    /// Grow this allocation in its allocator with a new layout.
    ///
    /// Shortcut for [`Allocator::grow`].
    pub fn grow(self, layout: Layout) -> Result<Alloc<'alloc, u8>, Error> {
        self.allocator.grow(self.cast(), layout)
    }

    /// Shrink this allocation in its allocator with a new layout.
    ///
    /// Shortcut for [`Allocator::shrink`].
    pub fn shrink(self, layout: Layout) -> Result<Alloc<'alloc, u8>, Error> {
        self.allocator.shrink(self.cast(), layout)
    }
}