realloc 0.1.0

A re-implementation of various ::alloc features
Documentation
use core::ops::{Deref, DerefMut};

use crate::{Alloc, Allocator, AllocatorExt, Error, Panic, Strategy};

/// A pointer type that uniquely owns an allocation of type `T`.
///
/// Note that this does not have the full API surface of `std::box::Box`,
/// largely due to the fact that `std::box::Box` has built-in compiler magic.
pub struct Box<'alloc, T, S: Strategy> {
    alloc: Option<Alloc<'alloc, T>>,
    _strategy: S,
}

#[cfg(feature = "global")]
impl<T, S: Strategy> Box<'static, T, S> {
    /// Allocates `value` in the global allocator.
    ///
    /// Fails if there is no global allocator.
    ///
    /// Only available on feature `global`.
    pub fn new(value: T) -> S::Result<Self, Error> {
        let allocator = S::create(crate::global::get().ok_or(Error::NoGlobalAllocator));
        S::and_then(allocator, |allocator| Self::new_in(value, allocator))
    }
}

impl<'alloc, T, S: Strategy> Box<'alloc, T, S> {
    /// Allocates `value` in the given allocator.
    pub fn new_in(value: T, allocator: &'alloc dyn Allocator) -> S::Result<Self, Error> {
        let alloc = S::create(allocator.alloc_with(value));
        let alloc = S::map(alloc, |alloc| Self {
            alloc: Some(alloc),
            _strategy: S::UNIT,
        });
        S::map_err(alloc, |(_, e)| e)
    }

    /// Creates a clone of this box in the given allocator.
    ///
    /// If you want to clone it in a different allocator, see
    /// [`clone_in`](Self::clone_in).
    pub fn clone_in<'new_alloc>(
        &self,
        allocator: &'new_alloc dyn Allocator,
    ) -> S::Result<Box<'new_alloc, T, S>, Error>
    where
        T: Clone,
    {
        let value = self.deref().clone();
        Box::<T, S>::new_in(value, allocator)
    }

    /// Creates a clone of this box in the same allocator it was created in.
    ///
    /// If you want to clone it in a different allocator, see
    /// [`clone_in`](Self::clone_in).
    pub fn clone_in_same(&self) -> S::Result<Self, Error>
    where
        T: Clone,
    {
        self.clone_in(self.alloc.as_ref().unwrap().allocator())
    }

    /// Change the [failure strategy](Strategy) employed on fallible methods.
    pub fn change_strategy<NS: Strategy>(mut self) -> Box<'alloc, T, NS> {
        let alloc = self.alloc.take();
        Box {
            alloc,
            _strategy: NS::UNIT,
        }
    }

    /// Deallocate the box, returning the inner value.
    ///
    /// A substitute for `*box` in `std::box::Box`.
    pub fn take(mut self) -> T {
        let alloc = self.alloc.take().unwrap();
        // SAFETY: the value is deallocated without being dropped
        let value = unsafe { alloc.as_ptr().read() };
        alloc.dealloc();
        value
    }

    /// Consumes and leaks the box, returning a mutable reference,
    /// `&'alloc mut T`.
    ///
    /// Note that this *will* cause a memory leak; as such, be wary of using
    /// this repeatedly, unless you intend on dropping/clearing the underlying
    /// allocator.
    pub fn leak(this: Self) -> &'alloc mut T {
        let mut this = core::mem::ManuallyDrop::new(this);

        // SAFETY: this allocation will now never be freed, so the data will
        // live as long as the underlying allocator
        unsafe { &mut *this.alloc.take().unwrap().as_ptr() }
    }
}

impl<T: Clone, S: Strategy> Clone for Box<'_, T, S> {
    fn clone(&self) -> Self {
        let value = self.deref().clone();
        Box::<_, Panic>::new_in(value, self.alloc.as_ref().unwrap().allocator()).change_strategy()
    }
}

impl<T, S: Strategy> Deref for Box<'_, T, S> {
    type Target = T;

    fn deref(&self) -> &T {
        // SAFETY: it's guaranteed to be initialized
        unsafe { self.alloc.as_ref().unwrap().as_ref() }
    }
}

impl<T, S: Strategy> DerefMut for Box<'_, T, S> {
    fn deref_mut(&mut self) -> &mut T {
        // SAFETY: it's guaranteed to be initialized
        unsafe { self.alloc.as_mut().unwrap().as_mut() }
    }
}

impl<T, S: Strategy> Drop for Box<'_, T, S> {
    fn drop(&mut self) {
        let alloc = self.alloc.take().unwrap();
        // SAFETY: the alloc is deallocated without its value being dropped
        drop(unsafe { alloc.as_ptr().read() });
        alloc.dealloc();
    }
}