1use crate::rt::Cleanup;
2use crate::rt::async_support::StreamOps;
3use alloc::alloc::Layout;
4use alloc::vec::Vec;
5use core::mem::{self, MaybeUninit};
6use core::ptr;
7
8pub struct AbiBuffer<O: StreamOps> {
20 rust_storage: Vec<MaybeUninit<O::Payload>>,
21 ops: O,
22 alloc: Option<Cleanup>,
23 cursor: usize,
24}
25
26impl<O: StreamOps> AbiBuffer<O> {
27 pub(crate) fn new(mut vec: Vec<O::Payload>, mut ops: O) -> AbiBuffer<O> {
28 let rust_storage = unsafe {
31 let ptr = vec.as_mut_ptr();
32 let len = vec.len();
33 let cap = vec.capacity();
34 mem::forget(vec);
35 Vec::<MaybeUninit<O::Payload>>::from_raw_parts(ptr.cast(), len, cap)
36 };
37
38 let alloc = if ops.native_abi_matches_canonical_abi() {
45 None
46 } else {
47 let elem_layout = ops.elem_layout();
48 let layout = Layout::from_size_align(
49 elem_layout.size() * rust_storage.len(),
50 elem_layout.align(),
51 )
52 .unwrap();
53 let (mut ptr, cleanup) = Cleanup::new(layout);
54 unsafe {
58 for item in rust_storage.iter() {
59 let item = item.assume_init_read();
60 ops.lower(item, ptr);
61 ptr = ptr.add(elem_layout.size());
62 }
63 }
64 cleanup
65 };
66 AbiBuffer {
67 rust_storage,
68 alloc,
69 ops,
70 cursor: 0,
71 }
72 }
73
74 pub(crate) fn abi_ptr_and_len(&self) -> (*const u8, usize) {
77 if self.ops.native_abi_matches_canonical_abi() {
81 let ptr = unsafe { self.rust_storage.as_ptr().add(self.cursor).cast() };
83 let len = self.rust_storage.len() - self.cursor;
84 return (ptr, len.try_into().unwrap());
85 }
86
87 let ptr = self
90 .alloc
91 .as_ref()
92 .map(|c| c.ptr.as_ptr())
93 .unwrap_or(ptr::null_mut());
94 (
95 unsafe { ptr.add(self.cursor * self.ops.elem_layout().size()) },
97 self.rust_storage.len() - self.cursor,
98 )
99 }
100
101 pub fn into_vec(mut self) -> Vec<O::Payload> {
114 self.take_vec()
115 }
116
117 pub fn remaining(&self) -> usize {
119 self.rust_storage.len() - self.cursor
120 }
121
122 pub(crate) fn advance(&mut self, amt: usize) {
128 assert!(amt + self.cursor <= self.rust_storage.len());
129 if !self.ops.contains_lists() {
130 self.cursor += amt;
131 return;
132 }
133 let (mut ptr, len) = self.abi_ptr_and_len();
134 assert!(amt <= len);
135 for _ in 0..amt {
136 self.cursor += 1;
142 unsafe {
146 self.ops.dealloc_lists(ptr.cast_mut());
147 ptr = ptr.add(self.ops.elem_layout().size());
148 }
149 }
150 }
151
152 fn take_vec(&mut self) -> Vec<O::Payload> {
153 if !self.ops.native_abi_matches_canonical_abi() {
163 let (mut ptr, mut len) = self.abi_ptr_and_len();
164 unsafe {
168 for dst in self.rust_storage[self.cursor..].iter_mut() {
169 dst.write(self.ops.lift(ptr.cast_mut()));
170 ptr = ptr.add(self.ops.elem_layout().size());
171 len -= 1;
172 }
173 assert_eq!(len, 0);
174 }
175 }
176
177 let mut storage = mem::take(&mut self.rust_storage);
182 storage.drain(..self.cursor);
183 self.cursor = 0;
184 self.alloc = None;
185
186 unsafe {
190 let ptr = storage.as_mut_ptr();
191 let len = storage.len();
192 let cap = storage.capacity();
193 mem::forget(storage);
194 Vec::<O::Payload>::from_raw_parts(ptr.cast(), len, cap)
195 }
196 }
197}
198
199impl<O> Drop for AbiBuffer<O>
200where
201 O: StreamOps,
202{
203 fn drop(&mut self) {
204 let _ = self.take_vec();
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use crate::rt::async_support::StreamVtable;
212 use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
213 use std::vec;
214
215 extern "C" fn cancel(_: u32) -> u32 {
216 todo!()
217 }
218 extern "C" fn drop(_: u32) {
219 todo!()
220 }
221 extern "C" fn new() -> u64 {
222 todo!()
223 }
224 extern "C" fn start_read(_: u32, _: *mut u8, _: usize) -> u32 {
225 todo!()
226 }
227 extern "C" fn start_write(_: u32, _: *const u8, _: usize) -> u32 {
228 todo!()
229 }
230
231 static BLANK: StreamVtable<u8> = StreamVtable {
232 cancel_read: cancel,
233 cancel_write: cancel,
234 drop_readable: drop,
235 drop_writable: drop,
236 dealloc_lists: None,
237 lift: None,
238 lower: None,
239 layout: unsafe { Layout::from_size_align_unchecked(1, 1) },
240 new,
241 start_read,
242 start_write,
243 };
244
245 #[test]
246 fn blank_advance_to_end() {
247 let mut buffer = AbiBuffer::new(vec![1, 2, 3, 4], &BLANK);
248 assert_eq!(buffer.remaining(), 4);
249 buffer.advance(1);
250 assert_eq!(buffer.remaining(), 3);
251 buffer.advance(2);
252 assert_eq!(buffer.remaining(), 1);
253 buffer.advance(1);
254 assert_eq!(buffer.remaining(), 0);
255 assert_eq!(buffer.into_vec(), []);
256 }
257
258 #[test]
259 fn blank_advance_partial() {
260 let buffer = AbiBuffer::new(vec![1, 2, 3, 4], &BLANK);
261 assert_eq!(buffer.into_vec(), [1, 2, 3, 4]);
262 let mut buffer = AbiBuffer::new(vec![1, 2, 3, 4], &BLANK);
263 buffer.advance(1);
264 assert_eq!(buffer.into_vec(), [2, 3, 4]);
265 let mut buffer = AbiBuffer::new(vec![1, 2, 3, 4], &BLANK);
266 buffer.advance(1);
267 buffer.advance(2);
268 assert_eq!(buffer.into_vec(), [4]);
269 }
270
271 #[test]
272 fn blank_ptr_eq() {
273 let mut buf = vec![1, 2, 3, 4];
274 let ptr = buf.as_mut_ptr();
275 let mut buffer = AbiBuffer::new(buf, &BLANK);
276 let (a, b) = buffer.abi_ptr_and_len();
277 assert_eq!(a, ptr);
278 assert_eq!(b, 4);
279 unsafe {
280 assert_eq!(std::slice::from_raw_parts(a, b), [1, 2, 3, 4]);
281 }
282
283 buffer.advance(1);
284 let (a, b) = buffer.abi_ptr_and_len();
285 assert_eq!(a, ptr.wrapping_add(1));
286 assert_eq!(b, 3);
287 unsafe {
288 assert_eq!(std::slice::from_raw_parts(a, b), [2, 3, 4]);
289 }
290
291 buffer.advance(2);
292 let (a, b) = buffer.abi_ptr_and_len();
293 assert_eq!(a, ptr.wrapping_add(3));
294 assert_eq!(b, 1);
295 unsafe {
296 assert_eq!(std::slice::from_raw_parts(a, b), [4]);
297 }
298
299 let ret = buffer.into_vec();
300 assert_eq!(ret, [4]);
301 assert_eq!(ret.as_ptr(), ptr);
302 }
303
304 #[derive(PartialEq, Eq, Debug)]
305 struct B(u8);
306
307 static OP: StreamVtable<B> = StreamVtable {
308 cancel_read: cancel,
309 cancel_write: cancel,
310 drop_readable: drop,
311 drop_writable: drop,
312 dealloc_lists: Some(|_ptr| {}),
313 lift: Some(|ptr| unsafe { B(*ptr - 1) }),
314 lower: Some(|b, ptr| unsafe {
315 *ptr = b.0 + 1;
316 }),
317 layout: unsafe { Layout::from_size_align_unchecked(1, 1) },
318 new,
319 start_read,
320 start_write,
321 };
322
323 #[test]
324 fn op_advance_to_end() {
325 let mut buffer = AbiBuffer::new(vec![B(1), B(2), B(3), B(4)], &OP);
326 assert_eq!(buffer.remaining(), 4);
327 buffer.advance(1);
328 assert_eq!(buffer.remaining(), 3);
329 buffer.advance(2);
330 assert_eq!(buffer.remaining(), 1);
331 buffer.advance(1);
332 assert_eq!(buffer.remaining(), 0);
333 assert_eq!(buffer.into_vec(), []);
334 }
335
336 #[test]
337 fn op_advance_partial() {
338 let buffer = AbiBuffer::new(vec![B(1), B(2), B(3), B(4)], &OP);
339 assert_eq!(buffer.into_vec(), [B(1), B(2), B(3), B(4)]);
340 let mut buffer = AbiBuffer::new(vec![B(1), B(2), B(3), B(4)], &OP);
341 buffer.advance(1);
342 assert_eq!(buffer.into_vec(), [B(2), B(3), B(4)]);
343 let mut buffer = AbiBuffer::new(vec![B(1), B(2), B(3), B(4)], &OP);
344 buffer.advance(1);
345 buffer.advance(2);
346 assert_eq!(buffer.into_vec(), [B(4)]);
347 }
348
349 #[test]
350 fn op_ptrs() {
351 let mut buf = vec![B(1), B(2), B(3), B(4)];
352 let ptr = buf.as_mut_ptr().cast::<u8>();
353 let mut buffer = AbiBuffer::new(buf, &OP);
354 let (a, b) = buffer.abi_ptr_and_len();
355 let base = a;
356 assert_ne!(a, ptr);
357 assert_eq!(b, 4);
358 unsafe {
359 assert_eq!(std::slice::from_raw_parts(a, b), [2, 3, 4, 5]);
360 }
361
362 buffer.advance(1);
363 let (a, b) = buffer.abi_ptr_and_len();
364 assert_ne!(a, ptr.wrapping_add(1));
365 assert_eq!(a, base.wrapping_add(1));
366 assert_eq!(b, 3);
367 unsafe {
368 assert_eq!(std::slice::from_raw_parts(a, b), [3, 4, 5]);
369 }
370
371 buffer.advance(2);
372 let (a, b) = buffer.abi_ptr_and_len();
373 assert_ne!(a, ptr.wrapping_add(3));
374 assert_eq!(a, base.wrapping_add(3));
375 assert_eq!(b, 1);
376 unsafe {
377 assert_eq!(std::slice::from_raw_parts(a, b), [5]);
378 }
379
380 let ret = buffer.into_vec();
381 assert_eq!(ret, [B(4)]);
382 assert_eq!(ret.as_ptr(), ptr.cast());
383 }
384
385 #[test]
386 fn dealloc_lists() {
387 static DEALLOCS: AtomicUsize = AtomicUsize::new(0);
388 static OP: StreamVtable<B> = StreamVtable {
389 cancel_read: cancel,
390 cancel_write: cancel,
391 drop_readable: drop,
392 drop_writable: drop,
393 dealloc_lists: Some(|ptr| {
394 let prev = DEALLOCS.fetch_add(1, Relaxed);
395 assert_eq!(unsafe { usize::from(*ptr) }, prev + 1);
396 }),
397 lift: Some(|ptr| unsafe { B(*ptr) }),
398 lower: Some(|b, ptr| unsafe {
399 *ptr = b.0;
400 }),
401 layout: unsafe { Layout::from_size_align_unchecked(1, 1) },
402 new,
403 start_read,
404 start_write,
405 };
406
407 assert_eq!(DEALLOCS.load(Relaxed), 0);
408 let buf = vec![B(1), B(2), B(3), B(4)];
409 let mut buffer = AbiBuffer::new(buf, &OP);
410 assert_eq!(DEALLOCS.load(Relaxed), 0);
411 buffer.abi_ptr_and_len();
412 assert_eq!(DEALLOCS.load(Relaxed), 0);
413
414 buffer.advance(1);
415 assert_eq!(DEALLOCS.load(Relaxed), 1);
416 buffer.abi_ptr_and_len();
417 assert_eq!(DEALLOCS.load(Relaxed), 1);
418 buffer.advance(2);
419 assert_eq!(DEALLOCS.load(Relaxed), 3);
420 buffer.abi_ptr_and_len();
421 assert_eq!(DEALLOCS.load(Relaxed), 3);
422 buffer.into_vec();
423 assert_eq!(DEALLOCS.load(Relaxed), 3);
424 }
425}