Skip to main content

stabby_abi/alloc/
boxed.rs

1//
2// Copyright (c) 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   Pierre Avital, <pierre.avital@me.com>
13//
14
15use crate::{unreachable_unchecked, AnonymRef, AnonymRefMut, IPtrMut, IntoDyn};
16
17use super::{vec::*, AllocPtr, AllocSlice, IAlloc};
18use core::{
19    fmt::Debug,
20    marker::PhantomData,
21    mem::{ManuallyDrop, MaybeUninit},
22    ptr::NonNull,
23};
24
25/// An ABI-stable Box, provided `Alloc` is ABI-stable.
26#[crate::stabby]
27pub struct Box<T, Alloc: IAlloc = super::DefaultAllocator> {
28    ptr: AllocPtr<T, Alloc>,
29}
30// SAFETY: Same constraints as `std::boxed::Box`
31unsafe impl<T: Send, Alloc: IAlloc + Send> Send for Box<T, Alloc> {}
32// SAFETY: Same constraints as `std::boxed::Box`
33unsafe impl<T: Sync, Alloc: IAlloc> Sync for Box<T, Alloc> {}
34// SAFETY: Same constraints as `std::boxed::Box`
35unsafe impl<T: Send, Alloc: IAlloc + Send> Send for BoxedSlice<T, Alloc> {}
36// SAFETY: Same constraints as `std::boxed::Box`
37unsafe impl<T: Sync, Alloc: IAlloc> Sync for BoxedSlice<T, Alloc> {}
38
39#[cfg(not(stabby_default_alloc = "disabled"))]
40impl<T> Box<T> {
41    /// Attempts to allocate [`Self`], initializing it with `constructor`.
42    ///
43    /// Note that the allocation may or may not be zeroed.
44    ///
45    /// If the allocation fails, the `constructor` will not be run.
46    ///
47    /// # Safety
48    /// `constructor` MUST return `Err(())` if it failed to initialize the passed argument.
49    ///
50    /// # Errors
51    /// Returns the uninitialized allocation if the constructor declares a failure.
52    ///
53    /// # Panics
54    /// If the allocator fails to provide an appropriate allocation.
55    pub unsafe fn make<
56        F: for<'a> FnOnce(&'a mut core::mem::MaybeUninit<T>) -> Result<&'a mut T, ()>,
57    >(
58        constructor: F,
59    ) -> Result<Self, Box<MaybeUninit<T>>> {
60        // SAFETY: Ensured by parent fn
61        unsafe { Self::make_in(constructor, super::DefaultAllocator::new()) }
62    }
63    /// Attempts to allocate [`Self`] and store `value` in it.
64    ///
65    /// # Panics
66    /// If the allocator fails to provide an appropriate allocation.
67    pub fn new(value: T) -> Self {
68        Self::new_in(value, super::DefaultAllocator::new())
69    }
70}
71impl<T, Alloc: IAlloc> Box<T, Alloc> {
72    /// Attempts to allocate [`Self`], initializing it with `constructor`.
73    ///
74    /// Note that the allocation may or may not be zeroed.
75    ///
76    /// If the `constructor` panics, the allocated memory will be leaked.
77    ///
78    /// # Errors
79    /// - Returns the `constructor` and the allocator in case of allocation failure.
80    /// - Returns the uninitialized allocated memory if `constructor` fails.
81    ///
82    /// # Safety
83    /// `constructor` MUST return `Err(())` if it failed to initialize the passed argument.
84    ///
85    /// # Notes
86    /// Note that the allocation may or may not be zeroed.
87    #[allow(clippy::type_complexity)]
88    pub unsafe fn try_make_in<
89        F: for<'a> FnOnce(&'a mut core::mem::MaybeUninit<T>) -> Result<&'a mut T, ()>,
90    >(
91        constructor: F,
92        mut alloc: Alloc,
93    ) -> Result<Self, Result<Box<MaybeUninit<T>, Alloc>, (F, Alloc)>> {
94        let mut ptr = match AllocPtr::alloc(&mut alloc) {
95            Some(mut ptr) => {
96                // SAFETY: `ptr` just got allocated via `AllocPtr::alloc`.
97                unsafe { ptr.prefix_mut() }.alloc.write(alloc);
98                ptr
99            }
100            None => return Err(Err((constructor, alloc))),
101        };
102        // SAFETY: We are the sole owners of `ptr`
103        constructor(unsafe { ptr.as_mut() }).map_or_else(
104            |()| Err(Ok(Box { ptr })),
105            |_| {
106                Ok(Self {
107                    // SAFETY: `constructor` reported success.
108                    ptr: unsafe { ptr.assume_init() },
109                })
110            },
111        )
112    }
113    /// Attempts to allocate a [`Self`] and store `value` in it
114    /// # Errors
115    /// Returns `value` and the allocator in case of failure.
116    pub fn try_new_in(value: T, alloc: Alloc) -> Result<Self, (T, Alloc)> {
117        // SAFETY: `ctor` is a valid constructor, always initializing the value.
118        let this = unsafe {
119            Self::try_make_in(
120                |slot: &mut core::mem::MaybeUninit<T>| {
121                    // SAFETY: `value` will be forgotten if the allocation succeeds and `read` is called.
122                    Ok(slot.write(core::ptr::read(&value)))
123                },
124                alloc,
125            )
126        };
127        match this {
128            Ok(this) => {
129                core::mem::forget(value);
130                Ok(this)
131            }
132            Err(Err((_, a))) => Err((value, a)),
133            // SAFETY: the constructor is infallible.
134            Err(Ok(_)) => unsafe { unreachable_unchecked!() },
135        }
136    }
137    /// Attempts to allocate [`Self`], initializing it with `constructor`.
138    ///
139    /// Note that the allocation may or may not be zeroed.
140    ///
141    /// # Errors
142    /// Returns the uninitialized allocated memory if `constructor` fails.
143    ///
144    /// # Safety
145    /// `constructor` MUST return `Err(())` if it failed to initialize the passed argument.
146    ///
147    /// # Panics
148    /// If the allocator fails to provide an appropriate allocation.
149    pub unsafe fn make_in<
150        F: for<'a> FnOnce(&'a mut core::mem::MaybeUninit<T>) -> Result<&'a mut T, ()>,
151    >(
152        constructor: F,
153        alloc: Alloc,
154    ) -> Result<Self, Box<MaybeUninit<T>, Alloc>> {
155        Self::try_make_in(constructor, alloc).map_err(|e| match e {
156            Ok(uninit) => uninit,
157            Err(_) => panic!("Allocation failed"),
158        })
159    }
160    /// Attempts to allocate [`Self`] and store `value` in it.
161    ///
162    /// # Panics
163    /// If the allocator fails to provide an appropriate allocation.
164    pub fn new_in(value: T, alloc: Alloc) -> Self {
165        // SAFETY: `constructor` fits the spec.
166        let this = unsafe { Self::make_in(move |slot| Ok(slot.write(value)), alloc) };
167        // SAFETY: `constructor` is infallible.
168        unsafe { this.unwrap_unchecked() }
169    }
170    /// Extracts the value from the allocation, freeing said allocation.
171    pub fn into_inner(this: Self) -> T {
172        let mut this = core::mem::ManuallyDrop::new(this);
173        // SAFETY: `this` will not be dropped, preventing double-frees.
174        let ret = ManuallyDrop::new(unsafe { core::ptr::read(&**this) });
175        // SAFETY: `Box::free` only frees the memory allocation, without calling the destructor for `ret`'s source.
176        unsafe { this.free() };
177        ManuallyDrop::into_inner(ret)
178    }
179    /// Returns the pointer to the inner raw allocation, leaking `this`.
180    ///
181    /// Note that the pointer may be dangling if `T` is zero-sized.
182    pub const fn into_raw(this: Self) -> AllocPtr<T, Alloc> {
183        let inner = this.ptr;
184        core::mem::forget(this);
185        inner
186    }
187    /// Constructs `Self` from a raw allocation.
188    /// # Safety
189    /// No other container must own (even partially) `this`.
190    pub const unsafe fn from_raw(this: AllocPtr<T, Alloc>) -> Self {
191        Self { ptr: this }
192    }
193}
194
195impl<T, Alloc: IAlloc> Box<T, Alloc> {
196    /// Frees the allocation without destroying the value in it.
197    /// # Safety
198    /// `self` is in an invalid state after this and MUST be forgotten immediately.
199    unsafe fn free(&mut self) {
200        // SAFETY: `Box` guarantees that `alloc` is stored in the prefix, and it won't be reused after this.
201        let mut alloc = unsafe { self.ptr.prefix().alloc.assume_init_read() };
202        // SAFETY: `self.ptr` was definitely allocated in `alloc`
203        unsafe { self.ptr.free(&mut alloc) }
204    }
205}
206
207impl<T: Clone, Alloc: IAlloc + Clone> Clone for Box<T, Alloc> {
208    fn clone(&self) -> Self {
209        Box::new_in(
210            T::clone(self),
211            unsafe { self.ptr.prefix().alloc.assume_init_ref() }.clone(),
212        )
213    }
214}
215impl<T, Alloc: IAlloc> core::ops::Deref for Box<T, Alloc> {
216    type Target = T;
217    fn deref(&self) -> &Self::Target {
218        unsafe { self.ptr.as_ref() }
219    }
220}
221
222impl<T, Alloc: IAlloc> core::ops::DerefMut for Box<T, Alloc> {
223    fn deref_mut(&mut self) -> &mut Self::Target {
224        unsafe { self.ptr.as_mut() }
225    }
226}
227impl<T, Alloc: IAlloc> crate::IPtr for Box<T, Alloc> {
228    unsafe fn as_ref(&self) -> AnonymRef<'_> {
229        AnonymRef {
230            ptr: self.ptr.ptr.cast(),
231            _marker: PhantomData,
232        }
233    }
234}
235impl<T, Alloc: IAlloc> crate::IPtrMut for Box<T, Alloc> {
236    unsafe fn as_mut(&mut self) -> AnonymRefMut<'_> {
237        AnonymRefMut {
238            ptr: self.ptr.ptr.cast(),
239            _marker: PhantomData,
240        }
241    }
242}
243impl<T, Alloc: IAlloc> crate::IPtrOwned for Box<T, Alloc> {
244    fn drop(
245        this: &mut core::mem::ManuallyDrop<Self>,
246        drop: unsafe extern "C" fn(AnonymRefMut<'_>),
247    ) {
248        // SAFETY: This is evil casting shenanigans, but `IPtrOwned` is a type anonimization primitive.
249        unsafe {
250            drop(Self::as_mut(this));
251        }
252        // SAFETY: `this` is immediately forgotten.
253        unsafe { this.free() }
254    }
255}
256impl<T, Alloc: IAlloc> Drop for Box<T, Alloc> {
257    fn drop(&mut self) {
258        // SAFETY: We own the target of `ptr` and guarantee it is initialized.
259        unsafe {
260            core::ptr::drop_in_place(self.ptr.as_mut());
261        }
262        // SAFETY: `this` is immediately forgotten.
263        unsafe { self.free() }
264    }
265}
266impl<T, Alloc: IAlloc> IntoDyn for Box<T, Alloc> {
267    type Anonymized = Box<(), Alloc>;
268    type Target = T;
269    fn anonimize(self) -> Self::Anonymized {
270        let original_prefix = self.ptr.prefix_ptr();
271        // SAFETY: Evil anonimization.
272        let anonymized = unsafe { core::mem::transmute::<Self, Self::Anonymized>(self) };
273        let anonymized_prefix = anonymized.ptr.prefix_ptr();
274        assert_eq!(anonymized_prefix, original_prefix, "The allocation prefix was lost in anonimization, this is definitely a bug, please report it.");
275        anonymized
276    }
277}
278
279/// An ABI-stable boxed slice.
280///
281/// Note that unlike `std`'s [`Box<[T}>`], this carries the capacity around in the allocation prefix,
282/// allowing the reconversion into a [`super::vec::Vec<T, Alloc>`] to keep track
283/// of the capacity.
284///
285/// The inner pointer may be dangling if the slice's length is 0 or `T` is a ZST.
286#[crate::stabby]
287pub struct BoxedSlice<T, Alloc: IAlloc = super::DefaultAllocator> {
288    pub(crate) slice: AllocSlice<T, Alloc>,
289    pub(crate) alloc: Alloc,
290}
291impl<T, Alloc: IAlloc> BoxedSlice<T, Alloc> {
292    /// Constructs an empty boxed slice with a given capacity.
293    pub fn with_capacity_in(capacity: usize, alloc: Alloc) -> Self {
294        Vec::with_capacity_in(capacity, alloc).into()
295    }
296    /// The number of elements in the boxed slice.
297    pub const fn len(&self) -> usize {
298        ptr_diff(self.slice.end, self.slice.start.ptr)
299    }
300    /// Returns `true` if the slice is empty.
301    pub const fn is_empty(&self) -> bool {
302        self.len() == 0
303    }
304    /// Cast into a standard slice.
305    pub const fn as_slice(&self) -> &[T] {
306        // SAFETY: we own this slice.
307        unsafe { core::slice::from_raw_parts(self.slice.start.ptr.as_ptr(), self.len()) }
308    }
309    /// Cast into a standard mutable slice.
310    #[rustversion::attr(since(1.86), const)]
311    pub fn as_slice_mut(&mut self) -> &mut [T] {
312        // SAFETY: we own this slice.
313        unsafe { core::slice::from_raw_parts_mut(self.slice.start.ptr.as_ptr(), self.len()) }
314    }
315    /// Attempts to add an element to the boxed slice without reallocating.
316    /// # Errors
317    /// Returns the value if pushing would require reallocating.
318    pub fn try_push(&mut self, value: T) -> Result<(), T> {
319        // SAFETY: the prefix must be initialized for this type to exist.
320        if self.slice.len()
321            >= unsafe { self.slice.start.prefix() }
322                .capacity
323                .load(core::sync::atomic::Ordering::Relaxed)
324        {
325            return Err(value);
326        }
327        // SAFETY: we've acertained that we have enough space to push an element.
328        unsafe {
329            core::ptr::write(self.slice.end.as_ptr(), value);
330            self.slice.end = NonNull::new_unchecked(self.slice.end.as_ptr().add(1));
331        }
332        Ok(())
333    }
334    pub(crate) fn into_raw_components(self) -> (AllocSlice<T, Alloc>, usize, Alloc) {
335        let slice = self.slice;
336        // SAFETY: We forget `alloc` immediately.
337        let alloc = unsafe { core::ptr::read(&self.alloc) };
338        core::mem::forget(self);
339        let capacity = if core::mem::size_of::<T>() == 0 || slice.is_empty() {
340            0
341        } else {
342            // SAFETY: we store the capacity in the prefix when constructed.
343            unsafe {
344                slice
345                    .start
346                    .prefix()
347                    .capacity
348                    .load(core::sync::atomic::Ordering::Relaxed)
349            }
350        };
351        (slice, capacity, alloc)
352    }
353}
354impl<T, Alloc: IAlloc> core::ops::Deref for BoxedSlice<T, Alloc> {
355    type Target = [T];
356    fn deref(&self) -> &Self::Target {
357        self.as_slice()
358    }
359}
360
361impl<T, Alloc: IAlloc> core::ops::DerefMut for BoxedSlice<T, Alloc> {
362    fn deref_mut(&mut self) -> &mut Self::Target {
363        self.as_slice_mut()
364    }
365}
366impl<T: Eq, Alloc: IAlloc> Eq for BoxedSlice<T, Alloc> {}
367impl<T: PartialEq, Alloc: IAlloc> PartialEq for BoxedSlice<T, Alloc> {
368    fn eq(&self, other: &Self) -> bool {
369        self.as_slice() == other.as_slice()
370    }
371}
372impl<T: Ord, Alloc: IAlloc> Ord for BoxedSlice<T, Alloc> {
373    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
374        self.as_slice().cmp(other.as_slice())
375    }
376}
377impl<T: PartialOrd, Alloc: IAlloc> PartialOrd for BoxedSlice<T, Alloc> {
378    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
379        self.as_slice().partial_cmp(other.as_slice())
380    }
381}
382impl<T: core::hash::Hash, Alloc: IAlloc> core::hash::Hash for BoxedSlice<T, Alloc> {
383    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
384        self.as_slice().hash(state)
385    }
386}
387impl<T, Alloc: IAlloc> From<Vec<T, Alloc>> for BoxedSlice<T, Alloc> {
388    fn from(value: Vec<T, Alloc>) -> Self {
389        let (mut slice, capacity, alloc) = value.into_raw_components();
390        if capacity != 0 {
391            // SAFETY: the AllocSlice is initialized, storing to it is safe.
392            unsafe {
393                slice.start.prefix_mut().capacity = core::sync::atomic::AtomicUsize::new(capacity);
394            }
395            Self {
396                slice: AllocSlice {
397                    start: slice.start,
398                    end: slice.end,
399                },
400                alloc,
401            }
402        } else {
403            Self { slice, alloc }
404        }
405    }
406}
407impl<T, Alloc: IAlloc> From<BoxedSlice<T, Alloc>> for Vec<T, Alloc> {
408    fn from(value: BoxedSlice<T, Alloc>) -> Self {
409        let (slice, capacity, alloc) = value.into_raw_components();
410        if capacity != 0 {
411            Vec {
412                inner: VecInner {
413                    start: slice.start,
414                    end: slice.end,
415                    capacity: ptr_add(slice.start.ptr, capacity),
416                    alloc,
417                },
418            }
419        } else {
420            Vec {
421                inner: VecInner {
422                    start: slice.start,
423                    end: slice.end,
424                    capacity: if core::mem::size_of::<T>() == 0 {
425                        unsafe { core::mem::transmute::<usize, NonNull<T>>(usize::MAX) }
426                    } else {
427                        slice.start.ptr
428                    },
429                    alloc,
430                },
431            }
432        }
433    }
434}
435impl<T: Copy, Alloc: IAlloc + Default> From<&[T]> for BoxedSlice<T, Alloc> {
436    fn from(value: &[T]) -> Self {
437        Vec::from(value).into()
438    }
439}
440impl<T, Alloc: IAlloc + Default> FromIterator<T> for BoxedSlice<T, Alloc> {
441    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
442        Vec::from_iter(iter).into()
443    }
444}
445
446impl<T, Alloc: IAlloc> Drop for BoxedSlice<T, Alloc> {
447    fn drop(&mut self) {
448        unsafe { core::ptr::drop_in_place(self.as_slice_mut()) }
449        if core::mem::size_of::<T>() != 0 && !self.is_empty() {
450            unsafe { self.slice.start.free(&mut self.alloc) }
451        }
452    }
453}
454
455impl<T: Debug, Alloc: IAlloc> Debug for BoxedSlice<T, Alloc> {
456    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
457        self.as_slice().fmt(f)
458    }
459}
460impl<T: core::fmt::LowerHex, Alloc: IAlloc> core::fmt::LowerHex for BoxedSlice<T, Alloc> {
461    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
462        let mut first = true;
463        for item in self {
464            if !first {
465                f.write_str(":")?;
466            }
467            first = false;
468            core::fmt::LowerHex::fmt(item, f)?;
469        }
470        Ok(())
471    }
472}
473impl<T: core::fmt::UpperHex, Alloc: IAlloc> core::fmt::UpperHex for BoxedSlice<T, Alloc> {
474    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
475        let mut first = true;
476        for item in self {
477            if !first {
478                f.write_str(":")?;
479            }
480            first = false;
481            core::fmt::UpperHex::fmt(item, f)?;
482        }
483        Ok(())
484    }
485}
486impl<'a, T, Alloc: IAlloc> IntoIterator for &'a BoxedSlice<T, Alloc> {
487    type Item = &'a T;
488    type IntoIter = core::slice::Iter<'a, T>;
489    fn into_iter(self) -> Self::IntoIter {
490        self.as_slice().iter()
491    }
492}
493impl<'a, T, Alloc: IAlloc> IntoIterator for &'a mut BoxedSlice<T, Alloc> {
494    type Item = &'a mut T;
495    type IntoIter = core::slice::IterMut<'a, T>;
496    fn into_iter(self) -> Self::IntoIter {
497        self.as_slice_mut().iter_mut()
498    }
499}
500impl<T, Alloc: IAlloc> IntoIterator for BoxedSlice<T, Alloc> {
501    type Item = T;
502    type IntoIter = super::vec::IntoIter<T, Alloc>;
503    fn into_iter(self) -> Self::IntoIter {
504        let this: super::vec::Vec<T, Alloc> = self.into();
505        this.into_iter()
506    }
507}
508pub use super::string::BoxedStr;
509
510#[cfg(feature = "serde")]
511mod serde_impl {
512    use super::*;
513    use crate::alloc::IAlloc;
514    use serde::{Deserialize, Serialize};
515    impl<T: Serialize, Alloc: IAlloc> Serialize for BoxedSlice<T, Alloc> {
516        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
517        where
518            S: serde::Serializer,
519        {
520            let slice: &[T] = self;
521            slice.serialize(serializer)
522        }
523    }
524    impl<'a, T: Deserialize<'a>, Alloc: IAlloc + Default> Deserialize<'a> for BoxedSlice<T, Alloc> {
525        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
526        where
527            D: serde::Deserializer<'a>,
528        {
529            crate::alloc::vec::Vec::deserialize(deserializer).map(Into::into)
530        }
531    }
532    impl<Alloc: IAlloc> Serialize for BoxedStr<Alloc> {
533        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
534        where
535            S: serde::Serializer,
536        {
537            let slice: &str = self;
538            slice.serialize(serializer)
539        }
540    }
541    impl<'a, Alloc: IAlloc + Default> Deserialize<'a> for BoxedStr<Alloc> {
542        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
543        where
544            D: serde::Deserializer<'a>,
545        {
546            crate::alloc::string::String::deserialize(deserializer).map(Into::into)
547        }
548    }
549}