1use super::*;
2
3#[repr(C)]
4#[derive(Debug, Eq, PartialEq, Hash)]
5pub struct SliceWithHeader<Header, Item> {
10 length: usize,
12 pub header: Header,
14 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 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 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)]
180pub struct StrWithHeader<Header> {
185 length: usize,
187 pub header: Header,
189 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 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}