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
133unsafe impl<'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 [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]
151    fn copy_into_uninit_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
152        let src = self.advance_slice_checked(dst.len())?;
153        // SAFETY:
154        // - `advance_slice_checked` guarantees that `src` is exactly `dst.len()` bytes.
155        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap
156        //   with the internal buffer.
157        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast::<u8>(), dst.len()) }
158        Ok(())
159    }
160
161    #[inline(always)]
162    fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
163        let src = self.advance_slice_checked(N)?;
164        // SAFETY: advance_slice_checked guarantees that `src` is exactly `N` bytes.
165        Ok(unsafe { *(src.as_ptr().cast::<[u8; N]>()) })
166    }
167
168    #[inline]
169    fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
170        self.advance_slice_checked(len)
171    }
172
173    #[inline(always)]
174    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> ReadResult<impl Reader<'a>> {
175        let window = self.advance_slice_checked(n_bytes)?;
176        // SAFETY: by calling `as_trusted_for`, caller guarantees they
177        // will will not read beyond the bounds of the slice, `n_bytes`.
178        Ok(unsafe { SliceScopedUnchecked::new(window) })
179    }
180}
181
182impl<T> Cursor<&mut [T]> {
183    #[inline(always)]
184    fn advance_slice_mut_checked(&mut self, len: usize) -> WriteResult<&mut [T]> {
185        let Some(slice) = advance_slice_mut_checked(self.inner, &mut self.pos, len) else {
186            return Err(write_size_limit(len));
187        };
188        Ok(slice)
189    }
190}
191
192impl Writer for Cursor<&mut [MaybeUninit<u8>]> {
193    #[inline]
194    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
195        let dst = self.advance_slice_mut_checked(src.len())?;
196        // SAFETY:
197        // - `advance_slice_mut_checked` guarantees that `dst` is exactly `src.len()` bytes.
198        // - Given Rust's aliasing rules, we can assume that `src` does not overlap
199        //   with the internal buffer.
200        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
201
202        Ok(())
203    }
204
205    #[inline(always)]
206    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
207        let window = self.advance_slice_mut_checked(n_bytes)?;
208        // SAFETY: by calling `as_trusted_for`, caller guarantees they
209        // will fully initialize `n_bytes` of memory and will not write
210        // beyond the bounds of the slice.
211        Ok(unsafe { SliceMutUnchecked::new(window) })
212    }
213}
214
215impl Writer for Cursor<&mut [u8]> {
216    #[inline]
217    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
218        let dst = self.advance_slice_mut_checked(src.len())?;
219        // SAFETY:
220        // - `advance_slice_mut_checked` guarantees that `dst` is exactly `src.len()` bytes.
221        // - Given Rust's aliasing rules, we can assume that `src` does not overlap
222        //   with the internal buffer.
223        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
224        Ok(())
225    }
226
227    #[inline(always)]
228    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
229        let window = self.advance_slice_mut_checked(n_bytes)?;
230        // SAFETY: by calling `as_trusted_for`, caller guarantees they
231        // will fully initialize `n_bytes` of memory and will not write
232        // beyond the bounds of the slice.
233        Ok(unsafe { SliceMutUnchecked::new(window) })
234    }
235}
236
237impl<const N: usize> Cursor<&mut MaybeUninit<[u8; N]>> {
238    #[inline(always)]
239    fn advance_slice_mut_checked(&mut self, len: usize) -> WriteResult<&mut [MaybeUninit<u8>]> {
240        let Some(slice) = advance_slice_mut_checked(transpose(self.inner), &mut self.pos, len)
241        else {
242            return Err(write_size_limit(len));
243        };
244        Ok(slice)
245    }
246}
247
248impl<const N: usize> Writer for Cursor<&mut MaybeUninit<[u8; N]>> {
249    #[inline]
250    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
251        let dst = self.advance_slice_mut_checked(src.len())?;
252        // SAFETY:
253        // - `advance_slice_mut_checked` guarantees that `dst` is exactly `src.len()` bytes.
254        // - Given Rust's aliasing rules, we can assume that `src` does not overlap
255        //   with the internal buffer.
256        unsafe { ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), src.len()) }
257
258        Ok(())
259    }
260
261    #[inline(always)]
262    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
263        let window = self.advance_slice_mut_checked(n_bytes)?;
264        // SAFETY: by calling `as_trusted_for`, caller guarantees they
265        // will fully initialize `n_bytes` of memory and will not write
266        // beyond the bounds of the slice.
267        Ok(unsafe { SliceMutUnchecked::new(window) })
268    }
269}
270
271/// Helper functions for writing to `Cursor<&mut Vec<u8>>` and `Cursor<Vec<u8>>`.
272#[cfg(feature = "alloc")]
273pub(super) mod vec {
274    use super::*;
275
276    /// Grow the vector if necessary to accommodate the given `needed` bytes.
277    ///
278    /// Note this differs from [`Vec::reserve`] in that it reserves relative to the cursor's
279    /// current position, rather than the initialized length of the vector. The `Cursor<Vec<u8>>`
280    /// implementation overwrites existing elements of the vector, so growing relative to length
281    /// would unnecessarily over-allocate memory.
282    ///
283    /// # Panics
284    ///
285    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
286    #[inline]
287    fn maybe_grow(inner: &mut Vec<u8>, pos: usize, needed: usize) -> WriteResult<()> {
288        let Some(required) = pos.checked_add(needed) else {
289            return Err(write_size_limit(needed));
290        };
291        if required > inner.capacity() {
292            grow(inner, required);
293        }
294        #[cold]
295        fn grow(inner: &mut Vec<u8>, required: usize) {
296            // SAFETY: We just checked that `required > inner.capacity()` (which is greater than
297            // or equal to `inner.len()`), so this will not underflow.
298            let additional = unsafe { required.unchecked_sub(inner.len()) };
299            inner.reserve(additional);
300        }
301        Ok(())
302    }
303
304    /// Zero-fill the gap between `inner.len()` and `pos`, if `pos` is past the
305    /// current initialized length.
306    ///
307    /// # Safety
308    ///
309    /// The caller must ensure that `inner.capacity() >= pos`.
310    ///
311    /// If `pos > inner.len()`, the range `inner.len()..pos` must be spare capacity
312    /// owned by `inner` and valid to write as `MaybeUninit<u8>`. This function
313    /// initializes that entire gap with zero bytes.
314    ///
315    /// Callers should normally establish this by calling `maybe_grow(inner, pos, n)`
316    /// with any `n` such that `pos + n` is checked and fits in the vector capacity.
317    #[inline]
318    unsafe fn zero_fill_gap(inner: &mut Vec<u8>, pos: usize) {
319        if let Some(init_gap) = pos.checked_sub(inner.len()) {
320            let spare = inner.spare_capacity_mut();
321            debug_assert!(spare.len() >= init_gap);
322
323            unsafe {
324                spare
325                    .get_unchecked_mut(..init_gap)
326                    .fill(MaybeUninit::new(0));
327            }
328        }
329    }
330
331    /// Prepare `inner` for a write of `needed` bytes starting at cursor position `pos`.
332    ///
333    /// This checks that `pos + needed` fits in `usize`, ensures the vector has enough
334    /// capacity for the whole write window, and zero-initializes any sparse gap between
335    /// the current length and `pos`. It does not change the vector's length: callers must
336    /// only expose newly initialized bytes after the write window itself has been
337    /// initialized, typically via [`add_len`] or an equivalent `set_len`.
338    #[inline]
339    pub(crate) fn prepare_write(inner: &mut Vec<u8>, pos: usize, needed: usize) -> WriteResult<()> {
340        maybe_grow(inner, pos, needed)?;
341        // SAFETY: `maybe_grow` checked `pos + needed` and ensured capacity for it,
342        // so `inner.capacity() >= pos`; `zero_fill_gap` only writes `inner.len()..pos`.
343        unsafe { zero_fill_gap(inner, pos) };
344        Ok(())
345    }
346
347    /// Add `len` to the cursor's position and update the length of the vector if necessary.
348    ///
349    /// # SAFETY:
350    /// - Must be called after a successful write to the vector.
351    #[inline(always)]
352    pub(super) unsafe fn add_len(inner: &mut Vec<u8>, pos: &mut usize, len: usize) {
353        // SAFETY: We just wrote `len` bytes to the vector, so `pos + len` is valid.
354        let next_pos = unsafe { pos.unchecked_add(len) };
355
356        // If pos exceeds the length of the vector, we just wrote to uninitialized capacity,
357        // which is now initialized.
358        if next_pos > inner.len() {
359            unsafe {
360                inner.set_len(next_pos);
361            }
362        }
363        *pos = next_pos;
364    }
365
366    /// Write `src` to the vector at the current position and advance the position by `src.len()`.
367    pub(super) fn write(inner: &mut Vec<u8>, pos: &mut usize, src: &[u8]) -> WriteResult<()> {
368        prepare_write(inner, *pos, src.len())?;
369        // SAFETY: `prepare_write` ensured at least `*pos + src.len()` capacity is
370        // available.
371        unsafe { ptr::copy_nonoverlapping(src.as_ptr(), inner.as_mut_ptr().add(*pos), src.len()) };
372        // SAFETY: `prepare_write` initialized any gap before `*pos`, and we
373        // just wrote `src.len()` bytes starting at `*pos`.
374        unsafe { add_len(inner, pos, src.len()) };
375        Ok(())
376    }
377
378    #[inline]
379    pub(super) unsafe fn as_trusted_for<'a>(
380        inner: &'a mut Vec<u8>,
381        pos: &'a mut usize,
382        n_bytes: usize,
383    ) -> WriteResult<impl Writer> {
384        prepare_write(inner, *pos, n_bytes)?;
385        // SAFETY: by calling `as_trusted_for`, caller guarantees they
386        // will fully initialize `n_bytes` of memory and will not write
387        // beyond the bounds of the slice.
388        Ok(unsafe { VecPosUnchecked::new(inner, pos) })
389    }
390}
391
392#[cfg(feature = "alloc")]
393struct VecPosUnchecked<'a> {
394    inner: &'a mut Vec<u8>,
395    pos: &'a mut usize,
396}
397
398#[cfg(feature = "alloc")]
399impl<'a> VecPosUnchecked<'a> {
400    /// # Safety
401    ///
402    /// The caller must ensure that `*pos` is within `inner`'s capacity and
403    /// that any gap before `*pos` has already been initialized. Writes through
404    /// this unchecked writer must stay within the trusted window reserved by
405    /// the caller.
406    const unsafe fn new(inner: &'a mut Vec<u8>, pos: &'a mut usize) -> Self {
407        Self { inner, pos }
408    }
409}
410
411#[cfg(feature = "alloc")]
412impl<'a> Writer for VecPosUnchecked<'a> {
413    #[inline]
414    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
415        // SAFETY:
416        // - `as_trusted_for` ensured sufficient capacity for the trusted window before
417        //   constructing this writer.
418        // - The trusted-writer contract requires all writes through this writer to stay
419        //   within that reserved window.
420        // - Given Rust's aliasing rules, we can assume that `src` does not overlap with
421        //   the internal buffer.
422        unsafe {
423            copy_nonoverlapping(
424                src.as_ptr(),
425                self.inner.as_mut_ptr().add(*self.pos),
426                src.len(),
427            );
428        }
429
430        // SAFETY: any gap before the trusted window was initialized before
431        // constructing this writer, and this call just initialized the bytes
432        // from the previous cursor position through `next_pos`.
433        unsafe { vec::add_len(self.inner, self.pos, src.len()) }
434
435        Ok(())
436    }
437}
438
439/// Writer implementation for `&mut Vec<u8>` that overwrites the underlying vector's memory.
440/// The vector will grow as needed.
441///
442/// # Examples
443///
444/// Overwriting an existing vector.
445/// ```
446/// # #[cfg(feature = "alloc")] {
447/// # use wincode::io::{Cursor, Writer};
448/// let mut vec = vec![0; 3];
449/// let mut cursor = Cursor::new(&mut vec);
450/// let bytes = [1, 2, 3, 4];
451/// cursor.write(&bytes).unwrap();
452/// assert_eq!(&vec, &[1, 2, 3, 4]);
453/// # }
454/// ```
455///
456/// Growing a vector.
457/// ```
458/// # #[cfg(feature = "alloc")] {
459/// # use wincode::io::{Cursor, Writer};
460/// let mut vec = vec![];
461/// let mut cursor = Cursor::new(&mut vec);
462/// let bytes = [1, 2, 3];
463/// cursor.write(&bytes).unwrap();
464/// assert_eq!(&vec, &[1, 2, 3]);
465/// # }
466/// ```
467#[cfg(feature = "alloc")]
468impl Writer for Cursor<&mut Vec<u8>> {
469    #[inline]
470    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
471        vec::write(self.inner, &mut self.pos, src)
472    }
473
474    #[inline(always)]
475    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
476        unsafe { vec::as_trusted_for(self.inner, &mut self.pos, n_bytes) }
477    }
478}
479
480/// Writer implementation for `Vec<u8>` that overwrites the underlying vector's memory.
481/// The vector will grow as needed.
482/// # Examples
483///
484/// Overwriting an existing vector.
485/// ```
486/// # #[cfg(feature = "alloc")] {
487/// # use wincode::io::{Cursor, Writer};
488/// let mut cursor = Cursor::new(vec![0; 3]);
489/// let bytes = [1, 2, 3, 4];
490/// cursor.write(&bytes).unwrap();
491/// assert_eq!(cursor.into_inner(), &[1, 2, 3, 4]);
492/// # }
493/// ```
494///
495/// Growing a vector.
496/// ```
497/// # #[cfg(feature = "alloc")] {
498/// # use wincode::io::{Cursor, Writer};
499/// let mut cursor = Cursor::new(vec![]);
500/// let bytes = [1, 2, 3];
501/// cursor.write(&bytes).unwrap();
502/// assert_eq!(cursor.into_inner(), &[1, 2, 3]);
503/// # }
504/// ```
505#[cfg(feature = "alloc")]
506impl Writer for Cursor<Vec<u8>> {
507    #[inline]
508    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
509        vec::write(&mut self.inner, &mut self.pos, src)
510    }
511
512    #[inline(always)]
513    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
514        unsafe { vec::as_trusted_for(&mut self.inner, &mut self.pos, n_bytes) }
515    }
516}
517
518#[cfg(all(test, feature = "alloc"))]
519mod tests {
520    #![allow(clippy::arithmetic_side_effects)]
521    use {super::*, crate::proptest_config::proptest_cfg, alloc::vec, proptest::prelude::*};
522
523    proptest! {
524        #![proptest_config(proptest_cfg())]
525
526        #[test]
527        fn cursor_read_no_panic_no_ub_check(bytes in any::<Vec<u8>>(), pos in any::<usize>()) {
528            let mut cursor = Cursor::new_at(&bytes, pos);
529
530            let mut dst = Vec::with_capacity(bytes.len());
531            let res = cursor.copy_into_uninit_slice(dst.spare_capacity_mut());
532            if pos > bytes.len() && !bytes.is_empty() {
533                prop_assert!(matches!(res, Err(ReadError::ReadSizeLimit(x)) if x == bytes.len()));
534            } else {
535                unsafe { dst.set_len(bytes.len()) };
536                prop_assert_eq!(&dst, &bytes[pos.min(bytes.len())..]);
537            }
538        }
539
540        #[test]
541        fn cursor_zero_len_ops_ok(bytes in any::<Vec<u8>>(), pos in any::<usize>()) {
542            let mut cursor = Cursor::new_at(&bytes, pos);
543            let start = cursor.position();
544
545            let mut buf: [MaybeUninit::<u8>; 0] = [];
546            cursor.copy_into_uninit_slice(&mut buf).unwrap();
547            prop_assert_eq!(cursor.position(), start);
548
549            unsafe { <Cursor<_> as Reader>::as_trusted_for(&mut cursor, 0) }.unwrap();
550            prop_assert_eq!(cursor.position(), start);
551        }
552
553        #[test]
554        fn cursor_as_trusted_for_remaining_advances_to_len(bytes in any::<Vec<u8>>(), pos in any::<usize>()) {
555            // Clamp pos to be within [0, len] so the request is valid.
556            let len = bytes.len();
557            let pos = if len == 0 { 0 } else { pos % (len + 1) };
558            let mut cursor = Cursor::new_at(&bytes, pos);
559            let remaining = len.saturating_sub(pos);
560
561            {
562                let _trusted = unsafe { <Cursor<_> as Reader>::as_trusted_for(&mut cursor, remaining) }.unwrap();
563            }
564
565            // After consuming the exact remaining, position should be exactly len.
566            prop_assert_eq!(cursor.position(), len);
567        }
568
569        #[test]
570        fn cursor_extremal_pos_max_zero_len_ok(bytes in any::<Vec<u8>>()) {
571            let mut cursor = Cursor::new_at(&bytes, usize::MAX);
572
573            // Zero-length ops still succeed and do not advance.
574            let mut buf: [MaybeUninit::<u8>; 0] = [];
575            let start = cursor.position();
576            prop_assert!(cursor.copy_into_uninit_slice(&mut buf).is_ok());
577            {
578                let _trusted = unsafe { <Cursor<_> as Reader>::as_trusted_for(&mut cursor, 0) }.unwrap();
579            }
580            prop_assert_eq!(cursor.position(), start);
581        }
582
583        #[test]
584        fn uninit_slice_write_no_panic_no_ub_check(bytes in any::<Vec<u8>>(), pos in any::<usize>()) {
585            let mut output: Vec<u8> = Vec::with_capacity(bytes.len());
586            let mut cursor = Cursor::new_at(output.spare_capacity_mut(), pos);
587            let res = cursor.write(&bytes);
588            if pos > bytes.len() && !bytes.is_empty() {
589                prop_assert!(matches!(res, Err(WriteError::WriteSizeLimit(x)) if x == bytes.len()));
590            } else if pos == 0 {
591                prop_assert_eq!(output, bytes);
592            }
593        }
594
595        #[test]
596        fn vec_write_no_panic_no_ub_check(bytes in any::<Vec<u8>>(), pos in any::<u16>()) {
597            let pos = pos as usize;
598            let mut output: Vec<u8> = Vec::new();
599            let mut cursor = Cursor::new_at(&mut output, pos);
600            // Vec impl grows, so it should be valid to write to any position within memory limits.
601            cursor.write(&bytes).unwrap();
602            prop_assert_eq!(&output[pos..], &bytes);
603        }
604
605        #[test]
606        fn cursor_write_vec_new(bytes in any::<Vec<u8>>()) {
607            let mut cursor = Cursor::new(Vec::new());
608            cursor.write(&bytes).unwrap();
609            prop_assert_eq!(&cursor.inner, &bytes);
610
611            let mut vec = Vec::with_capacity(bytes.len());
612            let mut cursor = Cursor::new(vec.spare_capacity_mut());
613            cursor.write(&bytes).unwrap();
614            unsafe { vec.set_len(bytes.len()) };
615            prop_assert_eq!(&vec, &bytes);
616        }
617
618        #[test]
619        fn cursor_write_existing_vec(bytes in any::<Vec<u8>>()) {
620            let mut cursor = Cursor::new(vec![0; bytes.len()]);
621            cursor.write(&bytes).unwrap();
622            prop_assert_eq!(&cursor.inner, &bytes);
623        }
624
625        #[test]
626        fn cursor_write_existing_grow_vec(bytes in any::<Vec<u8>>()) {
627            let mut cursor = Cursor::new(vec![0; bytes.len() / 2]);
628            cursor.write(&bytes).unwrap();
629            prop_assert_eq!(&cursor.inner, &bytes);
630        }
631
632        #[test]
633        fn cursor_write_partial_vec(bytes in any::<Vec<u8>>()) {
634            let mut cursor = Cursor::new(vec![1; bytes.len()]);
635            let half = bytes.len() - bytes.len() / 2;
636            cursor.write(&bytes[..half]).unwrap();
637            prop_assert_eq!(&cursor.inner[..half], &bytes[..half]);
638            // Remaining bytes are untouched
639            prop_assert_eq!(&cursor.inner[half..], &vec![1; bytes.len() - half]);
640            cursor.write(&bytes[half..]).unwrap();
641            prop_assert_eq!(&cursor.inner, &bytes);
642        }
643
644        #[test]
645        fn cursor_write_trusted_vec(bytes in any::<Vec<u8>>()) {
646            let mut cursor = Cursor::new(vec![1; bytes.len()]);
647            let half = bytes.len() - bytes.len() / 2;
648            cursor.write(&bytes[..half]).unwrap();
649            unsafe { <Cursor<_> as Writer>::as_trusted_for(&mut cursor, bytes.len() - half) }
650                .unwrap()
651                .write(&bytes[half..])
652                .unwrap();
653            cursor.finish().unwrap();
654            prop_assert_eq!(&cursor.inner, &bytes);
655        }
656
657        #[test]
658        fn cursor_write_trusted_grow_vec(bytes in any::<Vec<u8>>()) {
659            let mut cursor = Cursor::new(vec![1; bytes.len() / 2]);
660            let half = bytes.len() - bytes.len() / 2;
661            cursor.write(&bytes[..half]).unwrap();
662            unsafe { <Cursor<_> as Writer>::as_trusted_for(&mut cursor, bytes.len() - half) }
663                .unwrap()
664                .write(&bytes[half..])
665                .unwrap();
666            cursor.finish().unwrap();
667            prop_assert_eq!(&cursor.inner, &bytes);
668        }
669
670        #[test]
671        fn cursor_write_trusted_oversized_vec(bytes in any::<Vec<u8>>()) {
672            let mut cursor = Cursor::new(vec![1; bytes.len() * 2]);
673            let half = bytes.len() - bytes.len() / 2;
674            cursor.write(&bytes[..half]).unwrap();
675            unsafe { <Cursor<_> as Writer>::as_trusted_for(&mut cursor, bytes.len() - half) }
676                .unwrap()
677                .write(&bytes[half..])
678                .unwrap();
679            cursor.finish().unwrap();
680            prop_assert_eq!(&cursor.inner[..bytes.len()], &bytes);
681            // Remaining bytes are untouched
682            prop_assert_eq!(&cursor.inner[bytes.len()..], &vec![1; bytes.len()]);
683        }
684
685        #[cfg(feature = "derive")]
686        #[test]
687        fn cursor_read_items_with_inner_zero_copy(bytes in proptest::collection::vec(any::<u8>(), 64)) {
688            use crate::{config::DefaultConfig, SchemaRead};
689
690            // Test reader not supporting zero-copy, but used to read items that contain nested
691            // zero-copy content
692            #[derive(crate::SchemaRead)]
693            #[wincode(internal)]
694            struct NonZeroCopyWrapper {
695                zero_copy_content: [u8; 8],
696            }
697
698            let mut cursor = Cursor::new(&bytes);
699            let mut dst = MaybeUninit::uninit();
700            <[NonZeroCopyWrapper; 8] as SchemaRead<DefaultConfig>>::read(&mut cursor, &mut dst)
701                .unwrap();
702            let deserialized = unsafe { dst.assume_init() };
703            for (i, chunk) in bytes.chunks_exact(size_of::<NonZeroCopyWrapper>()).enumerate() {
704                prop_assert_eq!(&deserialized[i].zero_copy_content, chunk);
705            }
706        }
707    }
708
709    #[test]
710    fn cursor_vec_write_zero_fills_gap() {
711        let mut output = vec![1, 2, 3];
712        let mut cursor = Cursor::new_at(&mut output, 6);
713
714        cursor.write(&[9, 10]).unwrap();
715
716        assert_eq!(output, vec![1, 2, 3, 0, 0, 0, 9, 10]);
717    }
718
719    #[test]
720    fn cursor_vec_trusted_write_zero_fills_gap() {
721        let mut output = vec![1, 2, 3];
722        let mut cursor = Cursor::new_at(&mut output, 6);
723
724        unsafe { <Cursor<_> as Writer>::as_trusted_for(&mut cursor, 2) }
725            .unwrap()
726            .write(&[9, 10])
727            .unwrap();
728
729        assert_eq!(output, vec![1, 2, 3, 0, 0, 0, 9, 10]);
730    }
731
732    #[test]
733    fn cursor_vec_finish_does_not_extend_len() {
734        let mut output = Vec::with_capacity(8);
735        let mut cursor = Cursor::new_at(&mut output, 6);
736
737        cursor.finish().unwrap();
738
739        assert_eq!(output.len(), 0);
740    }
741}