Skip to main content

wincode/io/
slice.rs

1use {
2    super::*,
3    core::{marker::PhantomData, ptr::copy_nonoverlapping},
4};
5
6/// Split the given mutable slice by `len` bytes, advancing the slice by `len` bytes, or
7/// returning an error if the input slice does not have at least `len` bytes remaining.
8#[inline(always)]
9fn advance_slice_mut_checked<'a, T>(input: &mut &'a mut [T], len: usize) -> Option<&'a mut [T]> {
10    let (dst, rest) = mem::take(input).split_at_mut_checked(len)?;
11    *input = rest;
12    Some(dst)
13}
14
15/// Split the given mutable slice by `len` bytes, advancing the slice by `len` bytes.
16///
17/// # Safety
18///
19/// Calling this method with an out-of-bounds `len` is undefined behavior
20/// even if the resulting reference is not used. The caller has to ensure that
21/// `0 <= len <= self.len()`.
22#[inline(always)]
23unsafe fn advance_slice_mut_unchecked<'a, T>(input: &mut &'a mut [T], len: usize) -> &'a mut [T] {
24    let (dst, rest) = unsafe { mem::take(input).split_at_mut_unchecked(len) };
25    *input = rest;
26    dst
27}
28
29/// Split the given slice by `len` bytes, advancing the slice by `len` bytes, or
30/// returning an error if the input slice does not have at least `len` bytes remaining.
31#[inline(always)]
32fn advance_slice_checked<'a, T>(input: &mut &'a [T], len: usize) -> Option<&'a [T]> {
33    let (dst, rest) = input.split_at_checked(len)?;
34    *input = rest;
35    Some(dst)
36}
37
38/// Split the given slice by `len` bytes, advancing the slice by `len` bytes.
39///
40/// # Safety
41///
42/// Calling this method with an out-of-bounds `len` is undefined behavior
43/// even if the resulting reference is not used. The caller has to ensure that
44/// `0 <= len <= self.len()`.
45#[inline(always)]
46unsafe fn advance_slice_unchecked<'a, T>(input: &mut &'a [T], len: usize) -> &'a [T] {
47    let (dst, rest) = unsafe { input.split_at_unchecked(len) };
48    *input = rest;
49    dst
50}
51
52/// Implementation of [`Reader`] over a slice that does not perform any bounds checks.
53///
54/// This implementation inherits the lifetime of the underlying slice, and can be used
55/// for zero-copy [`Reader`] implementations.
56pub struct SliceUnchecked<'a, T> {
57    buf: &'a [T],
58}
59
60impl<'a, T> SliceUnchecked<'a, T> {
61    /// Create a new [`SliceUnchecked`] from the given slice.
62    ///
63    /// # Safety
64    ///
65    /// [`SliceUnchecked`]'s implementation of [`Reader`] will not perform any
66    /// bounds checks on the slice. It is up to the caller to ensure that any
67    /// [`Reader`] operations performed are within the bounds of the slice.
68    pub const unsafe fn new(buf: &'a [T]) -> Self {
69        Self { buf }
70    }
71}
72
73unsafe impl<'a> Reader<'a> for SliceUnchecked<'a, u8> {
74    const BORROW_KINDS: u8 = BorrowKind::Backing.mask() | BorrowKind::CallSite.mask();
75
76    #[inline]
77    fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()> {
78        // SAFETY: by constructing `SliceUnchecked`, caller guarantees
79        // they will read within the bounds of the slice.
80        let chunk = unsafe { advance_slice_unchecked(&mut self.buf, dst.len()) };
81        // SAFETY:
82        // -  Given the previous assumption that the caller guarantees the underlying
83        //    slice in bounds for the next `dst.len()` bytes, we assume that `chunk` is a valid,
84        //    in bounds, `dst.len()` bytes slice.
85        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap with the internal buffer.
86        unsafe { copy_nonoverlapping(chunk.as_ptr(), dst.as_mut_ptr(), dst.len()) };
87        Ok(())
88    }
89
90    #[inline]
91    fn copy_into_uninit_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
92        // SAFETY: by constructing `SliceUnchecked`, caller guarantees
93        // they will read within the bounds of the slice.
94        let chunk = unsafe { advance_slice_unchecked(&mut self.buf, dst.len()) };
95        // SAFETY:
96        // -  Given the previous assumption that the caller guarantees the underlying
97        //    slice in bounds for the next `dst.len()` bytes, we assume that `chunk` is a valid,
98        //    in bounds, `dst.len()` bytes slice.
99        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap with the internal buffer.
100        unsafe { copy_nonoverlapping(chunk.as_ptr(), dst.as_mut_ptr().cast::<u8>(), dst.len()) };
101        Ok(())
102    }
103
104    #[inline(always)]
105    fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
106        // SAFETY: by constructing `SliceUnchecked`, caller guarantees
107        // they will read within the bounds of the slice.
108        let chunk = unsafe { advance_slice_unchecked(&mut self.buf, N) };
109        // SAFETY: given the previous assumption that the caller guarantees the underlying
110        // slice in bounds for the next `N` bytes, we assume that `chunk` is a valid
111        // `&[u8; N]` slice.
112        Ok(unsafe { *(chunk.as_ptr().cast::<[u8; N]>()) })
113    }
114
115    #[inline]
116    fn take_borrowed(&mut self, len: usize) -> ReadResult<&'a [u8]> {
117        // SAFETY: by constructing `SliceUnchecked`, caller guarantees
118        // they will read within the bounds of the slice.
119        let chunk = unsafe { advance_slice_unchecked(&mut self.buf, len) };
120        Ok(chunk)
121    }
122
123    #[inline]
124    fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
125        self.take_borrowed(len)
126    }
127}
128
129/// Implementation of [`Reader`] and [`Writer`] over a slice that does not perform any bounds checks.
130///
131/// This implementation inherits the lifetime of the underlying slice, and can be used
132/// for zero-copy [`Reader`] implementations.
133pub struct SliceMutUnchecked<'a, T> {
134    buf: &'a mut [T],
135}
136
137#[cfg(test)]
138impl<T> core::ops::Deref for SliceMutUnchecked<'_, T> {
139    type Target = [T];
140
141    fn deref(&self) -> &Self::Target {
142        self.buf
143    }
144}
145
146impl<'a, T> SliceMutUnchecked<'a, T> {
147    /// Create a new [`SliceMutUnchecked`] from the given slice.
148    ///
149    /// # Safety
150    ///
151    /// [`SliceMutUnchecked`]'s implementation of [`Reader`] and [`Writer`] will
152    /// not perform any bounds checks on the slice. It is up to the caller to
153    /// ensure that any [`Reader`] or [`Writer`] operations performed are within
154    /// the bounds of the slice.
155    ///
156    /// ## Reading
157    ///
158    /// - The total number of bytes accessed/consumed must be within
159    ///   the bounds of the slice.
160    ///
161    /// ## Writing
162    ///
163    /// - All writes performed must stay within the bounds of the slice.
164    /// - It is permitted to overwrite the same bytes multiple times.
165    pub const unsafe fn new(buf: &'a mut [T]) -> Self {
166        Self { buf }
167    }
168}
169
170unsafe impl<'a> Reader<'a> for SliceMutUnchecked<'a, u8> {
171    const BORROW_KINDS: u8 =
172        BorrowKind::Backing.mask() | BorrowKind::BackingMut.mask() | BorrowKind::CallSite.mask();
173
174    #[inline]
175    fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()> {
176        // SAFETY: by constructing `SliceMutUnchecked`, caller guarantees
177        // they will read within the bounds of the slice.
178        let chunk = unsafe { advance_slice_mut_unchecked(&mut self.buf, dst.len()) };
179        // SAFETY:
180        // -  Given the previous assumption that the caller guarantees the underlying
181        //    slice in bounds for the next `dst.len()` bytes, we assume that `chunk` is a valid,
182        //    in bounds, `dst.len()` bytes slice.
183        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap with the internal buffer.
184        unsafe { copy_nonoverlapping(chunk.as_ptr(), dst.as_mut_ptr(), dst.len()) };
185        Ok(())
186    }
187
188    #[inline]
189    fn copy_into_uninit_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
190        // SAFETY: by constructing `SliceMutUnchecked`, caller guarantees
191        // they will read within the bounds of the slice.
192        let chunk = unsafe { advance_slice_mut_unchecked(&mut self.buf, dst.len()) };
193        // SAFETY:
194        // -  Given the previous assumption that the caller guarantees the underlying
195        //    slice in bounds for the next `dst.len()` bytes, we assume that `chunk` is a valid,
196        //    in bounds, `dst.len()` bytes slice.
197        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap with the internal buffer.
198        unsafe { copy_nonoverlapping(chunk.as_ptr(), dst.as_mut_ptr().cast::<u8>(), dst.len()) };
199        Ok(())
200    }
201
202    #[inline(always)]
203    fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
204        // SAFETY: by constructing `SliceMutUnchecked`, caller guarantees
205        // they will read within the bounds of the slice.
206        let chunk = unsafe { advance_slice_mut_unchecked(&mut self.buf, N) };
207        // SAFETY: given the previous assumption that the caller guarantees the underlying
208        // slice in bounds for the next `N` bytes, we assume that `chunk` is a valid
209        // `&[u8; N]` slice.
210        Ok(unsafe { *(chunk.as_ptr().cast::<[u8; N]>()) })
211    }
212
213    #[inline]
214    fn take_borrowed_mut(&mut self, len: usize) -> ReadResult<&'a mut [u8]> {
215        // SAFETY: by constructing `SliceMutUnchecked`, caller guarantees
216        // they will read within the bounds of the slice.
217        Ok(unsafe { advance_slice_mut_unchecked(&mut self.buf, len) })
218    }
219
220    #[inline]
221    fn take_borrowed(&mut self, len: usize) -> ReadResult<&'a [u8]> {
222        self.take_borrowed_mut(len).map(|s| &*s)
223    }
224
225    #[inline]
226    fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
227        self.take_borrowed(len)
228    }
229}
230
231/// Implementation of [`Reader`] over a slice that does not perform any bounds checks.
232///
233/// This implementation inherits the lifetime of its lexical scope, and can be used
234/// for non-borrowing [`Reader`] implementations.
235pub struct SliceScopedUnchecked<'a, 'b, T> {
236    inner: SliceUnchecked<'b, T>,
237    _marker: PhantomData<&'a [T]>,
238}
239
240impl<'b, T> SliceScopedUnchecked<'_, 'b, T> {
241    /// Create a new [`SliceScopedUnchecked`] from the given slice.
242    ///
243    /// # Safety
244    ///
245    /// [`SliceScopedUnchecked`]'s implementation of [`Reader`] will not perform any
246    /// bounds checks on the slice. It is up to the caller to ensure that any
247    /// [`Reader`] operations performed are within the bounds of the slice.
248    #[inline(always)]
249    pub const unsafe fn new(buf: &'b [T]) -> Self {
250        Self {
251            inner: unsafe { SliceUnchecked::new(buf) },
252            _marker: PhantomData,
253        }
254    }
255}
256
257unsafe impl<'a> Reader<'a> for SliceScopedUnchecked<'a, '_, u8> {
258    const BORROW_KINDS: u8 = BorrowKind::CallSite.mask();
259
260    #[inline(always)]
261    fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()> {
262        self.inner.copy_into_slice(dst)
263    }
264
265    #[inline(always)]
266    fn copy_into_uninit_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
267        self.inner.copy_into_uninit_slice(dst)
268    }
269
270    #[inline(always)]
271    fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
272        self.inner.take_array()
273    }
274
275    #[inline(always)]
276    fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
277        self.inner.take_scoped(len)
278    }
279}
280
281unsafe impl<'a> Reader<'a> for &'a [u8] {
282    const BORROW_KINDS: u8 = BorrowKind::Backing.mask() | BorrowKind::CallSite.mask();
283
284    #[inline]
285    fn take_borrowed(&mut self, len: usize) -> ReadResult<&'a [u8]> {
286        let Some(src) = advance_slice_checked(self, len) else {
287            return Err(read_size_limit(len));
288        };
289        Ok(src)
290    }
291
292    #[inline(always)]
293    fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
294        self.take_borrowed(len)
295    }
296
297    #[inline]
298    fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()> {
299        let Some(src) = advance_slice_checked(self, dst.len()) else {
300            return Err(read_size_limit(dst.len()));
301        };
302        // SAFETY:
303        // - `advance_slice_checked` guarantees that `src` is exactly `dst.len()` bytes.
304        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap
305        //   with the internal buffer.
306        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), dst.len()) };
307        Ok(())
308    }
309
310    #[inline]
311    fn copy_into_uninit_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
312        let Some(src) = advance_slice_checked(self, dst.len()) else {
313            return Err(read_size_limit(dst.len()));
314        };
315        // SAFETY:
316        // - `advance_slice_checked` guarantees that `src` is exactly `dst.len()` bytes.
317        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap
318        //   with the internal buffer.
319        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast::<u8>(), dst.len()) };
320        Ok(())
321    }
322
323    #[inline(always)]
324    fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
325        let Some((src, rest)) = self.split_first_chunk() else {
326            return Err(read_size_limit(N));
327        };
328        *self = rest;
329        Ok(*src)
330    }
331
332    #[inline(always)]
333    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> ReadResult<impl Reader<'a>> {
334        let Some(window) = advance_slice_checked(self, n_bytes) else {
335            return Err(read_size_limit(n_bytes));
336        };
337        // SAFETY: by calling `as_trusted_for`, caller guarantees they
338        // will will not read beyond the bounds of the slice, `n_bytes`.
339        Ok(unsafe { SliceUnchecked::new(window) })
340    }
341}
342
343unsafe impl<'a> Reader<'a> for &'a mut [u8] {
344    const BORROW_KINDS: u8 =
345        BorrowKind::Backing.mask() | BorrowKind::BackingMut.mask() | BorrowKind::CallSite.mask();
346
347    #[inline(always)]
348    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> ReadResult<impl Reader<'a>> {
349        let Some(window) = advance_slice_mut_checked(self, n_bytes) else {
350            return Err(read_size_limit(n_bytes));
351        };
352        // SAFETY: by calling `as_trusted_for`, caller guarantees they
353        // will will not read beyond the bounds of the slice, `n_bytes`.
354        Ok(unsafe { SliceMutUnchecked::new(window) })
355    }
356
357    #[inline]
358    fn take_borrowed_mut(&mut self, len: usize) -> ReadResult<&'a mut [u8]> {
359        let Some(src) = advance_slice_mut_checked(self, len) else {
360            return Err(read_size_limit(len));
361        };
362        Ok(src)
363    }
364
365    #[inline]
366    fn take_borrowed(&mut self, len: usize) -> ReadResult<&'a [u8]> {
367        self.take_borrowed_mut(len).map(|s| &*s)
368    }
369
370    #[inline]
371    fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
372        self.take_borrowed(len)
373    }
374
375    #[inline]
376    fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()> {
377        let src = self.take_borrowed(dst.len())?;
378        // SAFETY:
379        // - `take_borrowed` guarantees that `src` is exactly `dst.len()` bytes.
380        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap with the internal buffer.
381        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), dst.len()) }
382        Ok(())
383    }
384
385    #[inline]
386    fn copy_into_uninit_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
387        let src = self.take_borrowed(dst.len())?;
388        // SAFETY:
389        // - `take_borrowed` guarantees that `src` is exactly `dst.len()` bytes.
390        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap with the internal buffer.
391        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast::<u8>(), dst.len()) }
392        Ok(())
393    }
394
395    #[inline(always)]
396    fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
397        let Some((src, rest)) = mem::take(self).split_first_chunk_mut() else {
398            return Err(read_size_limit(N));
399        };
400        *self = rest;
401        Ok(*src)
402    }
403}
404
405impl Writer for SliceMutUnchecked<'_, u8> {
406    #[inline(always)]
407    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
408        // SAFETY: by constructing `SliceMutUnchecked`, caller guarantees
409        // they will write within the bounds of the slice.
410        let dst = unsafe { advance_slice_mut_unchecked(&mut self.buf, src.len()) };
411        // SAFETY:
412        // -  Given the previous assumption that the caller guarantees the underlying
413        //    slice in bounds for the next `src.len()` bytes, we assume that `dst` is a valid,
414        //    in bounds, `src.len()` bytes slice.
415        // - Given Rust's aliasing rules, we can assume that `src` does not overlap with the internal buffer.
416        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
417        Ok(())
418    }
419}
420
421impl Writer for SliceMutUnchecked<'_, MaybeUninit<u8>> {
422    #[inline(always)]
423    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
424        // SAFETY: by constructing `SliceMutUnchecked`, caller guarantees
425        // they will write within the bounds of the slice.
426        let dst = unsafe { advance_slice_mut_unchecked(&mut self.buf, src.len()) };
427        // SAFETY:
428        // -  Given the previous assumption that the caller guarantees the underlying
429        //    slice in bounds for the next `src.len()` bytes, we assume that `dst` is a valid,
430        //    in bounds, `src.len()` bytes slice.
431        // - Given Rust's aliasing rules, we can assume that `src` does not overlap with the internal buffer.
432        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
433        Ok(())
434    }
435}
436
437impl Writer for &mut [MaybeUninit<u8>] {
438    #[inline(always)]
439    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
440        let Some(window) = advance_slice_mut_checked(self, n_bytes) else {
441            return Err(write_size_limit(n_bytes));
442        };
443        // SAFETY: by calling `as_trusted_for`, caller guarantees they
444        // will fully initialize `n_bytes` of memory and will not write
445        // beyond the bounds of the slice.
446        Ok(unsafe { SliceMutUnchecked::new(window) })
447    }
448
449    #[inline(always)]
450    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
451        let Some(dst) = advance_slice_mut_checked(self, src.len()) else {
452            return Err(write_size_limit(src.len()));
453        };
454
455        // SAFETY: `advance_slice_mut_checked` guarantees that `dst` is exactly `src.len()` bytes.
456        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
457        Ok(())
458    }
459}
460
461impl Writer for &mut [u8] {
462    #[inline(always)]
463    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
464        let Some(window) = advance_slice_mut_checked(self, n_bytes) else {
465            return Err(write_size_limit(n_bytes));
466        };
467        // SAFETY: by calling `as_trusted_for`, caller guarantees they
468        // will fully initialize `n_bytes` of memory and will not write
469        // beyond the bounds of the slice.
470        Ok(unsafe { SliceMutUnchecked::new(window) })
471    }
472
473    #[inline]
474    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
475        let Some(dst) = advance_slice_mut_checked(self, src.len()) else {
476            return Err(write_size_limit(src.len()));
477        };
478
479        // SAFETY:
480        // - `advance_slice_mut_checked` guarantees that `dst` is exactly `src.len()` bytes.
481        // - Given Rust's aliasing rules, we can assume that `src` does not overlap
482        //   with the internal buffer.
483        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
484        Ok(())
485    }
486}
487
488#[cfg(all(test, feature = "alloc"))]
489mod tests {
490    #![allow(clippy::arithmetic_side_effects)]
491    use {super::*, crate::proptest_config::proptest_cfg, alloc::vec::Vec, proptest::prelude::*};
492
493    /// Execute the given block with supported readers.
494    macro_rules! with_readers {
495        ($bytes:expr, |$reader:ident| $body:block) => {{
496            {
497                let mut $reader = $bytes.as_slice();
498                $body
499            }
500            {
501                let mut $reader = unsafe { SliceUnchecked::new($bytes) };
502                $body
503            }
504            {
505                let mut $reader = Cursor::new($bytes);
506                $body
507            }
508            #[cfg(feature = "std")]
509            {
510                let mut $reader = std::io::Cursor::new($bytes);
511                $body
512            }
513        }};
514    }
515
516    /// Execute the given block with readers that will bounds check (and thus not panic).
517    macro_rules! with_untrusted_readers {
518        ($bytes:expr, |$reader:ident| $body:block) => {{
519            {
520                let mut $reader = $bytes.as_slice();
521                $body
522            }
523            {
524                let mut $reader = Cursor::new($bytes);
525                $body
526            }
527            #[cfg(feature = "std")]
528            {
529                let mut $reader = std::io::Cursor::new($bytes);
530                $body
531            }
532        }};
533    }
534
535    /// Execute the given block with slice reference writer and trusted slice writer for the given buffer.
536    macro_rules! with_writers {
537        ($buffer:expr, |$writer:ident| $body:block) => {{
538            {
539                let mut $writer = $buffer.spare_capacity_mut();
540                $body
541                $buffer.clear();
542            }
543            {
544                let mut $writer = unsafe { SliceMutUnchecked::new($buffer.spare_capacity_mut()) };
545                $body
546                $buffer.clear();
547            }
548            {
549                let _capacity = $buffer.capacity();
550                $buffer.resize(_capacity, 0);
551                let mut $writer = $buffer.as_mut_slice();
552                $body
553                $buffer.clear();
554            }
555        }};
556    }
557
558    // Execute the given block with slice writer of the given preallocated buffer.
559    macro_rules! with_known_len_writers {
560        ($buffer:expr, |$writer:ident| $body_write:block, $body_check:expr) => {{
561            let capacity = $buffer.capacity();
562            {
563                $buffer.resize(capacity, 0);
564                $buffer.fill(0);
565                let mut $writer = $buffer.as_mut_slice();
566                $body_write
567                $body_check;
568                $buffer.clear();
569            }
570            {
571                $buffer.fill(0);
572                $buffer.clear();
573                let mut $writer = $buffer.spare_capacity_mut();
574                $body_write
575                unsafe { $buffer.set_len(capacity) }
576                $body_check;
577            }
578        }};
579    }
580
581    proptest! {
582        #![proptest_config(proptest_cfg())]
583
584        #[test]
585        fn test_reader_copy_into_slice(bytes in any::<Vec<u8>>()) {
586            let len = bytes.len();
587            with_readers!(&bytes, |reader| {
588                let mut dst = alloc::vec![0; len];
589                let half = len / 2;
590                reader.copy_into_slice(&mut dst[..half]).unwrap();
591                // SAFETY: the returned reader is used to read exactly the requested number of bytes.
592                unsafe { Reader::as_trusted_for(&mut reader, len - half) }
593                    .unwrap()
594                    .copy_into_slice(&mut dst[half..])
595                    .unwrap();
596                prop_assert_eq!(&dst, &bytes);
597            });
598        }
599
600        #[test]
601        fn test_reader_copy_into_uninit_slice(bytes in any::<Vec<u8>>()) {
602            let len = bytes.len();
603            with_readers!(&bytes, |reader| {
604                let mut dst = Vec::with_capacity(len);
605                let half = len / 2;
606                let spare = dst.spare_capacity_mut();
607                reader.copy_into_uninit_slice(&mut spare[..half]).unwrap();
608                // SAFETY: the returned reader is used to read exactly the requested number of bytes.
609                unsafe { Reader::as_trusted_for(&mut reader, len - half) }
610                    .unwrap()
611                    .copy_into_uninit_slice(&mut spare[half..])
612                    .unwrap();
613                // SAFETY: both copy operations succeeded and initialized every byte in the allocation.
614                unsafe { dst.set_len(len) };
615                prop_assert_eq!(&dst, &bytes);
616            });
617        }
618
619        #[test]
620        fn test_reader_take_scoped(bytes in any::<Vec<u8>>()) {
621            with_readers!(&bytes, |reader| {
622                let read = reader.take_scoped(bytes.len()).unwrap();
623                prop_assert_eq!(&read, &bytes);
624            });
625        }
626
627        #[test]
628        fn reader_take_scoped_input_too_large(bytes in any::<Vec<u8>>()) {
629            with_untrusted_readers!(&bytes, |reader| {
630                prop_assert!(matches!(reader.take_scoped(bytes.len() + 1), Err(ReadError::ReadSizeLimit(x)) if x == bytes.len() + 1));
631            });
632        }
633
634        #[test]
635        fn test_reader_copy_into_slice_input_too_large(bytes in any::<Vec<u8>>()) {
636            let requested = bytes.len() + 1;
637            with_untrusted_readers!(&bytes, |reader| {
638                let mut dst = alloc::vec![0; requested];
639                prop_assert!(matches!(reader.copy_into_slice(&mut dst), Err(ReadError::ReadSizeLimit(x)) if x == requested));
640            });
641        }
642
643        #[test]
644        fn test_reader_copy_into_uninit_slice_input_too_large(bytes in any::<Vec<u8>>()) {
645            let requested = bytes.len() + 1;
646            with_untrusted_readers!(&bytes, |reader| {
647                let mut dst = Vec::with_capacity(requested);
648                prop_assert!(matches!(reader.copy_into_uninit_slice(dst.spare_capacity_mut()), Err(ReadError::ReadSizeLimit(x)) if x == requested));
649            });
650        }
651
652        #[test]
653        fn test_reader_copy_into_t(ints in proptest::collection::vec(any::<u64>(), 0..=100)) {
654            let bytes = ints.iter().flat_map(|int| int.to_le_bytes()).collect::<Vec<u8>>();
655            with_readers!(&bytes, |reader| {
656                for int in &ints {
657                    let mut val = MaybeUninit::<u64>::uninit();
658                    unsafe { reader.copy_into_t(&mut val).unwrap() };
659                    unsafe { prop_assert_eq!(val.assume_init(), *int) };
660                }
661            });
662        }
663
664        #[test]
665        fn test_reader_copy_into_slice_t(ints in proptest::collection::vec(any::<u64>(), 0..=100)) {
666            let bytes = ints.iter().flat_map(|int| int.to_le_bytes()).collect::<Vec<u8>>();
667            with_readers!(&bytes, |reader| {
668                let mut vals: Vec<u64> = Vec::with_capacity(ints.len());
669                let dst = vals.spare_capacity_mut();
670                unsafe { reader.copy_into_slice_t(dst).unwrap() };
671                unsafe { vals.set_len(ints.len()) };
672                prop_assert_eq!(&vals, &ints);
673            });
674        }
675
676        #[test]
677        fn test_writer_write(bytes in any::<Vec<u8>>()) {
678            let capacity = bytes.len();
679            let mut buffer = Vec::with_capacity(capacity);
680            with_writers!(&mut buffer, |writer| {
681                writer.write(&bytes).unwrap();
682                let written = capacity - writer.len();
683                unsafe { buffer.set_len(written) };
684                prop_assert_eq!(&buffer, &bytes);
685            });
686
687            with_known_len_writers!(&mut buffer, |writer| {
688                writer.write(&bytes).unwrap();
689            }, prop_assert_eq!(&buffer, &bytes));
690        }
691
692        #[test]
693        fn test_writer_write_input_too_large(bytes in proptest::collection::vec(any::<u8>(), 1..=100)) {
694            let mut buffer = Vec::with_capacity(bytes.len() - 1);
695            let mut writer = buffer.spare_capacity_mut();
696            prop_assert!(matches!(writer.write(&bytes), Err(WriteError::WriteSizeLimit(x)) if x == bytes.len()));
697        }
698
699        #[test]
700        fn test_writer_write_t(int in any::<u64>()) {
701            let capacity = 8;
702            let mut buffer = Vec::with_capacity(capacity);
703            with_writers!(&mut buffer, |writer| {
704                unsafe { writer.write_t(&int).unwrap() };
705                let written = capacity - writer.len();
706                unsafe { buffer.set_len(written) };
707                prop_assert_eq!(&buffer, &int.to_le_bytes());
708            });
709
710            with_known_len_writers!(&mut buffer, |writer| {
711                unsafe { writer.write_t(&int).unwrap() };
712            }, prop_assert_eq!(&buffer, &int.to_le_bytes()));
713        }
714
715        #[test]
716        fn test_writer_write_slice_t(ints in proptest::collection::vec(any::<u64>(), 0..=100)) {
717            let bytes = ints.iter().flat_map(|int| int.to_le_bytes()).collect::<Vec<u8>>();
718            let capacity = bytes.len();
719            let mut buffer = Vec::with_capacity(capacity);
720            with_writers!(&mut buffer, |writer| {
721                unsafe { writer.write_slice_t(&ints).unwrap() };
722                let written = capacity - writer.len();
723                unsafe { buffer.set_len(written) };
724                prop_assert_eq!(&buffer, &bytes);
725            });
726
727            with_known_len_writers!(&mut buffer, |writer| {
728                unsafe { writer.write_slice_t(&ints).unwrap() };
729            }, prop_assert_eq!(&buffer, &bytes));
730        }
731    }
732}