Skip to main content

wincode/io/
cursor.rs

1#[cfg(feature = "alloc")]
2use alloc::vec::Vec;
3use {
4    super::*,
5    core::ptr::copy_nonoverlapping,
6    slice::{SliceMutUnchecked, SliceScopedUnchecked},
7};
8
9/// `Cursor` wraps an in-memory buffer, providing [`Reader`] and [`Writer`] functionality
10/// for types implementing <code>[AsRef]<\[u8]></code>.
11///
12/// This can be especially useful for wrapping [`Reader`]s and [`Writer`]s that are consumed by
13/// reading or writing like `&[u8]` or `&mut [MaybeUninit<u8>]`, making them reusable.
14///
15/// # Examples
16///
17/// Using `Cursor` to write to a `MaybeUninit<[u8; N]>`.
18///
19/// ```
20/// # use rand::random;
21/// # use core::mem::MaybeUninit;
22/// use wincode::io::{Cursor, Reader, Writer};
23///
24/// fn rand_bytes() -> [u8; 8] {
25///     random::<u64>().to_le_bytes()
26/// }
27///
28/// let mut data = MaybeUninit::<[u8; 8]>::uninit();
29///
30/// let mut cursor = Cursor::new(&mut data);
31/// let bytes = rand_bytes();
32/// cursor.write(&bytes).unwrap();
33/// assert_eq!(unsafe { data.assume_init() }, bytes);
34///
35/// // We can write over the same buffer multiple times with a new Cursor.
36/// let mut cursor = Cursor::new(&mut data);
37/// let bytes = rand_bytes();
38/// cursor.write(&bytes).unwrap();
39/// assert_eq!(unsafe { data.assume_init() }, bytes);
40/// ```
41///
42/// Using `Cursor` to write to a `Vec`'s spare capacity.
43///
44/// ```
45/// # #[cfg(feature = "alloc")] {
46/// # use rand::random;
47/// use wincode::io::{Cursor, Reader, Writer};
48///
49/// # fn rand_bytes() -> [u8; 8] {
50/// #     random::<u64>().to_le_bytes()
51/// # }
52/// let mut data = Vec::with_capacity(8);
53///
54/// let mut cursor = Cursor::new(&mut data);
55/// let bytes = rand_bytes();
56/// cursor.write(&bytes).unwrap();
57/// assert_eq!(data, bytes);
58///
59/// // We can write over the same buffer multiple times with a new Cursor.
60/// let mut cursor = Cursor::new(&mut data);
61/// let bytes = rand_bytes();
62/// cursor.write(&bytes).unwrap();
63/// assert_eq!(data, bytes);
64/// # }
65/// ```
66pub struct Cursor<T> {
67    inner: T,
68    pos: usize,
69}
70
71impl<T> Cursor<T> {
72    pub const fn new(inner: T) -> Self {
73        Self { inner, pos: 0 }
74    }
75
76    /// Creates a new cursor at the given position.
77    pub const fn new_at(inner: T, pos: usize) -> Self {
78        Self { inner, pos }
79    }
80
81    /// Sets the position of the cursor.
82    pub const fn set_position(&mut self, pos: usize) {
83        self.pos = pos;
84    }
85
86    /// Consumes the cursor and returns the inner value.
87    pub fn into_inner(self) -> T {
88        self.inner
89    }
90
91    /// Returns the current position of the cursor.
92    pub const fn position(&self) -> usize {
93        self.pos
94    }
95}
96
97#[inline(always)]
98#[expect(clippy::arithmetic_side_effects)]
99fn advance_slice_checked<'a, T>(buf: &'a [T], pos: &mut usize, len: usize) -> Option<&'a [T]> {
100    let buf_len = buf.len();
101    let buf = buf[(*pos).min(buf_len)..].get(..len)?;
102    *pos += len;
103    Some(buf)
104}
105
106#[inline(always)]
107#[expect(clippy::arithmetic_side_effects)]
108fn advance_slice_mut_checked<'a, T>(
109    buf: &'a mut [T],
110    pos: &mut usize,
111    len: usize,
112) -> Option<&'a mut [T]> {
113    let buf_len = buf.len();
114    let buf = buf[(*pos).min(buf_len)..].get_mut(..len)?;
115    *pos += len;
116    Some(buf)
117}
118
119impl<T> Cursor<T>
120where
121    T: AsRef<[u8]>,
122{
123    /// Split the cursor at `len` and consume the left slice.
124    #[inline(always)]
125    fn advance_slice_checked(&mut self, len: usize) -> ReadResult<&[u8]> {
126        let Some(slice) = advance_slice_checked(self.inner.as_ref(), &mut self.pos, len) else {
127            return Err(read_size_limit(len));
128        };
129        Ok(slice)
130    }
131}
132
133impl<'a, T> Reader<'a> for Cursor<T>
134where
135    T: AsRef<[u8]>,
136{
137    const BORROW_KINDS: u8 = BorrowKind::CallSite.mask();
138
139    #[inline]
140    fn copy_into_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
141        let src = self.advance_slice_checked(dst.len())?;
142        // SAFETY:
143        // - `advance_slice_checked` guarantees that `src` is exactly `dst.len()` bytes.
144        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap
145        //   with the internal buffer.
146        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), dst.len()) }
147        Ok(())
148    }
149
150    #[inline(always)]
151    fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
152        let src = self.advance_slice_checked(N)?;
153        // SAFETY: advance_slice_checked guarantees that `src` is exactly `N` bytes.
154        Ok(unsafe { *(src.as_ptr().cast::<[u8; N]>()) })
155    }
156
157    #[inline]
158    fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
159        self.advance_slice_checked(len)
160    }
161
162    #[inline(always)]
163    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> ReadResult<impl Reader<'a>> {
164        let window = self.advance_slice_checked(n_bytes)?;
165        // SAFETY: by calling `as_trusted_for`, caller guarantees they
166        // will will not read beyond the bounds of the slice, `n_bytes`.
167        Ok(unsafe { SliceScopedUnchecked::new(window) })
168    }
169}
170
171impl<T> Cursor<&mut [T]> {
172    #[inline(always)]
173    fn advance_slice_mut_checked(&mut self, len: usize) -> WriteResult<&mut [T]> {
174        let Some(slice) = advance_slice_mut_checked(self.inner, &mut self.pos, len) else {
175            return Err(write_size_limit(len));
176        };
177        Ok(slice)
178    }
179}
180
181impl Writer for Cursor<&mut [MaybeUninit<u8>]> {
182    #[inline]
183    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
184        let dst = self.advance_slice_mut_checked(src.len())?;
185        // SAFETY:
186        // - `advance_slice_mut_checked` guarantees that `dst` is exactly `src.len()` bytes.
187        // - Given Rust's aliasing rules, we can assume that `src` does not overlap
188        //   with the internal buffer.
189        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
190
191        Ok(())
192    }
193
194    #[inline(always)]
195    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
196        let window = self.advance_slice_mut_checked(n_bytes)?;
197        // SAFETY: by calling `as_trusted_for`, caller guarantees they
198        // will fully initialize `n_bytes` of memory and will not write
199        // beyond the bounds of the slice.
200        Ok(unsafe { SliceMutUnchecked::new(window) })
201    }
202}
203
204impl Writer for Cursor<&mut [u8]> {
205    #[inline]
206    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
207        let dst = self.advance_slice_mut_checked(src.len())?;
208        // SAFETY:
209        // - `advance_slice_mut_checked` guarantees that `dst` is exactly `src.len()` bytes.
210        // - Given Rust's aliasing rules, we can assume that `src` does not overlap
211        //   with the internal buffer.
212        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
213        Ok(())
214    }
215
216    #[inline(always)]
217    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
218        let window = self.advance_slice_mut_checked(n_bytes)?;
219        // SAFETY: by calling `as_trusted_for`, caller guarantees they
220        // will fully initialize `n_bytes` of memory and will not write
221        // beyond the bounds of the slice.
222        Ok(unsafe { SliceMutUnchecked::new(window) })
223    }
224}
225
226impl<const N: usize> Cursor<&mut MaybeUninit<[u8; N]>> {
227    #[inline(always)]
228    fn advance_slice_mut_checked(&mut self, len: usize) -> WriteResult<&mut [MaybeUninit<u8>]> {
229        let Some(slice) = advance_slice_mut_checked(transpose(self.inner), &mut self.pos, len)
230        else {
231            return Err(write_size_limit(len));
232        };
233        Ok(slice)
234    }
235}
236
237impl<const N: usize> Writer for Cursor<&mut MaybeUninit<[u8; N]>> {
238    #[inline]
239    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
240        let dst = self.advance_slice_mut_checked(src.len())?;
241        // SAFETY:
242        // - `advance_slice_mut_checked` guarantees that `dst` is exactly `src.len()` bytes.
243        // - Given Rust's aliasing rules, we can assume that `src` does not overlap
244        //   with the internal buffer.
245        unsafe { ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
246
247        Ok(())
248    }
249
250    #[inline(always)]
251    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
252        let window = self.advance_slice_mut_checked(n_bytes)?;
253        // SAFETY: by calling `as_trusted_for`, caller guarantees they
254        // will fully initialize `n_bytes` of memory and will not write
255        // beyond the bounds of the slice.
256        Ok(unsafe { SliceMutUnchecked::new(window) })
257    }
258}
259
260/// Helper functions for writing to `Cursor<&mut Vec<u8>>` and `Cursor<Vec<u8>>`.
261#[cfg(feature = "alloc")]
262mod vec {
263    use super::*;
264
265    /// Grow the vector if necessary to accommodate the given `needed` bytes.
266    ///
267    /// Note this differs from [`Vec::reserve`] in that it reserves relative to the cursor's
268    /// current position, rather than the initialized length of the vector. The `Cursor<Vec<u8>>`
269    /// implementation overwrites existing elements of the vector, so growing relative to length
270    /// would unnecessarily over-allocate memory.
271    ///
272    /// # Panics
273    ///
274    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
275    #[inline]
276    pub(super) fn maybe_grow(inner: &mut Vec<u8>, pos: usize, needed: usize) -> WriteResult<()> {
277        let Some(required) = pos.checked_add(needed) else {
278            return Err(write_size_limit(needed));
279        };
280        if required > inner.capacity() {
281            grow(inner, required);
282        }
283        #[cold]
284        fn grow(inner: &mut Vec<u8>, required: usize) {
285            // SAFETY: We just checked that `required > inner.capacity()` (which is greater than
286            // or equal to `inner.len()`), so this will not underflow.
287            let additional = unsafe { required.unchecked_sub(inner.len()) };
288            inner.reserve(additional);
289        }
290        Ok(())
291    }
292
293    /// Add `len` to the cursor's position and update the length of the vector if necessary.
294    ///
295    /// # SAFETY:
296    /// - Must be called after a successful write to the vector.
297    pub(super) unsafe fn add_len(inner: &mut Vec<u8>, pos: &mut usize, len: usize) {
298        // SAFETY: We just wrote `len` bytes to the vector, so `pos + len` is valid.
299        let next_pos = unsafe { pos.unchecked_add(len) };
300
301        // If pos exceeds the length of the vector, we just wrote to uninitialized capacity,
302        // which is now initialized.
303        if next_pos > inner.len() {
304            unsafe {
305                inner.set_len(next_pos);
306            }
307        }
308        *pos = next_pos;
309    }
310
311    /// Write `src` to the vector at the current position and advance the position by `src.len()`.
312    pub(super) fn write(inner: &mut Vec<u8>, pos: &mut usize, src: &[u8]) -> WriteResult<()> {
313        maybe_grow(inner, *pos, src.len())?;
314        // SAFETY: We just ensured at least `pos + src.len()` capacity is available.
315        unsafe { ptr::copy_nonoverlapping(src.as_ptr(), inner.as_mut_ptr().add(*pos), src.len()) };
316        // SAFETY: We just wrote `src.len()` bytes to the vector.
317        unsafe { add_len(inner, pos, src.len()) };
318        Ok(())
319    }
320
321    #[inline]
322    #[expect(clippy::arithmetic_side_effects)]
323    pub(super) unsafe fn as_trusted_for<'a>(
324        inner: &'a mut Vec<u8>,
325        pos: &'a mut usize,
326        n_bytes: usize,
327    ) -> WriteResult<impl Writer> {
328        maybe_grow(inner, *pos, n_bytes)?;
329        // SAFETY: `maybe_grow` ensures at least `pos + n_bytes` capacity is available.
330        let buf = unsafe {
331            from_raw_parts_mut(
332                inner.as_mut_ptr().add(*pos).cast::<MaybeUninit<u8>>(),
333                n_bytes,
334            )
335        };
336
337        *pos += n_bytes;
338        // SAFETY: by calling `as_trusted_for`, caller guarantees they
339        // will fully initialize `n_bytes` of memory and will not write
340        // beyond the bounds of the slice.
341        Ok(unsafe { SliceMutUnchecked::new(buf) })
342    }
343
344    #[inline]
345    pub(super) fn finish(inner: &mut Vec<u8>, pos: usize) {
346        if pos > inner.len() {
347            unsafe {
348                inner.set_len(pos);
349            }
350        }
351    }
352}
353
354/// Writer implementation for `&mut Vec<u8>` that overwrites the underlying vector's memory.
355/// The vector will grow as needed.
356///
357/// # Examples
358///
359/// Overwriting an existing vector.
360/// ```
361/// # #[cfg(feature = "alloc")] {
362/// # use wincode::io::{Cursor, Writer};
363/// let mut vec = vec![0; 3];
364/// let mut cursor = Cursor::new(&mut vec);
365/// let bytes = [1, 2, 3, 4];
366/// cursor.write(&bytes).unwrap();
367/// assert_eq!(&vec, &[1, 2, 3, 4]);
368/// # }
369/// ```
370///
371/// Growing a vector.
372/// ```
373/// # #[cfg(feature = "alloc")] {
374/// # use wincode::io::{Cursor, Writer};
375/// let mut vec = vec![];
376/// let mut cursor = Cursor::new(&mut vec);
377/// let bytes = [1, 2, 3];
378/// cursor.write(&bytes).unwrap();
379/// assert_eq!(&vec, &[1, 2, 3]);
380/// # }
381/// ```
382#[cfg(feature = "alloc")]
383impl Writer for Cursor<&mut Vec<u8>> {
384    #[inline]
385    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
386        vec::write(self.inner, &mut self.pos, src)
387    }
388
389    #[inline]
390    fn finish(&mut self) -> WriteResult<()> {
391        vec::finish(self.inner, self.pos);
392        Ok(())
393    }
394
395    #[inline(always)]
396    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
397        unsafe { vec::as_trusted_for(self.inner, &mut self.pos, n_bytes) }
398    }
399}
400
401/// Writer implementation for `Vec<u8>` that overwrites the underlying vector's memory.
402/// The vector will grow as needed.
403/// # Examples
404///
405/// Overwriting an existing vector.
406/// ```
407/// # #[cfg(feature = "alloc")] {
408/// # use wincode::io::{Cursor, Writer};
409/// let mut cursor = Cursor::new(vec![0; 3]);
410/// let bytes = [1, 2, 3, 4];
411/// cursor.write(&bytes).unwrap();
412/// assert_eq!(cursor.into_inner(), &[1, 2, 3, 4]);
413/// # }
414/// ```
415///
416/// Growing a vector.
417/// ```
418/// # #[cfg(feature = "alloc")] {
419/// # use wincode::io::{Cursor, Writer};
420/// let mut cursor = Cursor::new(vec![]);
421/// let bytes = [1, 2, 3];
422/// cursor.write(&bytes).unwrap();
423/// assert_eq!(cursor.into_inner(), &[1, 2, 3]);
424/// # }
425/// ```
426#[cfg(feature = "alloc")]
427impl Writer for Cursor<Vec<u8>> {
428    #[inline]
429    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
430        vec::write(&mut self.inner, &mut self.pos, src)
431    }
432
433    #[inline]
434    fn finish(&mut self) -> WriteResult<()> {
435        vec::finish(&mut self.inner, self.pos);
436        Ok(())
437    }
438
439    #[inline(always)]
440    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
441        unsafe { vec::as_trusted_for(&mut self.inner, &mut self.pos, n_bytes) }
442    }
443}
444
445#[cfg(all(test, feature = "alloc"))]
446mod tests {
447    #![allow(clippy::arithmetic_side_effects)]
448    use {super::*, crate::proptest_config::proptest_cfg, alloc::vec, proptest::prelude::*};
449
450    proptest! {
451        #![proptest_config(proptest_cfg())]
452
453        #[test]
454        fn cursor_read_no_panic_no_ub_check(bytes in any::<Vec<u8>>(), pos in any::<usize>()) {
455            let mut cursor = Cursor::new_at(&bytes, pos);
456
457            let mut dst = Vec::with_capacity(bytes.len());
458            let res = cursor.copy_into_slice(dst.spare_capacity_mut());
459            if pos > bytes.len() && !bytes.is_empty() {
460                prop_assert!(matches!(res, Err(ReadError::ReadSizeLimit(x)) if x == bytes.len()));
461            } else {
462                unsafe { dst.set_len(bytes.len()) };
463                prop_assert_eq!(&dst, &bytes[pos.min(bytes.len())..]);
464            }
465        }
466
467        #[test]
468        fn cursor_zero_len_ops_ok(bytes in any::<Vec<u8>>(), pos in any::<usize>()) {
469            let mut cursor = Cursor::new_at(&bytes, pos);
470            let start = cursor.position();
471
472            let mut buf: [MaybeUninit::<u8>; 0] = [];
473            cursor.copy_into_slice(&mut buf).unwrap();
474            prop_assert_eq!(cursor.position(), start);
475
476            unsafe { <Cursor<_> as Reader>::as_trusted_for(&mut cursor, 0) }.unwrap();
477            prop_assert_eq!(cursor.position(), start);
478        }
479
480        #[test]
481        fn cursor_as_trusted_for_remaining_advances_to_len(bytes in any::<Vec<u8>>(), pos in any::<usize>()) {
482            // Clamp pos to be within [0, len] so the request is valid.
483            let len = bytes.len();
484            let pos = if len == 0 { 0 } else { pos % (len + 1) };
485            let mut cursor = Cursor::new_at(&bytes, pos);
486            let remaining = len.saturating_sub(pos);
487
488            {
489                let _trusted = unsafe { <Cursor<_> as Reader>::as_trusted_for(&mut cursor, remaining) }.unwrap();
490            }
491
492            // After consuming the exact remaining, position should be exactly len.
493            prop_assert_eq!(cursor.position(), len);
494        }
495
496        #[test]
497        fn cursor_extremal_pos_max_zero_len_ok(bytes in any::<Vec<u8>>()) {
498            let mut cursor = Cursor::new_at(&bytes, usize::MAX);
499
500            // Zero-length ops still succeed and do not advance.
501            let mut buf: [MaybeUninit::<u8>; 0] = [];
502            let start = cursor.position();
503            prop_assert!(cursor.copy_into_slice(&mut buf).is_ok());
504            {
505                let _trusted = unsafe { <Cursor<_> as Reader>::as_trusted_for(&mut cursor, 0) }.unwrap();
506            }
507            prop_assert_eq!(cursor.position(), start);
508        }
509
510        #[test]
511        fn uninit_slice_write_no_panic_no_ub_check(bytes in any::<Vec<u8>>(), pos in any::<usize>()) {
512            let mut output: Vec<u8> = Vec::with_capacity(bytes.len());
513            let mut cursor = Cursor::new_at(output.spare_capacity_mut(), pos);
514            let res = cursor.write(&bytes);
515            if pos > bytes.len() && !bytes.is_empty() {
516                prop_assert!(matches!(res, Err(WriteError::WriteSizeLimit(x)) if x == bytes.len()));
517            } else if pos == 0 {
518                prop_assert_eq!(output, bytes);
519            }
520        }
521
522        #[test]
523        fn vec_write_no_panic_no_ub_check(bytes in any::<Vec<u8>>(), pos in any::<u16>()) {
524            let pos = pos as usize;
525            let mut output: Vec<u8> = Vec::new();
526            let mut cursor = Cursor::new_at(&mut output, pos);
527            // Vec impl grows, so it should be valid to write to any position within memory limits.
528            cursor.write(&bytes).unwrap();
529            prop_assert_eq!(&output[pos..], &bytes);
530        }
531
532        #[test]
533        fn cursor_write_vec_new(bytes in any::<Vec<u8>>()) {
534            let mut cursor = Cursor::new(Vec::new());
535            cursor.write(&bytes).unwrap();
536            prop_assert_eq!(&cursor.inner, &bytes);
537
538            let mut vec = Vec::with_capacity(bytes.len());
539            let mut cursor = Cursor::new(vec.spare_capacity_mut());
540            cursor.write(&bytes).unwrap();
541            unsafe { vec.set_len(bytes.len()) };
542            prop_assert_eq!(&vec, &bytes);
543        }
544
545        #[test]
546        fn cursor_write_existing_vec(bytes in any::<Vec<u8>>()) {
547            let mut cursor = Cursor::new(vec![0; bytes.len()]);
548            cursor.write(&bytes).unwrap();
549            prop_assert_eq!(&cursor.inner, &bytes);
550        }
551
552        #[test]
553        fn cursor_write_existing_grow_vec(bytes in any::<Vec<u8>>()) {
554            let mut cursor = Cursor::new(vec![0; bytes.len() / 2]);
555            cursor.write(&bytes).unwrap();
556            prop_assert_eq!(&cursor.inner, &bytes);
557        }
558
559        #[test]
560        fn cursor_write_partial_vec(bytes in any::<Vec<u8>>()) {
561            let mut cursor = Cursor::new(vec![1; bytes.len()]);
562            let half = bytes.len() - bytes.len() / 2;
563            cursor.write(&bytes[..half]).unwrap();
564            prop_assert_eq!(&cursor.inner[..half], &bytes[..half]);
565            // Remaining bytes are untouched
566            prop_assert_eq!(&cursor.inner[half..], &vec![1; bytes.len() - half]);
567            cursor.write(&bytes[half..]).unwrap();
568            prop_assert_eq!(&cursor.inner, &bytes);
569        }
570
571        #[test]
572        fn cursor_write_trusted_vec(bytes in any::<Vec<u8>>()) {
573            let mut cursor = Cursor::new(vec![1; bytes.len()]);
574            let half = bytes.len() - bytes.len() / 2;
575            cursor.write(&bytes[..half]).unwrap();
576            unsafe { <Cursor<_> as Writer>::as_trusted_for(&mut cursor, bytes.len() - half) }
577                .unwrap()
578                .write(&bytes[half..])
579                .unwrap();
580            cursor.finish().unwrap();
581            prop_assert_eq!(&cursor.inner, &bytes);
582        }
583
584        #[test]
585        fn cursor_write_trusted_grow_vec(bytes in any::<Vec<u8>>()) {
586            let mut cursor = Cursor::new(vec![1; bytes.len() / 2]);
587            let half = bytes.len() - bytes.len() / 2;
588            cursor.write(&bytes[..half]).unwrap();
589            unsafe { <Cursor<_> as Writer>::as_trusted_for(&mut cursor, bytes.len() - half) }
590                .unwrap()
591                .write(&bytes[half..])
592                .unwrap();
593            cursor.finish().unwrap();
594            prop_assert_eq!(&cursor.inner, &bytes);
595        }
596
597        #[test]
598        fn cursor_write_trusted_oversized_vec(bytes in any::<Vec<u8>>()) {
599            let mut cursor = Cursor::new(vec![1; bytes.len() * 2]);
600            let half = bytes.len() - bytes.len() / 2;
601            cursor.write(&bytes[..half]).unwrap();
602            unsafe { <Cursor<_> as Writer>::as_trusted_for(&mut cursor, bytes.len() - half) }
603                .unwrap()
604                .write(&bytes[half..])
605                .unwrap();
606            cursor.finish().unwrap();
607            prop_assert_eq!(&cursor.inner[..bytes.len()], &bytes);
608            // Remaining bytes are untouched
609            prop_assert_eq!(&cursor.inner[bytes.len()..], &vec![1; bytes.len()]);
610        }
611
612        #[cfg(feature = "derive")]
613        #[test]
614        fn cursor_read_items_with_inner_zero_copy(bytes in proptest::collection::vec(any::<u8>(), 64)) {
615            use crate::{config::DefaultConfig, SchemaRead};
616
617            // Test reader not supporting zero-copy, but used to read items that contain nested
618            // zero-copy content
619            #[derive(crate::SchemaRead)]
620            #[wincode(internal)]
621            struct NonZeroCopyWrapper {
622                zero_copy_content: [u8; 8],
623            }
624
625            let mut cursor = Cursor::new(&bytes);
626            let mut dst = MaybeUninit::uninit();
627            <[NonZeroCopyWrapper; 8] as SchemaRead<DefaultConfig>>::read(&mut cursor, &mut dst)
628                .unwrap();
629            let deserialized = unsafe { dst.assume_init() };
630            for (i, chunk) in bytes.chunks_exact(size_of::<NonZeroCopyWrapper>()).enumerate() {
631                prop_assert_eq!(&deserialized[i].zero_copy_content, chunk);
632            }
633        }
634    }
635}