virt-arena 0.3.0

A virtual memory bump allocator.
Documentation
use std::alloc::Layout;
use std::cell::Cell;
use std::ptr::NonNull;

use libc::*;

pub struct VirtArena {
    start: NonNull<u8>,
    cursor: Cell<NonNull<u8>>,
}

impl Default for VirtArena {
    fn default() -> Self {
        Self::new()
    }
}

impl Drop for VirtArena {
    fn drop(&mut self) {
        unsafe { munmap(self.start.as_ptr().cast(), super::VIRT_ALLOC_SIZE) };
    }
}

impl VirtArena {
    fn new() -> Self {
        let start = unsafe {
            mmap(
                std::ptr::null_mut(),
                super::VIRT_ALLOC_SIZE,
                PROT_READ | PROT_WRITE,
                MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
                -1,
                0,
            )
        };

        if start == MAP_FAILED {
            panic!(
                "Failed to allocate virtual arena: {}",
                std::io::Error::last_os_error()
            );
        }
        let start = NonNull::new(start.cast()).expect("mmaped pointer should never be NULL");

        Self {
            start,
            cursor: Cell::new(start),
        }
    }
}

impl crate::VirtArenaRaw for VirtArena {
    fn bytes_used(&self) -> usize {
        unsafe { self.cursor.get().byte_offset_from(self.start) as usize }
    }

    fn reset(&mut self) {
        self.cursor.set(self.start);
    }

    fn alloc(&self, layout: Layout) -> NonNull<u8> {
        let ptr = self.cursor.get();

        let off = ptr.align_offset(layout.align());

        unsafe {
            let ptr = ptr.byte_add(off);
            let cursor: NonNull<u8> = ptr.byte_add(layout.size()).cast();

            if cursor.byte_offset_from(self.start) as usize > super::VIRT_ALLOC_SIZE {
                panic!("OOM");
            }
            self.cursor.set(cursor);

            ptr
        }
    }
}