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}