osiris/types/
boxed.rs

1//! This module provides a simple heap-allocated memory block for in-kernel use.
2
3use crate::{error::Result, mem};
4
5use core::{
6    mem::{MaybeUninit, forget},
7    ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeTo},
8    ptr::{NonNull, drop_in_place, slice_from_raw_parts_mut, write},
9};
10
11/// A heap-allocated memory block.
12#[proc_macros::fmt]
13pub struct Box<T: ?Sized> {
14    /// Pointer to the heap-allocated memory.
15    /// This is uniquely owned, so no covariance issues.
16    ptr: NonNull<T>,
17}
18
19#[allow(dead_code)]
20impl<T> Box<[T]> {
21    /// Create a new zeroed heap-allocated slice with the given length.
22    ///
23    /// `len` - The length of the slice.
24    ///
25    /// Returns a new heap-allocated slice with the given length or an error if the allocation failed.
26    pub fn new_slice_zeroed(len: usize) -> Result<Self> {
27        if len == 0 {
28            return Ok(Self::new_slice_empty());
29        }
30
31        if let Some(ptr) = mem::malloc(size_of::<T>() * len, align_of::<T>()) {
32            let ptr = slice_from_raw_parts_mut(ptr.as_ptr().cast(), len);
33            Ok(Self {
34                ptr: unsafe { NonNull::new_unchecked(ptr) },
35            })
36        } else {
37            Err(kerr!(OutOfMemory))
38        }
39    }
40
41    /// Create a new empty slice.
42    ///
43    /// Returns a new empty slice.
44    pub const fn new_slice_empty() -> Self {
45        let ptr = slice_from_raw_parts_mut(NonNull::dangling().as_ptr(), 0);
46        Self {
47            ptr: unsafe { NonNull::new_unchecked(ptr) },
48        }
49    }
50
51    /// Create a new uninit heap-allocated slice with the given length.
52    ///
53    /// `len` - The length of the slice.
54    ///
55    /// Returns a new heap-allocated slice with the given length or an error if the allocation failed.
56    pub fn new_slice_uninit(len: usize) -> Result<Box<[MaybeUninit<T>]>> {
57        if let Some(ptr) = mem::malloc(
58            size_of::<MaybeUninit<T>>() * len,
59            align_of::<MaybeUninit<T>>(),
60        ) {
61            let ptr = slice_from_raw_parts_mut(ptr.as_ptr().cast(), len);
62            Ok(Box {
63                ptr: unsafe { NonNull::new_unchecked(ptr) },
64            })
65        } else {
66            Err(kerr!(OutOfMemory))
67        }
68    }
69}
70
71#[allow(dead_code)]
72impl<T> Box<T> {
73    /// Create a new heap-allocated value.
74    ///
75    /// `value` - The value to store on the heap.
76    ///
77    /// Returns a new heap-allocated value or `None` if the allocation failed.
78    pub fn new(value: T) -> Option<Self> {
79        if let Some(ptr) = mem::malloc(size_of::<T>(), align_of::<T>()) {
80            unsafe {
81                write(ptr.as_ptr().cast(), value);
82            }
83
84            Some(Self { ptr: ptr.cast() })
85        } else {
86            None
87        }
88    }
89
90    /// Returns a mutable reference to the heap-allocated value.
91    pub fn as_mut(&mut self) -> &mut T {
92        unsafe { self.ptr.as_mut() }
93    }
94
95    /// Returns an immutable reference to the heap-allocated value.
96    pub fn as_ref(&self) -> &T {
97        unsafe { self.ptr.as_ref() }
98    }
99
100    /// Consumes the `Box`, returning a pointer to the heap-allocated value.
101    ///
102    /// The caller is responsible for freeing the memory with the global `free` function.
103    /// A pointer created with this function can be converted back into a `Box` with the `from_raw` function.
104    pub fn into_raw(self) -> NonNull<T> {
105        let ptr = self.ptr;
106        forget(self);
107        ptr
108    }
109
110    /// Moves a pointer to a heap-allocated value into a `Box`.
111    ///
112    /// `ptr` - The pointer to the heap-allocated value.
113    ///
114    /// Returns a new `Box` managing the given pointer.
115    /// # Safety
116    ///
117    /// The caller must ensure that the pointer is valid and that the memory is not freed while the `Box` is alive.
118    ///
119    /// The caller must ensure that the following conditions are met:
120    ///
121    /// * The pointer must be allocated with the global `malloc` function.
122    /// * The pointer must be unique and not aliased.
123    /// * The pointer must be properly aligned.
124    /// * The pointer must point to a valid `T`.
125    ///
126    /// The `Box` takes ownership of the memory and will free it with the global allocator when dropped.
127    pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
128        Self { ptr }
129    }
130}
131
132impl<T: ?Sized> Drop for Box<T> {
133    fn drop(&mut self) {
134        unsafe {
135            let size = size_of_val(self.ptr.as_ref());
136
137            if size == 0 {
138                return;
139            }
140
141            drop_in_place(self.ptr.as_ptr());
142            mem::free(self.ptr.cast(), size);
143        }
144    }
145}
146
147impl<T> Deref for Box<T> {
148    type Target = T;
149
150    fn deref(&self) -> &Self::Target {
151        self.as_ref()
152    }
153}
154
155impl<T> DerefMut for Box<T> {
156    fn deref_mut(&mut self) -> &mut Self::Target {
157        self.as_mut()
158    }
159}
160
161impl<T> Deref for Box<[T]> {
162    type Target = [T];
163
164    fn deref(&self) -> &[T] {
165        unsafe { self.ptr.as_ref() }
166    }
167}
168
169impl<T> DerefMut for Box<[T]> {
170    fn deref_mut(&mut self) -> &mut [T] {
171        unsafe { self.ptr.as_mut() }
172    }
173}
174
175impl<T> Index<usize> for Box<[T]> {
176    type Output = T;
177
178    fn index(&self, index: usize) -> &Self::Output {
179        &self.as_ref()[index]
180    }
181}
182
183impl<T> Index<Range<usize>> for Box<[T]> {
184    type Output = [T];
185
186    fn index(&self, index: Range<usize>) -> &Self::Output {
187        &self.as_ref()[index]
188    }
189}
190
191impl<T> Index<RangeTo<usize>> for Box<[T]> {
192    type Output = [T];
193
194    fn index(&self, index: RangeTo<usize>) -> &Self::Output {
195        &self.as_ref()[index]
196    }
197}
198
199impl<T> Index<RangeFrom<usize>> for Box<[T]> {
200    type Output = [T];
201
202    fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
203        &self.as_ref()[index]
204    }
205}
206
207impl<T> IndexMut<usize> for Box<[T]> {
208    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
209        &mut self.as_mut()[index]
210    }
211}
212
213impl<T> IndexMut<Range<usize>> for Box<[T]> {
214    fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
215        &mut self.as_mut()[index]
216    }
217}
218
219impl<T> IndexMut<RangeTo<usize>> for Box<[T]> {
220    fn index_mut(&mut self, index: RangeTo<usize>) -> &mut Self::Output {
221        &mut self.as_mut()[index]
222    }
223}
224
225impl<T> IndexMut<RangeFrom<usize>> for Box<[T]> {
226    fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut Self::Output {
227        &mut self.as_mut()[index]
228    }
229}
230
231impl<T> AsRef<T> for Box<T> {
232    fn as_ref(&self) -> &T {
233        self.as_ref()
234    }
235}
236
237impl<T> AsMut<T> for Box<T> {
238    fn as_mut(&mut self) -> &mut T {
239        self.as_mut()
240    }
241}