1use std::str;
19
20use super::error::{MAX_GROUP_SIZE, SbeDecodeError};
21
22#[derive(Debug, Clone)]
27pub struct SbeCursor<'a> {
28 buf: &'a [u8],
29 pos: usize,
30}
31
32impl<'a> SbeCursor<'a> {
33 #[must_use]
35 pub const fn new(buf: &'a [u8]) -> Self {
36 Self { buf, pos: 0 }
37 }
38
39 #[must_use]
41 pub const fn new_at(buf: &'a [u8], pos: usize) -> Self {
42 Self { buf, pos }
43 }
44
45 #[must_use]
47 pub const fn pos(&self) -> usize {
48 self.pos
49 }
50
51 #[must_use]
53 pub const fn remaining(&self) -> usize {
54 self.buf.len().saturating_sub(self.pos)
55 }
56
57 #[must_use]
59 pub const fn buffer(&self) -> &'a [u8] {
60 self.buf
61 }
62
63 #[must_use]
65 pub fn peek(&self) -> &'a [u8] {
66 &self.buf[self.pos..]
67 }
68
69 #[inline]
75 pub fn require(&self, n: usize) -> Result<(), SbeDecodeError> {
76 if self.remaining() < n {
77 return Err(SbeDecodeError::BufferTooShort {
78 expected: self.pos + n,
79 actual: self.buf.len(),
80 });
81 }
82 Ok(())
83 }
84
85 #[inline]
91 pub fn advance(&mut self, n: usize) -> Result<(), SbeDecodeError> {
92 self.require(n)?;
93 self.pos += n;
94 Ok(())
95 }
96
97 #[inline]
101 pub fn skip(&mut self, n: usize) {
102 self.pos += n;
103 }
104
105 pub fn reset(&mut self) {
107 self.pos = 0;
108 }
109
110 pub fn set_pos(&mut self, pos: usize) {
112 self.pos = pos;
113 }
114
115 #[inline]
121 pub fn read_u8(&mut self) -> Result<u8, SbeDecodeError> {
122 self.require(1)?;
123 let value = self.buf[self.pos];
124 self.pos += 1;
125 Ok(value)
126 }
127
128 #[inline]
134 pub fn read_i8(&mut self) -> Result<i8, SbeDecodeError> {
135 self.require(1)?;
136 let value = self.buf[self.pos] as i8;
137 self.pos += 1;
138 Ok(value)
139 }
140
141 #[inline]
147 pub fn read_u16_le(&mut self) -> Result<u16, SbeDecodeError> {
148 Ok(u16::from_le_bytes(self.read_array::<2>()?))
149 }
150
151 #[inline]
157 pub fn read_i16_le(&mut self) -> Result<i16, SbeDecodeError> {
158 Ok(i16::from_le_bytes(self.read_array::<2>()?))
159 }
160
161 #[inline]
167 pub fn read_u32_le(&mut self) -> Result<u32, SbeDecodeError> {
168 Ok(u32::from_le_bytes(self.read_array::<4>()?))
169 }
170
171 #[inline]
177 pub fn read_i32_le(&mut self) -> Result<i32, SbeDecodeError> {
178 Ok(i32::from_le_bytes(self.read_array::<4>()?))
179 }
180
181 #[inline]
187 pub fn read_u64_le(&mut self) -> Result<u64, SbeDecodeError> {
188 Ok(u64::from_le_bytes(self.read_array::<8>()?))
189 }
190
191 #[inline]
197 pub fn read_i64_le(&mut self) -> Result<i64, SbeDecodeError> {
198 Ok(i64::from_le_bytes(self.read_array::<8>()?))
199 }
200
201 #[inline]
207 pub fn read_u128_le(&mut self) -> Result<u128, SbeDecodeError> {
208 Ok(u128::from_le_bytes(self.read_array::<16>()?))
209 }
210
211 #[inline]
217 pub fn read_i128_le(&mut self) -> Result<i128, SbeDecodeError> {
218 Ok(i128::from_le_bytes(self.read_array::<16>()?))
219 }
220
221 #[inline]
227 pub fn read_optional_i64_le(&mut self) -> Result<Option<i64>, SbeDecodeError> {
228 let value = self.read_i64_le()?;
229 Ok(if value == i64::MIN { None } else { Some(value) })
230 }
231
232 #[expect(
238 clippy::inline_always,
239 reason = "preserves checked slice lengths for fixed-width SBE decoding"
240 )]
241 #[inline(always)]
242 pub fn read_bytes(&mut self, n: usize) -> Result<&'a [u8], SbeDecodeError> {
243 self.require(n)?;
244 let slice = &self.buf[self.pos..self.pos + n];
245 self.pos += n;
246 Ok(slice)
247 }
248
249 #[inline]
253 fn read_array<const N: usize>(&mut self) -> Result<[u8; N], SbeDecodeError> {
254 self.require(N)?;
255 let bytes: [u8; N] = self.buf[self.pos..self.pos + N]
256 .try_into()
257 .expect("slice length matches N");
258 self.pos += N;
259 Ok(bytes)
260 }
261
262 #[inline]
270 pub fn read_var_string8(&mut self) -> Result<String, SbeDecodeError> {
271 Ok(self.read_var_string8_ref()?.to_owned())
272 }
273
274 #[inline]
280 pub fn read_var_string8_ref(&mut self) -> Result<&'a str, SbeDecodeError> {
281 let len = self.read_u8()? as usize;
282 if len == 0 {
283 return Ok("");
284 }
285 self.require(len)?;
286 let s = str::from_utf8(&self.buf[self.pos..self.pos + len])
287 .map_err(|_| SbeDecodeError::InvalidUtf8)?;
288 self.pos += len;
289 Ok(s)
290 }
291
292 #[inline]
300 pub fn read_var_string16(&mut self) -> Result<String, SbeDecodeError> {
301 Ok(self.read_var_string16_ref()?.to_owned())
302 }
303
304 #[inline]
310 pub fn read_var_string16_ref(&mut self) -> Result<&'a str, SbeDecodeError> {
311 let len = usize::from(self.read_u16_le()?);
312 if len == 0 {
313 return Ok("");
314 }
315 self.require(len)?;
316 let s = str::from_utf8(&self.buf[self.pos..self.pos + len])
317 .map_err(|_| SbeDecodeError::InvalidUtf8)?;
318 self.pos += len;
319 Ok(s)
320 }
321
322 pub fn skip_var_data8(&mut self) -> Result<(), SbeDecodeError> {
330 let len = self.read_u8()? as usize;
331 self.advance(len)
332 }
333
334 pub fn read_var_bytes8(&mut self) -> Result<Vec<u8>, SbeDecodeError> {
342 let len = self.read_u8()? as usize;
343 Ok(self.read_bytes(len)?.to_vec())
344 }
345
346 pub fn skip_var_data16(&mut self) -> Result<(), SbeDecodeError> {
352 let len = usize::from(self.read_u16_le()?);
353 self.advance(len)
354 }
355
356 pub fn read_var_bytes16(&mut self) -> Result<Vec<u8>, SbeDecodeError> {
364 let len = usize::from(self.read_u16_le()?);
365 Ok(self.read_bytes(len)?.to_vec())
366 }
367
368 #[inline]
377 pub fn read_group_header(&mut self) -> Result<(u16, u32), SbeDecodeError> {
378 let block_length = self.read_u16_le()?;
379 let num_in_group = self.read_u32_le()?;
380
381 if num_in_group > MAX_GROUP_SIZE {
382 return Err(SbeDecodeError::GroupSizeTooLarge {
383 count: num_in_group,
384 max: MAX_GROUP_SIZE,
385 });
386 }
387
388 Ok((block_length, num_in_group))
389 }
390
391 #[inline]
400 pub fn read_group_header_16(&mut self) -> Result<(u16, u16), SbeDecodeError> {
401 let block_length = self.read_u16_le()?;
402 let num_in_group = self.read_u16_le()?;
403
404 if u32::from(num_in_group) > MAX_GROUP_SIZE {
405 return Err(SbeDecodeError::GroupSizeTooLarge {
406 count: u32::from(num_in_group),
407 max: MAX_GROUP_SIZE,
408 });
409 }
410
411 Ok((block_length, num_in_group))
412 }
413
414 pub fn read_group<T, F>(
426 &mut self,
427 block_length: u16,
428 num_in_group: u32,
429 mut decode_item: F,
430 ) -> Result<Vec<T>, SbeDecodeError>
431 where
432 F: FnMut(&mut Self) -> Result<T, SbeDecodeError>,
433 {
434 let block_len = block_length as usize;
435 let count = num_in_group as usize;
436
437 self.require(count * block_len)?;
439
440 let mut items = Vec::with_capacity(count);
441 for _ in 0..count {
442 let item_start = self.pos;
443 let item_end = item_start + block_len;
444
445 let buf = self
446 .buf
447 .get(..item_end)
448 .ok_or(SbeDecodeError::BufferTooShort {
449 expected: item_end,
450 actual: self.buf.len(),
451 })?;
452
453 let mut entry = Self::new_at(buf, item_start);
454 let item = decode_item(&mut entry);
455 self.pos = entry.pos;
456 items.push(item?);
457 self.pos = item_end;
458 }
459
460 Ok(items)
461 }
462}
463
464#[cfg(test)]
465mod tests {
466 use rstest::rstest;
467
468 use super::*;
469
470 #[rstest]
471 fn test_new_starts_at_zero() {
472 let buf = [1, 2, 3, 4];
473 let cursor = SbeCursor::new(&buf);
474 assert_eq!(cursor.pos(), 0);
475 assert_eq!(cursor.remaining(), 4);
476 }
477
478 #[rstest]
479 fn test_new_at_starts_at_offset() {
480 let buf = [1, 2, 3, 4];
481 let cursor = SbeCursor::new_at(&buf, 2);
482 assert_eq!(cursor.pos(), 2);
483 assert_eq!(cursor.remaining(), 2);
484 }
485
486 #[rstest]
487 fn test_read_u8() {
488 let buf = [0x42, 0xFF];
489 let mut cursor = SbeCursor::new(&buf);
490
491 assert_eq!(cursor.read_u8().unwrap(), 0x42);
492 assert_eq!(cursor.pos(), 1);
493
494 assert_eq!(cursor.read_u8().unwrap(), 0xFF);
495 assert_eq!(cursor.pos(), 2);
496
497 assert!(cursor.read_u8().is_err());
498 }
499
500 #[rstest]
501 fn test_read_i8() {
502 let buf = [0x7F, 0x80]; let mut cursor = SbeCursor::new(&buf);
504
505 assert_eq!(cursor.read_i8().unwrap(), 127);
506 assert_eq!(cursor.read_i8().unwrap(), -128);
507 }
508
509 #[rstest]
510 fn test_read_u16_le() {
511 let buf = [0x34, 0x12]; let mut cursor = SbeCursor::new(&buf);
513
514 assert_eq!(cursor.read_u16_le().unwrap(), 0x1234);
515 assert_eq!(cursor.pos(), 2);
516 }
517
518 #[rstest]
519 fn test_read_i64_le() {
520 let value: i64 = -1_234_567_890_123_456_789;
521 let buf = value.to_le_bytes();
522 let mut cursor = SbeCursor::new(&buf);
523
524 assert_eq!(cursor.read_i64_le().unwrap(), value);
525 assert_eq!(cursor.pos(), 8);
526 }
527
528 #[rstest]
529 #[case::u16(&[0x34][..], 2)]
530 #[case::u32(&[0x34, 0x12, 0x00][..], 4)]
531 #[case::u64(&[0; 7][..], 8)]
532 #[case::u128(&[0; 15][..], 16)]
533 fn test_multi_byte_reads_buffer_too_short(#[case] buf: &[u8], #[case] needed: usize) {
534 let mut cursor = SbeCursor::new(buf);
535 let err = match needed {
536 2 => cursor.read_u16_le().map(|_| ()).unwrap_err(),
537 4 => cursor.read_u32_le().map(|_| ()).unwrap_err(),
538 8 => cursor.read_u64_le().map(|_| ()).unwrap_err(),
539 16 => cursor.read_u128_le().map(|_| ()).unwrap_err(),
540 _ => unreachable!(),
541 };
542
543 assert_eq!(
544 err,
545 SbeDecodeError::BufferTooShort {
546 expected: needed,
547 actual: buf.len()
548 }
549 );
550 assert_eq!(cursor.pos(), 0, "position must not advance on error");
551 }
552
553 #[rstest]
554 fn test_read_optional_i64_null() {
555 let buf = i64::MIN.to_le_bytes();
556 let mut cursor = SbeCursor::new(&buf);
557
558 assert_eq!(cursor.read_optional_i64_le().unwrap(), None);
559 }
560
561 #[rstest]
562 fn test_read_optional_i64_present() {
563 let value: i64 = 12345;
564 let buf = value.to_le_bytes();
565 let mut cursor = SbeCursor::new(&buf);
566
567 assert_eq!(cursor.read_optional_i64_le().unwrap(), Some(12345));
568 }
569
570 #[rstest]
571 fn test_read_var_string8() {
572 let mut buf = vec![5]; buf.extend_from_slice(b"hello");
574 let mut cursor = SbeCursor::new(&buf);
575
576 assert_eq!(cursor.read_var_string8().unwrap(), "hello");
577 assert_eq!(cursor.pos(), 6); }
579
580 #[rstest]
581 fn test_read_var_string8_empty() {
582 let buf = [0]; let mut cursor = SbeCursor::new(&buf);
584
585 assert_eq!(cursor.read_var_string8().unwrap(), "");
586 assert_eq!(cursor.pos(), 1);
587 }
588
589 #[rstest]
590 fn test_read_var_string8_invalid_utf8() {
591 let buf = [2, 0xFF, 0xFE]; let mut cursor = SbeCursor::new(&buf);
593
594 assert!(matches!(
595 cursor.read_var_string8(),
596 Err(SbeDecodeError::InvalidUtf8)
597 ));
598 }
599
600 #[rstest]
601 fn test_read_group_header() {
602 let buf = [24, 0, 3, 0, 0, 0];
604 let mut cursor = SbeCursor::new(&buf);
605
606 let (block_len, count) = cursor.read_group_header().unwrap();
607 assert_eq!(block_len, 24);
608 assert_eq!(count, 3);
609 assert_eq!(cursor.pos(), 6);
610 }
611
612 #[rstest]
613 fn test_read_group_header_too_large() {
614 let count = MAX_GROUP_SIZE + 1;
616 let mut buf = vec![24, 0]; buf.extend_from_slice(&count.to_le_bytes());
618 let mut cursor = SbeCursor::new(&buf);
619
620 assert!(matches!(
621 cursor.read_group_header(),
622 Err(SbeDecodeError::GroupSizeTooLarge { .. })
623 ));
624 }
625
626 #[rstest]
627 fn test_read_group() {
628 let mut buf = Vec::new();
630 buf.extend_from_slice(&100u32.to_le_bytes()); buf.extend_from_slice(&200u32.to_le_bytes()); let mut cursor = SbeCursor::new(&buf);
634 let items: Vec<u32> = cursor
635 .read_group(4, 2, super::SbeCursor::read_u32_le)
636 .unwrap();
637
638 assert_eq!(items, vec![100, 200]);
639 assert_eq!(cursor.pos(), 8);
640 }
641
642 #[rstest]
643 fn test_read_group_respects_block_length() {
644 let mut buf = Vec::new();
646 buf.extend_from_slice(&100u32.to_le_bytes());
647 buf.extend_from_slice(&[0, 0, 0, 0]); buf.extend_from_slice(&200u32.to_le_bytes());
649 buf.extend_from_slice(&[0, 0, 0, 0]); let mut cursor = SbeCursor::new(&buf);
652 let items: Vec<u32> = cursor
653 .read_group(8, 2, super::SbeCursor::read_u32_le)
654 .unwrap();
655
656 assert_eq!(items, vec![100, 200]);
657 assert_eq!(cursor.pos(), 16); }
659
660 #[rstest]
661 #[case(0)]
662 #[case(3)]
663 fn test_read_group_rejects_entry_overread(#[case] block_length: u16) {
664 let buf = [9, 8, 7, 6, 5, 4, 3, 2, 1];
665 let mut cursor = SbeCursor::new_at(&buf, 1);
666 let mut calls = 0;
667 let item_end = 1 + usize::from(block_length);
668
669 let result = cursor.read_group(block_length, 2, |entry| {
670 calls += 1;
671 assert_eq!(entry.pos(), 1);
672 assert_eq!(entry.buffer(), &buf[..item_end]);
673 assert_eq!(entry.remaining(), usize::from(block_length));
674 assert_eq!(entry.peek(), &buf[1..item_end]);
675 entry.read_u32_le()
676 });
677
678 assert_eq!(
679 result,
680 Err(SbeDecodeError::BufferTooShort {
681 expected: 5,
682 actual: item_end,
683 })
684 );
685 assert_eq!(cursor.pos(), 1);
686 assert_eq!(calls, 1);
687 }
688
689 #[rstest]
690 fn test_read_group_rejects_position_past_buffer() {
691 let mut cursor = SbeCursor::new_at(&[1, 2], 3);
692 let result = cursor.read_group(0, 1, SbeCursor::read_u8);
693
694 assert_eq!(
695 result,
696 Err(SbeDecodeError::BufferTooShort {
697 expected: 3,
698 actual: 2
699 })
700 );
701 assert_eq!(cursor.pos(), 3);
702 }
703
704 #[rstest]
705 fn test_read_group_preserves_position_after_partial_overread() {
706 let mut cursor = SbeCursor::new_at(&[9, 8, 7, 6, 5, 4, 3, 2], 1);
707
708 let result = cursor.read_group(3, 2, |entry| {
709 entry.read_u8()?;
710 entry.read_u32_le()
711 });
712
713 assert_eq!(
714 result,
715 Err(SbeDecodeError::BufferTooShort {
716 expected: 6,
717 actual: 4
718 })
719 );
720 assert_eq!(cursor.pos(), 2);
721 }
722
723 #[rstest]
724 fn test_require_success() {
725 let buf = [1, 2, 3, 4];
726 let cursor = SbeCursor::new(&buf);
727
728 assert!(cursor.require(4).is_ok());
729 assert!(cursor.require(3).is_ok());
730 }
731
732 #[rstest]
733 fn test_require_failure() {
734 let buf = [1, 2];
735 let cursor = SbeCursor::new(&buf);
736
737 let err = cursor.require(3).unwrap_err();
738 assert_eq!(
739 err,
740 SbeDecodeError::BufferTooShort {
741 expected: 3,
742 actual: 2
743 }
744 );
745 }
746
747 #[rstest]
748 fn test_advance() {
749 let buf = [1, 2, 3, 4];
750 let mut cursor = SbeCursor::new(&buf);
751
752 cursor.advance(2).unwrap();
753 assert_eq!(cursor.pos(), 2);
754 assert_eq!(cursor.remaining(), 2);
755
756 assert!(cursor.advance(3).is_err());
757 }
758
759 #[rstest]
760 fn test_peek() {
761 let buf = [1, 2, 3, 4];
762 let mut cursor = SbeCursor::new(&buf);
763
764 assert_eq!(cursor.peek(), &[1, 2, 3, 4]);
765 cursor.advance(2).unwrap();
766 assert_eq!(cursor.peek(), &[3, 4]);
767 }
768
769 #[rstest]
770 fn test_reset() {
771 let buf = [1, 2, 3, 4];
772 let mut cursor = SbeCursor::new(&buf);
773
774 cursor.advance(3).unwrap();
775 assert_eq!(cursor.pos(), 3);
776
777 cursor.reset();
778 assert_eq!(cursor.pos(), 0);
779 assert_eq!(cursor.remaining(), 4);
780 }
781
782 #[rstest]
783 #[case::short(false)]
784 #[case::wide(true)]
785 fn test_var_bytes_preserve_binary_and_position(#[case] wide: bool) {
786 let mut buf = if wide { vec![3, 0] } else { vec![3] };
787 buf.extend_from_slice(&[0xff, 0, 0x80, 0x42]);
788 let mut read = SbeCursor::new(&buf);
789 let mut skip = read.clone();
790
791 let bytes = if wide {
792 skip.skip_var_data16().unwrap();
793 read.read_var_bytes16().unwrap()
794 } else {
795 skip.skip_var_data8().unwrap();
796 read.read_var_bytes8().unwrap()
797 };
798
799 assert_eq!(bytes, [0xff, 0, 0x80]);
800 assert_eq!(read.pos(), buf.len() - 1);
801 assert_eq!(skip.pos(), read.pos());
802 assert_eq!(read.peek(), [0x42]);
803 assert_eq!(skip.peek(), [0x42]);
804 }
805
806 #[rstest]
807 #[case::short(false)]
808 #[case::wide(true)]
809 fn test_var_bytes_reject_truncated_payload(#[case] wide: bool) {
810 let buf = if wide {
811 vec![3, 0, 0xff]
812 } else {
813 vec![3, 0xff]
814 };
815
816 let prefix = if wide { 2 } else { 1 };
817 let mut read = SbeCursor::new(&buf);
818 let mut skip = read.clone();
819
820 let (read_result, skip_result) = if wide {
821 (read.read_var_bytes16(), skip.skip_var_data16())
822 } else {
823 (read.read_var_bytes8(), skip.skip_var_data8())
824 };
825
826 let expected = SbeDecodeError::BufferTooShort {
827 expected: prefix + 3,
828 actual: buf.len(),
829 };
830
831 assert_eq!(read_result, Err(expected.clone()));
832 assert_eq!(skip_result, Err(expected));
833 assert_eq!(read.pos(), prefix);
834 assert_eq!(skip.pos(), prefix);
835 }
836
837 #[rstest]
838 fn test_read_group_propagates_item_error() {
839 let mut cursor = SbeCursor::new(&[1, 2, 3, 4]);
840
841 let result = cursor.read_group(2, 2, |entry| {
842 let value = entry.read_u8()?;
843 if value == 3 {
844 Err(SbeDecodeError::InvalidValue { field: "entry" })
845 } else {
846 Ok(value)
847 }
848 });
849
850 assert_eq!(result, Err(SbeDecodeError::InvalidValue { field: "entry" }));
851 assert_eq!(cursor.pos(), 3);
852 }
853}