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