crucible/
alloc.rs

1use core::alloc::{self, Layout, AllocError};
2use core::marker::PhantomData;
3use core::mem;
4use core::ptr::NonNull;
5
6/// Allocate an array of `len` elements of type `T`.  The array begins uninitialized.
7pub fn allocate<T>(len: usize) -> *mut T {
8    unimplemented!("allocate")
9}
10
11/// Allocate an array of `len` elements of type `T`.  The array initially contains all zeros.  This
12/// fails if `crux-mir` doesn't know how to zero-initialize `T`.
13pub fn allocate_zeroed<T>(len: usize) -> *mut T {
14    unimplemented!("allocate_zeroed")
15}
16
17/// Reallocate the array at `*ptr` to contain `new_len` elements.  This reallocation always happens
18/// in-place and never fails, so there is no need to return a new pointer.
19pub fn reallocate<T>(ptr: *mut T, new_len: usize) {
20    unimplemented!("reallocate")
21}
22
23pub struct TypedAllocator<T>(pub PhantomData<T>);
24
25impl<T> TypedAllocator<T> {
26    pub const fn new() -> TypedAllocator<T> {
27        TypedAllocator(PhantomData)
28    }
29}
30
31impl<T> Default for TypedAllocator<T> {
32    fn default() -> TypedAllocator<T> {
33        TypedAllocator::new()
34    }
35}
36
37fn size_to_len<T>(size: usize) -> usize {
38    if mem::size_of::<T>() == 0 {
39        0
40    } else {
41        size / Layout::new::<T>().size()
42    }
43}
44
45unsafe impl<T> alloc::Allocator for TypedAllocator<T> {
46    // Required methods
47    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
48        unsafe {
49            let len = size_to_len::<T>(layout.size());
50            let ptr = NonNull::new_unchecked(allocate::<T>(len));
51            Ok(NonNull::slice_from_raw_parts(
52                core::mem::transmute::<NonNull<T>, NonNull<u8>>(ptr),
53                len,
54            ))
55        }
56    }
57    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
58        // No-op.  crucible-mir currently doesn't track deallocation.
59    }
60
61    // Provided methods
62    fn allocate_zeroed(
63        &self,
64        layout: Layout,
65    ) -> Result<NonNull<[u8]>, AllocError> {
66        unsafe {
67            let len = size_to_len::<T>(layout.size());
68            let ptr = NonNull::new_unchecked(allocate_zeroed::<T>(len));
69            Ok(NonNull::slice_from_raw_parts(
70                core::mem::transmute::<NonNull<T>, NonNull<u8>>(ptr),
71                len,
72            ))
73        }
74    }
75    unsafe fn grow(
76        &self,
77        ptr: NonNull<u8>,
78        old_layout: Layout,
79        new_layout: Layout,
80    ) -> Result<NonNull<[u8]>, AllocError> {
81        let old_len = size_to_len::<T>(old_layout.size());
82        let new_len = size_to_len::<T>(new_layout.size());
83        reallocate(ptr.as_ptr().cast::<T>(), new_len);
84        // `reallocate` always reallocates in place, so we can just return the old pointer.
85        Ok(NonNull::slice_from_raw_parts(ptr.cast::<u8>(), new_len))
86    }
87    unsafe fn grow_zeroed(
88        &self,
89        ptr: NonNull<u8>,
90        old_layout: Layout,
91        new_layout: Layout,
92    ) -> Result<NonNull<[u8]>, AllocError> {
93        panic!("crucible does not yet support Allocator::grow_zeroed")
94    }
95    unsafe fn shrink(
96        &self,
97        ptr: NonNull<u8>,
98        old_layout: Layout,
99        new_layout: Layout,
100    ) -> Result<NonNull<[u8]>, AllocError> {
101        let old_len = size_to_len::<T>(old_layout.size());
102        let new_len = size_to_len::<T>(new_layout.size());
103        reallocate(ptr.as_ptr().cast::<T>(), new_len);
104        Ok(NonNull::slice_from_raw_parts(ptr.cast::<u8>(), new_len))
105    }
106}