arraybox/
lib.rs

1#![feature(ptr_metadata)]
2#![feature(unsize)]
3
4#![no_std]
5
6use core::borrow::{Borrow, BorrowMut};
7use core::fmt::{self, Debug, Display, Formatter};
8use core::marker::{PhantomData, Unsize};
9use core::mem::{ManuallyDrop, MaybeUninit, align_of, size_of};
10use core::ops::{Deref, DerefMut};
11use core::ptr::{self, Pointee};
12
13/// A helper type for creating [`ArrayBox`] with buffer appropriated for any of two types.
14///
15/// The type satisfies the following properties:
16///
17/// 1. `size_of::<AnyOf2<T1, T2>>() >= size_of::<T1>()`
18/// 2. `size_of::<AnyOf2<T1, T2>>() >= size_of::<T2>()`
19/// 3. `align_of::<AnyOf2<T1, T2>>() >= align_of::<T1>()`
20/// 4. `align_of::<AnyOf2<T1, T2>>() >= align_of::<T2>()`
21#[repr(C)]
22pub union AnyOf2<T1, T2> {
23    _a: ManuallyDrop<T1>,
24    _b: ManuallyDrop<T2>,
25}
26
27/// A stack-allocated container that can store dynamically sized types.
28///
29/// `B` type parameter specifies buffer size (`== size_of::<B>()`), and alignment (`== align_of::<B>()`).
30pub struct ArrayBox<'a, T: ?Sized + 'a, B> {
31    buf: MaybeUninit<B>,
32    metadata: <T as Pointee>::Metadata,
33    phantom: PhantomData<&'a T>,
34}
35
36impl<'a, T: ?Sized + 'a, B> Drop for ArrayBox<'a, T, B> {
37    fn drop(&mut self) {
38        unsafe { ptr::drop_in_place(self.as_mut_ptr()) };
39    }
40}
41
42impl<'a, T: ?Sized + 'a, B> ArrayBox<'a, T, B> {
43    /// Allocates memory on stack and then places `source` into it as DST `T`.
44    pub const fn new<S: Unsize<T>>(mut source: S) -> Self {
45        assert!(align_of::<B>() >= align_of::<S>());
46        assert!(size_of::<B>() >= size_of::<S>());
47        let metadata = (&mut source as *mut T).to_raw_parts().1;
48        let mut res = ArrayBox { buf: MaybeUninit::uninit(), metadata, phantom: PhantomData };
49        unsafe { ptr::write::<S>(res.buf.as_mut_ptr() as *mut u8 as *mut S, source) };
50        res
51    }
52
53    /// Return raw immutable pointer to the stored object.
54    pub fn as_ptr(&self) -> *const T {
55        let metadata = self.metadata;
56        ptr::from_raw_parts(self.buf.as_ptr() as *const u8 as *const (), metadata)
57    }
58
59    /// Return raw mutable pointer to the stored object.
60    pub fn as_mut_ptr(&mut self) -> *mut T {
61        let metadata = self.metadata;
62        ptr::from_raw_parts_mut(self.buf.as_mut_ptr() as *mut u8 as *mut (), metadata)
63    }
64}
65
66impl<'a, T: ?Sized + 'a, B> AsRef<T> for ArrayBox<'a, T, B> {
67    fn as_ref(&self) -> &T {
68        unsafe { &*self.as_ptr() }
69    }
70}
71
72impl<'a, T: ?Sized + 'a, B> AsMut<T> for ArrayBox<'a, T, B> {
73    fn as_mut(&mut self) -> &mut T {
74        unsafe { &mut *self.as_mut_ptr() }
75    }
76}
77
78impl<'a, T: ?Sized + 'a, B> Borrow<T> for ArrayBox<'a, T, B> {
79    fn borrow(&self) -> &T { self.as_ref() }
80}
81
82impl<'a, T: ?Sized + 'a, B> BorrowMut<T> for ArrayBox<'a, T, B> {
83    fn borrow_mut(&mut self) -> &mut T { self.as_mut() }
84}
85
86impl<'a, T: ?Sized + 'a, B> Deref for ArrayBox<'a, T, B> {
87    type Target = T;
88
89    fn deref(&self) -> &T { self.as_ref() }
90}
91
92impl<'a, T: ?Sized + 'a, B> DerefMut for ArrayBox<'a, T, B> {
93    fn deref_mut(&mut self) -> &mut T { self.as_mut() }
94}
95
96impl<'a, T: Debug + ?Sized + 'a, B> Debug for ArrayBox<'a, T, B> {
97    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
98        self.as_ref().fmt(f)
99    }
100}
101
102impl<'a, T: Display + ?Sized + 'a, B> Display for ArrayBox<'a, T, B> {
103    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
104        self.as_ref().fmt(f)
105    }
106}