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.inner which is available at
6// http://www.eclipse.org/legal/epl-2.inner, or the Apache License, Version 2.inner
7// which is available at https://www.apache.org/licenses/LICENSE-2.inner.
8//
9// SPDX-License-Identifier: EPL-2.inner OR Apache-2.inner
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        mut 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(this.as_mut());
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    #[rustversion::attr(since(1.86), const)]
306    pub fn as_slice(&self) -> &[T] {
307        // SAFETY: we own this slice.
308        unsafe { core::slice::from_raw_parts(self.slice.start.ptr.as_ptr(), self.len()) }
309    }
310    /// Cast into a standard mutable slice.
311    #[rustversion::attr(since(1.86), const)]
312    pub fn as_slice_mut(&mut self) -> &mut [T] {
313        // SAFETY: we own this slice.
314        unsafe { core::slice::from_raw_parts_mut(self.slice.start.ptr.as_ptr(), self.len()) }
315    }
316    /// Attempts to add an element to the boxed slice without reallocating.
317    /// # Errors
318    /// Returns the value if pushing would require reallocating.
319    pub fn try_push(&mut self, value: T) -> Result<(), T> {
320        // SAFETY: the prefix must be initialized for this type to exist.
321        if self.slice.len()
322            >= unsafe { self.slice.start.prefix() }
323                .capacity
324                .load(core::sync::atomic::Ordering::Relaxed)
325        {
326            return Err(value);
327        }
328        // SAFETY: we've acertained that we have enough space to push an element.
329        unsafe {
330            core::ptr::write(self.slice.end.as_ptr(), value);
331            self.slice.end = NonNull::new_unchecked(self.slice.end.as_ptr().add(1));
332        }
333        Ok(())
334    }
335    pub(crate) fn into_raw_components(self) -> (AllocSlice<T, Alloc>, usize, Alloc) {
336        let slice = self.slice;
337        // SAFETY: We forget `alloc` immediately.
338        let alloc = unsafe { core::ptr::read(&self.alloc) };
339        core::mem::forget(self);
340        let capacity = if core::mem::size_of::<T>() == 0 || slice.is_empty() {
341            0
342        } else {
343            // SAFETY: we store the capacity in the prefix when constructed.
344            unsafe {
345                slice
346                    .start
347                    .prefix()
348                    .capacity
349                    .load(core::sync::atomic::Ordering::Relaxed)
350            }
351        };
352        (slice, capacity, alloc)
353    }
354}
355impl<T, Alloc: IAlloc> core::ops::Deref for BoxedSlice<T, Alloc> {
356    type Target = [T];
357    fn deref(&self) -> &Self::Target {
358        self.as_slice()
359    }
360}
361
362impl<T, Alloc: IAlloc> core::ops::DerefMut for BoxedSlice<T, Alloc> {
363    fn deref_mut(&mut self) -> &mut Self::Target {
364        self.as_slice_mut()
365    }
366}
367impl<T: Eq, Alloc: IAlloc> Eq for BoxedSlice<T, Alloc> {}
368impl<T: PartialEq, Alloc: IAlloc> PartialEq for BoxedSlice<T, Alloc> {
369    fn eq(&self, other: &Self) -> bool {
370        self.as_slice() == other.as_slice()
371    }
372}
373impl<T: Ord, Alloc: IAlloc> Ord for BoxedSlice<T, Alloc> {
374    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
375        self.as_slice().cmp(other.as_slice())
376    }
377}
378impl<T: PartialOrd, Alloc: IAlloc> PartialOrd for BoxedSlice<T, Alloc> {
379    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
380        self.as_slice().partial_cmp(other.as_slice())
381    }
382}
383impl<T: core::hash::Hash, Alloc: IAlloc> core::hash::Hash for BoxedSlice<T, Alloc> {
384    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
385        self.as_slice().hash(state)
386    }
387}
388impl<T, Alloc: IAlloc> From<Vec<T, Alloc>> for BoxedSlice<T, Alloc> {
389    fn from(value: Vec<T, Alloc>) -> Self {
390        let (mut slice, capacity, alloc) = value.into_raw_components();
391        if capacity != 0 {
392            // SAFETY: the AllocSlice is initialized, storing to it is safe.
393            unsafe {
394                slice.start.prefix_mut().capacity = core::sync::atomic::AtomicUsize::new(capacity);
395            }
396            Self {
397                slice: AllocSlice {
398                    start: slice.start,
399                    end: slice.end,
400                },
401                alloc,
402            }
403        } else {
404            Self { slice, alloc }
405        }
406    }
407}
408impl<T, Alloc: IAlloc> From<BoxedSlice<T, Alloc>> for Vec<T, Alloc> {
409    fn from(value: BoxedSlice<T, Alloc>) -> Self {
410        let (slice, capacity, alloc) = value.into_raw_components();
411        if capacity != 0 {
412            Vec {
413                inner: VecInner {
414                    start: slice.start,
415                    end: slice.end,
416                    capacity: ptr_add(slice.start.ptr, capacity),
417                    alloc,
418                },
419            }
420        } else {
421            Vec {
422                inner: VecInner {
423                    start: slice.start,
424                    end: slice.end,
425                    capacity: if core::mem::size_of::<T>() == 0 {
426                        unsafe { core::mem::transmute::<usize, NonNull<T>>(usize::MAX) }
427                    } else {
428                        slice.start.ptr
429                    },
430                    alloc,
431                },
432            }
433        }
434    }
435}
436impl<T: Copy, Alloc: IAlloc + Default> From<&[T]> for BoxedSlice<T, Alloc> {
437    fn from(value: &[T]) -> Self {
438        Vec::from(value).into()
439    }
440}
441impl<T, Alloc: IAlloc + Default> FromIterator<T> for BoxedSlice<T, Alloc> {
442    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
443        Vec::from_iter(iter).into()
444    }
445}
446
447impl<T, Alloc: IAlloc> Drop for BoxedSlice<T, Alloc> {
448    fn drop(&mut self) {
449        unsafe { core::ptr::drop_in_place(self.as_slice_mut()) }
450        if core::mem::size_of::<T>() != 0 && !self.is_empty() {
451            unsafe { self.slice.start.free(&mut self.alloc) }
452        }
453    }
454}
455
456impl<T: Debug, Alloc: IAlloc> Debug for BoxedSlice<T, Alloc> {
457    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
458        self.as_slice().fmt(f)
459    }
460}
461impl<T: core::fmt::LowerHex, Alloc: IAlloc> core::fmt::LowerHex for BoxedSlice<T, Alloc> {
462    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
463        let mut first = true;
464        for item in self {
465            if !first {
466                f.write_str(":")?;
467            }
468            first = false;
469            core::fmt::LowerHex::fmt(item, f)?;
470        }
471        Ok(())
472    }
473}
474impl<T: core::fmt::UpperHex, Alloc: IAlloc> core::fmt::UpperHex for BoxedSlice<T, Alloc> {
475    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
476        let mut first = true;
477        for item in self {
478            if !first {
479                f.write_str(":")?;
480            }
481            first = false;
482            core::fmt::UpperHex::fmt(item, f)?;
483        }
484        Ok(())
485    }
486}
487impl<'a, T, Alloc: IAlloc> IntoIterator for &'a BoxedSlice<T, Alloc> {
488    type Item = &'a T;
489    type IntoIter = core::slice::Iter<'a, T>;
490    fn into_iter(self) -> Self::IntoIter {
491        self.as_slice().iter()
492    }
493}
494impl<'a, T, Alloc: IAlloc> IntoIterator for &'a mut BoxedSlice<T, Alloc> {
495    type Item = &'a mut T;
496    type IntoIter = core::slice::IterMut<'a, T>;
497    fn into_iter(self) -> Self::IntoIter {
498        self.as_slice_mut().iter_mut()
499    }
500}
501impl<T, Alloc: IAlloc> IntoIterator for BoxedSlice<T, Alloc> {
502    type Item = T;
503    type IntoIter = super::vec::IntoIter<T, Alloc>;
504    fn into_iter(self) -> Self::IntoIter {
505        let this: super::vec::Vec<T, Alloc> = self.into();
506        this.into_iter()
507    }
508}
509pub use super::string::BoxedStr;
510
511#[cfg(feature = "serde")]
512mod serde_impl {
513    use super::*;
514    use crate::alloc::IAlloc;
515    use serde::{Deserialize, Serialize};
516    impl<T: Serialize, Alloc: IAlloc> Serialize for BoxedSlice<T, Alloc> {
517        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
518        where
519            S: serde::Serializer,
520        {
521            let slice: &[T] = self;
522            slice.serialize(serializer)
523        }
524    }
525    impl<'a, T: Deserialize<'a>, Alloc: IAlloc + Default> Deserialize<'a> for BoxedSlice<T, Alloc> {
526        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
527        where
528            D: serde::Deserializer<'a>,
529        {
530            crate::alloc::vec::Vec::deserialize(deserializer).map(Into::into)
531        }
532    }
533    impl<Alloc: IAlloc> Serialize for BoxedStr<Alloc> {
534        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
535        where
536            S: serde::Serializer,
537        {
538            let slice: &str = self;
539            slice.serialize(serializer)
540        }
541    }
542    impl<'a, Alloc: IAlloc + Default> Deserialize<'a> for BoxedStr<Alloc> {
543        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
544        where
545            D: serde::Deserializer<'a>,
546        {
547            crate::alloc::string::String::deserialize(deserializer).map(Into::into)
548        }
549    }
550}