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}