allocandrescu 0.1.0-alpha.2

Allocator combinators.
Documentation
//! Allocator combinators.

use crate::ArenaAllocator;
use allocator_api2::alloc::{AllocError, Allocator};
use core::{alloc::Layout, ptr::NonNull};

/// Conditional allocator combinator.
///
/// This `struct` is created by [`fallback`](crate::Allocandrescu::cond) method on [`Allocandrescu`](crate::Allocandrescu).
/// See its documentation for more details.
pub struct Cond<A, F> {
    alloc: A,
    pred: F,
}

impl<A, F> Cond<A, F> {
    #[inline]
    pub fn new(alloc: A, pred: F) -> Self {
        Self { alloc, pred }
    }
}

unsafe impl<A, F> Allocator for Cond<A, F>
where
    A: Allocator,
    F: Fn(Layout) -> bool,
{
    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
        if (self.pred)(layout) {
            self.alloc.allocate(layout)
        } else {
            Err(AllocError)
        }
    }

    #[inline]
    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
        self.alloc.deallocate(ptr, layout)
    }

    // TODO: optimize default implementations where applicable
}

impl<A, F> ArenaAllocator for Cond<A, F>
where
    A: ArenaAllocator,
    F: Fn(Layout) -> bool,
{
    #[inline]
    fn contains(&self, ptr: NonNull<u8>, layout: Layout) -> bool {
        self.alloc.contains(ptr, layout)
    }
}

/// Fallback allocator combinator.
///
/// This `struct` is created by [`fallback`](crate::Allocandrescu::fallback) method on [`Allocandrescu`](crate::Allocandrescu).
/// See its documentation for more details.
pub struct Fallback<P, S> {
    primary: P,
    secondary: S,
}

impl<P, S> Fallback<P, S> {
    #[inline]
    pub fn new(primary: P, secondary: S) -> Self {
        Self { primary, secondary }
    }

    #[inline]
    pub fn primary(&self) -> &P {
        &self.primary
    }

    #[inline]
    pub fn secondary(&self) -> &S {
        &self.secondary
    }
}

unsafe impl<P, S> Allocator for Fallback<P, S>
where
    P: ArenaAllocator,
    S: Allocator,
{
    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
        self.primary
            .allocate(layout)
            .or_else(|_| self.secondary.allocate(layout))
    }

    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
        if self.primary.contains(ptr, layout) {
            self.primary.deallocate(ptr, layout)
        } else {
            self.secondary.deallocate(ptr, layout)
        }
    }
}

impl<P, S> ArenaAllocator for Fallback<P, S>
where
    P: ArenaAllocator,
    S: ArenaAllocator,
{
    #[inline]
    fn contains(&self, ptr: NonNull<u8>, layout: Layout) -> bool {
        self.primary.contains(ptr, layout) || self.secondary.contains(ptr, layout)
    }
}