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
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 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 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 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 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 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 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 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 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 Ok(unsafe { SliceMutUnchecked::new(window) })
257 }
258}
259
260#[cfg(feature = "alloc")]
262mod vec {
263 use super::*;
264
265 #[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 let additional = unsafe { required.unchecked_sub(inner.len()) };
288 inner.reserve(additional);
289 }
290 Ok(())
291 }
292
293 pub(super) unsafe fn add_len(inner: &mut Vec<u8>, pos: &mut usize, len: usize) {
298 let next_pos = unsafe { pos.unchecked_add(len) };
300
301 if next_pos > inner.len() {
304 unsafe {
305 inner.set_len(next_pos);
306 }
307 }
308 *pos = next_pos;
309 }
310
311 pub(super) fn write(inner: &mut Vec<u8>, pos: &mut usize, src: &[u8]) -> WriteResult<()> {
313 maybe_grow(inner, *pos, src.len())?;
314 unsafe { ptr::copy_nonoverlapping(src.as_ptr(), inner.as_mut_ptr().add(*pos), src.len()) };
316 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 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 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#[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#[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 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 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 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 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 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 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 #[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}