Skip to main content

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