1#[cfg(feature = "alloc")]
2use alloc::vec::Vec;
3use {
4 super::*,
5 core::ptr::copy_nonoverlapping,
6 slice::{SliceMutUnchecked, SliceScopedUnchecked},
7};
8
9pub 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 pub const fn new_at(inner: T, pos: usize) -> Self {
78 Self { inner, pos }
79 }
80
81 pub const fn set_position(&mut self, pos: usize) {
83 self.pos = pos;
84 }
85
86 pub fn into_inner(self) -> T {
88 self.inner
89 }
90
91 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 #[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 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 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 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 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 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 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 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 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 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 Ok(unsafe { SliceMutUnchecked::new(window) })
268 }
269}
270
271#[cfg(feature = "alloc")]
273pub(super) mod vec {
274 use super::*;
275
276 #[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 let additional = unsafe { required.unchecked_sub(inner.len()) };
299 inner.reserve(additional);
300 }
301 Ok(())
302 }
303
304 #[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 #[inline]
339 pub(crate) fn prepare_write(inner: &mut Vec<u8>, pos: usize, needed: usize) -> WriteResult<()> {
340 maybe_grow(inner, pos, needed)?;
341 unsafe { zero_fill_gap(inner, pos) };
344 Ok(())
345 }
346
347 #[inline(always)]
352 pub(super) unsafe fn add_len(inner: &mut Vec<u8>, pos: &mut usize, len: usize) {
353 let next_pos = unsafe { pos.unchecked_add(len) };
355
356 if next_pos > inner.len() {
359 unsafe {
360 inner.set_len(next_pos);
361 }
362 }
363 *pos = next_pos;
364 }
365
366 pub(super) fn write(inner: &mut Vec<u8>, pos: &mut usize, src: &[u8]) -> WriteResult<()> {
368 prepare_write(inner, *pos, src.len())?;
369 unsafe { ptr::copy_nonoverlapping(src.as_ptr(), inner.as_mut_ptr().add(*pos), src.len()) };
372 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 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 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 unsafe {
423 copy_nonoverlapping(
424 src.as_ptr(),
425 self.inner.as_mut_ptr().add(*self.pos),
426 src.len(),
427 );
428 }
429
430 unsafe { vec::add_len(self.inner, self.pos, src.len()) }
434
435 Ok(())
436 }
437}
438
439#[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#[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 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 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 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 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 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 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 #[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}