Skip to main content

musli_core/alloc/
boxed.rs

1use core::cmp::Ordering;
2use core::fmt;
3use core::hash::{Hash, Hasher};
4use core::mem::needs_drop;
5use core::ops::{Deref, DerefMut};
6
7use super::{Alloc, AllocError, Allocator, GlobalAllocator};
8
9/// A Müsli-allocated pointer type that uniquely owns a heap allocation of type
10/// `T`.
11///
12/// This is a [`Box`][std-box] type capable of using the allocator provided
13/// through a [`Context`]. Therefore it can be safely used in no-std
14/// environments.
15///
16/// [std-box]: std::boxed::Box
17/// [`Context`]: crate::Context
18///
19/// # Thread safety
20///
21/// A box is [`Send`] or [`Sync`] only if the allocation it holds is. Boxes
22/// backed by the global allocator are thread safe as long as `T` is:
23///
24/// ```
25/// use musli::alloc::{Box, Global};
26///
27/// fn assert_send_sync<T: Send + Sync>(_: &T) {}
28///
29/// let boxed = Box::<u32, Global>::new_in(42, Global::new())?;
30/// assert_send_sync(&boxed);
31/// # Ok::<_, musli::alloc::AllocError>(())
32/// ```
33///
34/// But a box allocated from a [`Slice`] refers to allocator state which is not
35/// synchronized, so it cannot be sent to another thread:
36///
37/// ```compile_fail,E0277
38/// use musli::alloc::{ArrayBuffer, Box, Slice};
39///
40/// fn assert_send<T: Send>(_: &T) {}
41///
42/// let mut buf = ArrayBuffer::new();
43/// let alloc = Slice::new(&mut buf);
44/// let boxed = Box::new_in(42u32, &alloc)?;
45/// assert_send(&boxed);
46/// # Ok::<_, musli::alloc::AllocError>(())
47/// ```
48///
49/// Nor can it be shared between threads:
50///
51/// ```compile_fail,E0277
52/// use musli::alloc::{ArrayBuffer, Box, Slice};
53///
54/// fn assert_sync<T: Sync>(_: &T) {}
55///
56/// let mut buf = ArrayBuffer::new();
57/// let alloc = Slice::new(&mut buf);
58/// let boxed = Box::new_in(42u32, &alloc)?;
59/// assert_sync(&boxed);
60/// # Ok::<_, musli::alloc::AllocError>(())
61/// ```
62///
63/// [`Slice`]: https://docs.rs/musli/latest/musli/alloc/struct.Slice.html
64pub struct Box<T, A>
65where
66    A: Allocator,
67{
68    buf: A::Alloc<T>,
69}
70
71impl<T, A> Box<T, A>
72where
73    A: Allocator,
74{
75    /// Allocates memory on the heap and then places `x` into it.
76    ///
77    /// This doesn't actually allocate if `T` is zero-sized.
78    ///
79    /// ## Examples
80    ///
81    /// ```
82    /// use musli::alloc::{AllocError, Box};
83    ///
84    /// musli::alloc::default(|alloc| {
85    ///     let mut a = Box::new_in(10u32, alloc)?;
86    ///     assert_eq!(a.as_ref(), &10u32);
87    ///     Ok::<_, AllocError>(())
88    /// });
89    /// # Ok::<_, musli::alloc::AllocError>(())
90    /// ```
91    ///
92    /// Zero-sized types:
93    ///
94    /// ```
95    /// use musli::alloc::{AllocError, Box};
96    ///
97    /// musli::alloc::default(|alloc| {
98    ///     let mut a = Box::new_in((), alloc)?;
99    ///     assert_eq!(a.as_ref(), &());
100    ///     Ok::<_, AllocError>(())
101    /// });
102    /// # Ok::<_, musli::alloc::AllocError>(())
103    /// ```
104    #[inline]
105    pub fn new_in(value: T, alloc: A) -> Result<Self, AllocError> {
106        Ok(Self {
107            buf: alloc.alloc(value)?,
108        })
109    }
110}
111
112impl<T, A> Clone for Box<T, A>
113where
114    T: Clone,
115    A: GlobalAllocator,
116{
117    #[inline]
118    fn clone(&self) -> Self {
119        let mut buf = <A as GlobalAllocator>::clone_alloc(&self.buf);
120
121        // SAFETY: Layout assumptions are correct when a buffer is cloned.
122        unsafe {
123            buf.as_mut_ptr().write(self.as_ref().clone());
124        }
125
126        Self { buf }
127    }
128}
129
130impl<T, A> Deref for Box<T, A>
131where
132    A: Allocator,
133{
134    type Target = T;
135
136    #[inline]
137    fn deref(&self) -> &Self::Target {
138        // SAFETY: The returned buffer is valid per construction.
139        unsafe { &*self.buf.as_ptr() }
140    }
141}
142
143impl<T, A> DerefMut for Box<T, A>
144where
145    A: Allocator,
146{
147    #[inline]
148    fn deref_mut(&mut self) -> &mut Self::Target {
149        // SAFETY: The returned buffer is valid per construction.
150        unsafe { &mut *self.buf.as_mut_ptr() }
151    }
152}
153
154impl<T, A> AsRef<T> for Box<T, A>
155where
156    A: Allocator,
157{
158    #[inline]
159    fn as_ref(&self) -> &T {
160        self
161    }
162}
163
164impl<T, A> Drop for Box<T, A>
165where
166    A: Allocator,
167{
168    #[inline]
169    fn drop(&mut self) {
170        // SAFETY: Layout assumptions are correctly encoded in the type as it
171        // was being allocated or grown.
172        unsafe {
173            if needs_drop::<T>() {
174                self.buf.as_mut_ptr().drop_in_place();
175            }
176        }
177    }
178}
179
180impl<T, A> fmt::Display for Box<T, A>
181where
182    T: fmt::Display,
183    A: Allocator,
184{
185    #[inline]
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        fmt::Display::fmt(&**self, f)
188    }
189}
190
191impl<T, A> fmt::Debug for Box<T, A>
192where
193    T: fmt::Debug,
194    A: Allocator,
195{
196    #[inline]
197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        fmt::Debug::fmt(&**self, f)
199    }
200}
201
202impl<T, A> PartialEq for Box<T, A>
203where
204    T: PartialEq,
205    A: Allocator,
206{
207    #[inline]
208    fn eq(&self, other: &Self) -> bool {
209        PartialEq::eq(&**self, &**other)
210    }
211
212    #[inline]
213    #[allow(clippy::partialeq_ne_impl)]
214    fn ne(&self, other: &Self) -> bool {
215        PartialEq::ne(&**self, &**other)
216    }
217}
218
219impl<T, A> PartialOrd for Box<T, A>
220where
221    T: PartialOrd,
222    A: Allocator,
223{
224    #[inline]
225    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
226        PartialOrd::partial_cmp(&**self, &**other)
227    }
228
229    #[inline]
230    fn lt(&self, other: &Self) -> bool {
231        PartialOrd::lt(&**self, &**other)
232    }
233
234    #[inline]
235    fn le(&self, other: &Self) -> bool {
236        PartialOrd::le(&**self, &**other)
237    }
238
239    #[inline]
240    fn ge(&self, other: &Self) -> bool {
241        PartialOrd::ge(&**self, &**other)
242    }
243
244    #[inline]
245    fn gt(&self, other: &Self) -> bool {
246        PartialOrd::gt(&**self, &**other)
247    }
248}
249
250impl<T, A> Ord for Box<T, A>
251where
252    T: Ord,
253    A: Allocator,
254{
255    #[inline]
256    fn cmp(&self, other: &Self) -> Ordering {
257        Ord::cmp(&**self, &**other)
258    }
259}
260
261impl<T, A> Eq for Box<T, A>
262where
263    T: Eq,
264    A: Allocator,
265{
266}
267
268impl<T, A> Hash for Box<T, A>
269where
270    T: Hash,
271    A: Allocator,
272{
273    #[inline]
274    fn hash<H: Hasher>(&self, state: &mut H) {
275        (**self).hash(state);
276    }
277}
278
279impl<T, A> Hasher for Box<T, A>
280where
281    T: Hasher,
282    A: Allocator,
283{
284    #[inline]
285    fn finish(&self) -> u64 {
286        (**self).finish()
287    }
288
289    #[inline]
290    fn write(&mut self, bytes: &[u8]) {
291        (**self).write(bytes)
292    }
293
294    #[inline]
295    fn write_u8(&mut self, i: u8) {
296        (**self).write_u8(i)
297    }
298
299    #[inline]
300    fn write_u16(&mut self, i: u16) {
301        (**self).write_u16(i)
302    }
303
304    #[inline]
305    fn write_u32(&mut self, i: u32) {
306        (**self).write_u32(i)
307    }
308
309    #[inline]
310    fn write_u64(&mut self, i: u64) {
311        (**self).write_u64(i)
312    }
313
314    #[inline]
315    fn write_u128(&mut self, i: u128) {
316        (**self).write_u128(i)
317    }
318
319    #[inline]
320    fn write_usize(&mut self, i: usize) {
321        (**self).write_usize(i)
322    }
323
324    #[inline]
325    fn write_i8(&mut self, i: i8) {
326        (**self).write_i8(i)
327    }
328
329    #[inline]
330    fn write_i16(&mut self, i: i16) {
331        (**self).write_i16(i)
332    }
333
334    #[inline]
335    fn write_i32(&mut self, i: i32) {
336        (**self).write_i32(i)
337    }
338
339    #[inline]
340    fn write_i64(&mut self, i: i64) {
341        (**self).write_i64(i)
342    }
343
344    #[inline]
345    fn write_i128(&mut self, i: i128) {
346        (**self).write_i128(i)
347    }
348
349    #[inline]
350    fn write_isize(&mut self, i: isize) {
351        (**self).write_isize(i)
352    }
353}