platform/boxed.rs
1// SPDX-FileCopyrightText: 2025 Jens Pitkänen <jens.pitkanen@helsinki.fi>
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5use core::{
6 fmt::{Debug, Display},
7 ops::{Deref, DerefMut},
8};
9
10/// Owned pointer to a `T`.
11///
12/// Intended for similar use cases as the standard library `Box`, but this one
13/// does not free the memory on drop (though it does drop the `T`). Used
14/// sparingly in cases where we really need to own a dynamically allocated `T`
15/// instead of borrowing it, and using a static borrow would be too verbose.
16pub struct Box<T: 'static + ?Sized> {
17 inner: *mut T,
18 should_drop: bool,
19}
20
21impl<T: ?Sized> Box<T> {
22 /// Creates a [`Box`] from a leaked borrow of the boxed value.
23 pub fn from_mut(value: &'static mut T) -> Box<T> {
24 Box {
25 inner: value,
26 should_drop: true,
27 }
28 }
29
30 /// Creates a [`Box`] from a raw pointer to the boxed value.
31 ///
32 /// ### Safety
33 ///
34 /// The caller must ensure that the memory behind the pointer is never read,
35 /// written, or freed while this `Box` exists, and that the T pointed to by
36 /// this pointer is never accessed after this call, unless it's after
37 /// deconstructing this box with [`Box::into_ptr`].
38 pub unsafe fn from_ptr(ptr: *mut T) -> Box<T> {
39 Box {
40 inner: ptr,
41 should_drop: true,
42 }
43 }
44
45 /// Consumes the [`Box<T>`] without dropping the internal value and returns
46 /// the internal pointer.
47 pub fn into_ptr(mut self) -> *mut T {
48 self.should_drop = false; // avoid dropping the value
49 self.inner
50 }
51}
52
53impl<T: ?Sized> Drop for Box<T> {
54 fn drop(&mut self) {
55 if self.should_drop {
56 // Safety:
57 // - self.inner is valid for reads and writes because the constructors
58 // require it.
59 // - self.inner is properly aligned because the constructors require it.
60 // - self.inner is nonnull because the constructors require it.
61 // - self.inner should be valid for dropping, because it's exclusively
62 // owned by us, and it should be unsafe to leave T in an un-droppable
63 // state via the deref channels.
64 // - the T pointed to by self.inner is exclusively accessible by the
65 // internals of this Box, and since we're in a drop impl, we have a
66 // mutable borrow of this Box, so this should indeed be the only way
67 // to access parts of the object.
68 unsafe { self.inner.drop_in_place() };
69 }
70 }
71}
72
73impl<T: ?Sized> Deref for Box<T> {
74 type Target = T;
75
76 fn deref(&self) -> &Self::Target {
77 // Safety: the constructors ensure that the pointer is good to
78 // turn into a reference.
79 unsafe { &*self.inner }
80 }
81}
82
83impl<T: ?Sized> DerefMut for Box<T> {
84 fn deref_mut(&mut self) -> &mut Self::Target {
85 // Safety: the constructors ensure that the pointer is good to
86 // turn into a reference.
87 unsafe { &mut *self.inner }
88 }
89}
90
91impl<T: ?Sized + Debug> Debug for Box<T> {
92 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
93 let inner: &T = self;
94 f.debug_tuple("Box").field(&inner).finish()
95 }
96}
97
98impl<T: ?Sized + Display> Display for Box<T> {
99 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
100 let inner: &T = self;
101 write!(f, "{}", inner)
102 }
103}
104
105// Safety: if the inner value is Sync, the box is Sync as well, there's no
106// additional thread safety semantics here.
107unsafe impl<T: ?Sized + Sync> Sync for Box<T> {}
108
109#[cfg(test)]
110mod tests {
111 use core::sync::atomic::{AtomicBool, Ordering};
112
113 use crate::Box;
114
115 #[test]
116 fn dropping_a_box_drops_the_value() {
117 static DROPPED: AtomicBool = AtomicBool::new(false);
118 struct Example;
119 impl Drop for Example {
120 fn drop(&mut self) {
121 DROPPED.store(true, Ordering::Release);
122 }
123 }
124
125 let mut example = Example;
126 let example_ptr = &raw mut example;
127 {
128 let example_box = unsafe { Box::from_ptr(example_ptr) };
129 assert!(!DROPPED.load(Ordering::Acquire));
130 drop(example_box);
131 assert!(DROPPED.load(Ordering::Acquire));
132 }
133 core::mem::forget(example);
134 }
135}