without_alloc/
boxed.rs

1//! A pointer type for allocation with RAII semantics.
2//!
3//! See [`Box`] for more information.
4//!
5//! [`Box`]: struct.Box.html
6use core::{borrow, cmp, fmt, hash, mem, ops, ptr};
7use crate::uninit::Uninit;
8use unsize::CoerciblePtr;
9
10/// An allocated instance of a type.
11///
12/// ## Example
13///
14/// The basic usage are allocated recursive data structures. Here is a standard example using a
15/// `Bump` with `'static` storage duration as the allocator:
16///
17/// ```
18/// use without_alloc::{Box, alloc::LocalAllocLeakExt};
19/// use static_alloc::Bump;
20///
21/// #[derive(Debug)]
22/// enum List<T> {
23///     Nil,
24///     Cons(T, Box<'static, List<T>>),
25/// }
26///
27/// static SLAB: Bump<[u8; 1024]> = Bump::uninit();
28///
29/// let base = SLAB.boxed(List::Nil).unwrap();
30/// let one = SLAB.boxed(List::Cons(0, base)).unwrap();
31/// let two = SLAB.boxed(List::Cons(1, one)).unwrap();
32///
33/// // We can destruct the value (not with `*` but comparable).
34/// match Box::take(two).0 {
35///     List::Cons(val, _)  => assert_eq!(val, 1), // Got the value back.
36///     _ => unreachable!(),
37/// }
38/// ```
39///
40/// ## Downsides
41///
42/// Unfortunately, this `Box` does not yet support unsizing. This is very unfortunate as it means
43/// you can't use it for type erasure.
44///
45/// ## Design
46/// You will likely notice quickly that this has different semantics than the `std::boxed::Box`.
47/// Its inner pointer may be larger and it does not allocate nor deallocate memory on its own. This
48/// only wraps a fully initialized `Uninit` in a RAII/`Drop` interface.
49///
50/// Of course, there is a reason for this choice. The standard `Box`, storing only the raw pointer
51/// (as a `Unique`), requires its underlying allocation to have the *exact* same size and align
52/// (`Layout`) as the value and the layout needs to be recalculated when deallocating. Without a
53/// dependency on an allocator it would seem that the underlying layout becomes less important and
54/// can be thrown away but the opposite is the case. Many converters for the `std::boxed::Box` rely
55/// on being able to reallocate into a suitably constructed new allocation on will. Not having this
56/// luxury at our disposal means there should be a mechanism to cope with mismatching allocations
57/// anyways. So we simply store the full `Uninit` provided, relying on the library user to manage
58/// other aspects of allocation for us.
59///
60/// Instead, this `Box` can offer additional ways to manipulate and massage the underlying
61/// allocation. It should be possible to restore the exact allocation `Box` semantics (albeit with
62/// one `usize` more space usage) via a wrapper when an allocator is available.
63pub struct Box<'a, T: ?Sized> {
64    inner: Uninit<'a, T>,
65}
66
67
68/// Unsize a Box, for example into a dynamic trait object.
69///
70/// # Usage
71///
72/// ```
73/// # use without_alloc::boxed::Box;
74/// use unsize::{Coercion, CoerceUnsize};
75/// use without_alloc::Uninit;
76/// use core::mem::MaybeUninit;
77///
78/// let mut memory: MaybeUninit<usize> = MaybeUninit::uninit();
79/// let boxed = Box::new(0usize, Uninit::from(&mut memory));
80///
81/// let debug: Box<dyn core::fmt::Debug> = unsafe {
82///     boxed.unsize(Coercion::to_debug())
83/// };
84/// ```
85unsafe impl<'a, T, U: ?Sized> CoerciblePtr<U> for Box<'a, T> {
86    type Pointee = T;
87    type Output = Box<'a, U>;
88    fn as_sized_ptr(&mut self) -> *mut T {
89        self.inner.as_ptr()
90    }
91    unsafe fn replace_ptr(self, new: *mut U) -> Box<'a, U> {
92        let inner = Box::into_raw(self);
93        let inner = inner.replace_ptr(new);
94        Box::from_raw(inner)
95    }
96}
97
98impl<'a, T> Box<'a, T> {
99    /// Place `val` into a provided allocation.
100    pub fn new(val: T, mut into: Uninit<'a, T>) -> Self {
101        into.borrow_mut().init(val);
102
103        Box {
104            inner: into,
105        }
106    }
107
108    /// Take out the value and return the allocation.
109    ///
110    /// This function is the opposite of `new`.
111    pub fn take(b: Self) -> (T, Uninit<'a, T>) {
112        let val = unsafe { b.inner.read() };
113        (val, Self::into_raw(b))
114    }
115}
116
117impl<'a, T: ?Sized> Box<'a, T> {
118    /// Create a box from an pointer to an already initialized value.
119    ///
120    /// Ensures that an already initialized value is properly dropped at the end of the lifetime of
121    /// the `Box`.
122    ///
123    /// ## Safety
124    /// The pointed-to location must have already been initialized via external means. This is as
125    /// unsafe as `init.as_mut()`.
126    pub unsafe fn from_raw(init: Uninit<'a, T>) -> Self {
127        Box {
128            inner: init,
129        }
130    }
131
132    /// Unwrap the contained `Uninit`.
133    ///
134    /// The value stays initialized but that information is no longer statically available. If you
135    /// simply want to avoid the `Drop` call, consider `ManuallyDrop` instead.
136    pub fn into_raw(b: Self) -> Uninit<'a, T> {
137        let ptr = b.inner.as_non_null();
138        let len = b.inner.size();
139        mem::forget(b);
140        unsafe {
141            // SAFETY: restored the `Uninit` we just forgot.
142            Uninit::new(ptr, len)
143        }
144    }
145
146    /// Consumes and leaks the Box, returning a mutable reference, `&'a mut T`.
147    ///
148    /// Compared to a standard `Box` it should be noted that the reference alone is not enough
149    /// to invoke `Box::from_raw`.
150    pub fn leak(b: Self) -> &'a mut T {
151        let raw = Self::into_raw(b);
152        // SAFETY: still initialized
153        unsafe { raw.into_mut() }
154    }
155}
156
157impl<T: ?Sized> Drop for Box<'_, T> {
158    fn drop(&mut self) {
159        unsafe {
160            ptr::drop_in_place(self.inner.as_ptr())
161        }
162    }
163}
164
165impl<T: ?Sized> ops::Deref for Box<'_, T> {
166    type Target = T;
167
168    fn deref(&self) -> &T {
169        unsafe {
170            self.inner.as_ref()
171        }
172    }
173}
174
175impl<T: ?Sized> ops::DerefMut for Box<'_, T> {
176    fn deref_mut(&mut self) -> &mut T {
177        unsafe {
178            self.inner.as_mut()
179        }
180    }
181}
182
183impl<'a, 'b, T: PartialEq> PartialEq<Box<'b, T>> for Box<'a, T> {
184    #[inline]
185    fn eq(&self, other: &Box<T>) -> bool {
186        PartialEq::eq(&**self, &**other)
187    }
188    #[inline]
189    fn ne(&self, other: &Box<T>) -> bool {
190        PartialEq::ne(&**self, &**other)
191    }
192}
193
194impl<'a, 'b, T: PartialOrd> PartialOrd<Box<'b, T>> for Box<'a, T> {
195    #[inline]
196    fn partial_cmp(&self, other: &Box<T>) -> Option<cmp::Ordering> {
197        PartialOrd::partial_cmp(&**self, &**other)
198    }
199    #[inline]
200    fn lt(&self, other: &Box<T>) -> bool {
201        PartialOrd::lt(&**self, &**other)
202    }
203    #[inline]
204    fn le(&self, other: &Box<T>) -> bool {
205        PartialOrd::le(&**self, &**other)
206    }
207    #[inline]
208    fn ge(&self, other: &Box<T>) -> bool {
209        PartialOrd::ge(&**self, &**other)
210    }
211    #[inline]
212    fn gt(&self, other: &Box<T>) -> bool {
213        PartialOrd::gt(&**self, &**other)
214    }
215}
216
217impl<T: Ord> Ord for Box<'_, T> {
218    #[inline]
219    fn cmp(&self, other: &Box<T>) -> cmp::Ordering {
220        Ord::cmp(&**self, &**other)
221    }
222}
223
224impl<T: Eq> Eq for Box<'_, T> { }
225
226impl<T: hash::Hash> hash::Hash for Box<'_, T> {
227    fn hash<H: hash::Hasher>(&self, state: &mut H) {
228        (**self).hash(state)
229    }
230}
231
232impl<T: fmt::Debug> fmt::Debug for Box<'_, T> {
233    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234        fmt::Debug::fmt(&**self, f)
235    }
236}
237
238impl<T> fmt::Pointer for Box<'_, T> {
239    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240        fmt::Pointer::fmt(&self.inner.as_ptr(), f)
241    }
242}
243
244impl<T> borrow::Borrow<T> for Box<'_, T> {
245    fn borrow(&self) -> &T {
246        &**self
247    }
248}
249
250impl<T> borrow::BorrowMut<T> for Box<'_, T> {
251    fn borrow_mut(&mut self) -> &mut T {
252        &mut **self
253    }
254}
255
256impl<T> AsRef<T> for Box<'_, T> {
257    fn as_ref(&self) -> &T {
258        &**self
259    }
260}
261
262impl<T> AsMut<T> for Box<'_, T> {
263    fn as_mut(&mut self) -> &mut T {
264        &mut **self
265    }
266}
267
268#[cfg(test)]
269mod tests {
270    use super::Box;
271    use crate::alloc::LocalAllocLeakExt;
272    use static_alloc::Bump;
273
274   #[test]
275    fn leak_with_smaller_lifetime() {
276        static SLAB: Bump<[usize; 1]> = Bump::uninit();
277        let local = 0;
278
279        // Box is `'static` but variable is not.
280        let boxed: Box<'static, _> = SLAB.boxed(&local).unwrap();
281        // Check that we can leak with appropriate lifetime.
282        let _: & mut _ = Box::leak(boxed);
283        // local needs to be live for the time before the box is leaked
284        let _ = local;
285    }
286}