outsource_heap/
file_backed.rs

1//! This module provides an example file backed allocator, which can be used with
2//! the scoped allocator methods provided by this crate.
3//! It is a simple wrapper for the [`linked_list_allocator`] crate.
4
5use super::Store;
6use ::std::sync::Mutex;
7use ::std::io;
8use ::std::path::Path;
9use ::std::fs::OpenOptions;
10use ::std::alloc::Layout;
11use ::core::ptr::NonNull;
12use ::memmap2::MmapMut;
13use ::linked_list_allocator::Heap;
14
15pub struct FileBacked {
16    _mmap: MmapMut,
17    heap: Mutex<Heap>,
18}
19impl FileBacked {
20    pub fn open(capacity: u64, path: &Path) -> Result<Self, io::Error> {
21        let cap = capacity.try_into().map_err(|_| {
22            io::Error::new(io::ErrorKind::Unsupported, "tried to allocate more than usize::MAX")
23        })?;
24        let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?;
25        file.set_len(capacity)?;
26        let mut mmap = unsafe { MmapMut::map_mut(&file)? };
27        let base = (&mut *mmap).as_mut_ptr();
28        let heap = Mutex::new(unsafe { Heap::new(base, cap) });
29        Ok(Self { _mmap: mmap, heap })
30    }
31}
32
33// It seems like a bad idea to use this for your true global allocator,
34// so I'm preventing that usage for now.
35unsafe impl Store for FileBacked {
36    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
37        self.heap.lock().unwrap()
38            .allocate_first_fit(layout)
39            .map(|x| x.as_ptr())
40            .unwrap_or(::core::ptr::null_mut())
41    }
42    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
43        let ptr = unsafe { NonNull::new_unchecked(ptr) };
44        unsafe { self.heap.lock().unwrap().deallocate(ptr, layout); }
45    }
46}