slice_dst/
provided_types.rs

1use super::*;
2
3#[repr(C)]
4#[derive(Debug, Eq, PartialEq, Hash)]
5/// A custom slice-based DST.
6///
7/// The length is stored as a `usize` at offset 0.
8/// This _must_ be the length of the trailing slice of the DST.
9pub struct SliceWithHeader<Header, Item> {
10    /// Safety: must be at offset 0
11    length: usize,
12    /// The included header. Does not dictate the slice length.
13    pub header: Header,
14    /// The included slice.
15    pub slice: [Item],
16}
17
18unsafe impl<Header, Item> SliceDst for SliceWithHeader<Header, Item> {
19    fn layout_for(len: usize) -> Layout {
20        Self::layout(len).0
21    }
22
23    fn retype(ptr: ptr::NonNull<[()]>) -> ptr::NonNull<Self> {
24        unsafe { ptr::NonNull::new_unchecked(ptr.as_ptr() as *mut _) }
25    }
26}
27
28impl<Header, Item> SliceWithHeader<Header, Item> {
29    fn layout(len: usize) -> (Layout, [usize; 3]) {
30        let length_layout = Layout::new::<usize>();
31        let header_layout = Layout::new::<Header>();
32        let slice_layout = Layout::array::<Item>(len).unwrap();
33        polyfill::repr_c_3([length_layout, header_layout, slice_layout]).unwrap()
34    }
35
36    #[allow(clippy::new_ret_no_self)]
37    /// Create a new slice/header DST in a [`AllocSliceDst`] container.
38    ///
39    /// # Panics
40    ///
41    /// Panics if the items iterator incorrectly reports its length.
42    pub fn new<A, I>(header: Header, items: I) -> A
43    where
44        A: AllocSliceDst<Self>,
45        I: IntoIterator<Item = Item>,
46        I::IntoIter: ExactSizeIterator,
47    {
48        let items = items.into_iter();
49        let len = items.len();
50
51        struct InProgress<Header, Item> {
52            raw: ptr::NonNull<SliceWithHeader<Header, Item>>,
53            written: usize,
54            layout: Layout,
55            length_offset: usize,
56            header_offset: usize,
57            slice_offset: usize,
58        }
59
60        impl<Header, Item> Drop for InProgress<Header, Item> {
61            fn drop(&mut self) {
62                unsafe {
63                    ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
64                        self.raw().add(self.slice_offset).cast::<Item>(),
65                        self.written,
66                    ));
67                }
68            }
69        }
70
71        impl<Header, Item> InProgress<Header, Item> {
72            fn init(
73                len: usize,
74                header: Header,
75                mut items: impl ExactSizeIterator<Item = Item>,
76            ) -> impl FnOnce(ptr::NonNull<SliceWithHeader<Header, Item>>) {
77                move |ptr| {
78                    let mut this = Self::new(len, ptr);
79
80                    unsafe {
81                        for _ in 0..len {
82                            let item = items
83                                .next()
84                                .expect("ExactSizeIterator over-reported length");
85                            this.push(item);
86                        }
87
88                        assert!(
89                            items.next().is_none(),
90                            "ExactSizeIterator under-reported length"
91                        );
92
93                        this.finish(len, header)
94                    }
95                }
96            }
97
98            fn raw(&self) -> *mut u8 {
99                self.raw.as_ptr().cast()
100            }
101
102            fn new(len: usize, raw: ptr::NonNull<SliceWithHeader<Header, Item>>) -> Self {
103                let (layout, [length_offset, header_offset, slice_offset]) =
104                    SliceWithHeader::<Header, Item>::layout(len);
105                InProgress {
106                    raw,
107                    written: 0,
108                    layout,
109                    length_offset,
110                    header_offset,
111                    slice_offset,
112                }
113            }
114
115            unsafe fn push(&mut self, item: Item) {
116                self.raw()
117                    .add(self.slice_offset)
118                    .cast::<Item>()
119                    .add(self.written)
120                    .write(item);
121                self.written += 1;
122            }
123
124            unsafe fn finish(self, len: usize, header: Header) {
125                let this = ManuallyDrop::new(self);
126                ptr::write(this.raw().add(this.length_offset).cast(), len);
127                ptr::write(this.raw().add(this.header_offset).cast(), header);
128                debug_assert_eq!(this.layout, Layout::for_value(this.raw.as_ref()))
129            }
130        }
131
132        unsafe { A::new_slice_dst(len, InProgress::init(len, header, items)) }
133    }
134
135    #[allow(clippy::new_ret_no_self)]
136    /// Create a new slice/header DST from a slice, in a [`AllocSliceDst`] container.
137    pub fn from_slice<A>(header: Header, s: &[Item]) -> A
138    where
139        A: AllocSliceDst<Self>,
140        Item: Copy,
141    {
142        let len = s.len();
143        let (layout, [length_offset, header_offset, slice_offset]) = Self::layout(len);
144        unsafe {
145            A::new_slice_dst(len, |ptr| {
146                let raw = ptr.as_ptr().cast::<u8>();
147                ptr::write(raw.add(length_offset).cast(), len);
148                ptr::write(raw.add(header_offset).cast(), header);
149                ptr::copy_nonoverlapping(s.as_ptr(), raw.add(slice_offset).cast(), len);
150                debug_assert_eq!(Layout::for_value(ptr.as_ref()), layout);
151            })
152        }
153    }
154}
155
156impl<Header, Item> Clone for Box<SliceWithHeader<Header, Item>>
157where
158    Header: Clone,
159    Item: Clone,
160{
161    fn clone(&self) -> Self {
162        SliceWithHeader::new(self.header.clone(), self.slice.iter().cloned())
163    }
164}
165
166#[cfg(feature = "erasable")]
167unsafe impl<Header, Item> Erasable for SliceWithHeader<Header, Item> {
168    unsafe fn unerase(this: ErasedPtr) -> ptr::NonNull<Self> {
169        let len: usize = ptr::read(this.as_ptr().cast());
170        let raw =
171            ptr::NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(this.as_ptr().cast(), len));
172        Self::retype(raw)
173    }
174
175    const ACK_1_1_0: bool = true;
176}
177
178#[repr(C)]
179#[derive(Debug, Eq, PartialEq, Hash)]
180/// A custom str-based DST.
181///
182/// The length is stored as a `usize` at offset 0.
183/// This _must_ be the length of the trailing slice.
184pub struct StrWithHeader<Header> {
185    /// Safety: must be at offset 0
186    length: usize,
187    /// The included header. Does not dictate the slice length.
188    pub header: Header,
189    /// The included str.
190    pub str: str,
191}
192
193unsafe impl<Header> SliceDst for StrWithHeader<Header> {
194    fn layout_for(len: usize) -> Layout {
195        Self::layout(len).0
196    }
197
198    fn retype(ptr: ptr::NonNull<[()]>) -> ptr::NonNull<Self> {
199        unsafe { ptr::NonNull::new_unchecked(ptr.as_ptr() as *mut _) }
200    }
201}
202
203impl<Header> StrWithHeader<Header> {
204    fn layout(len: usize) -> (Layout, [usize; 3]) {
205        let length_layout = Layout::new::<usize>();
206        let header_layout = Layout::new::<Header>();
207        let slice_layout = Layout::array::<u8>(len).unwrap();
208        polyfill::repr_c_3([length_layout, header_layout, slice_layout]).unwrap()
209    }
210
211    #[allow(clippy::new_ret_no_self)]
212    /// Create a new str/header DST in a [`AllocSliceDst`] container.
213    pub fn new<A>(header: Header, s: &str) -> A
214    where
215        A: AllocSliceDst<Self>,
216    {
217        let len = s.len();
218        let (layout, [length_offset, header_offset, str_offset]) = Self::layout(len);
219        unsafe {
220            A::new_slice_dst(len, |ptr| {
221                let raw = ptr.as_ptr().cast::<u8>();
222                ptr::write(raw.add(length_offset).cast(), len);
223                ptr::write(raw.add(header_offset).cast(), header);
224                ptr::copy_nonoverlapping(s.as_bytes().as_ptr(), raw.add(str_offset).cast(), len);
225                debug_assert_eq!(Layout::for_value(ptr.as_ref()), layout);
226            })
227        }
228    }
229}
230
231impl<Header> Clone for Box<StrWithHeader<Header>>
232where
233    Header: Clone,
234{
235    fn clone(&self) -> Self {
236        StrWithHeader::new(self.header.clone(), &self.str)
237    }
238}
239
240#[cfg(feature = "erasable")]
241unsafe impl<Header> Erasable for StrWithHeader<Header> {
242    unsafe fn unerase(this: ErasedPtr) -> ptr::NonNull<Self> {
243        let len: usize = ptr::read(this.as_ptr().cast());
244        let raw =
245            ptr::NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(this.as_ptr().cast(), len));
246        Self::retype(raw)
247    }
248
249    const ACK_1_1_0: bool = true;
250}