1use crate::{Error, Le};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct Bit {
9 pub byte: u16,
10 pub shift: u8,
11}
12
13#[derive(Debug, Clone, Copy)]
15pub struct TableRef<'a> {
16 buf: &'a [u8],
17 fixed: &'a [u8],
19 fixed_start: usize,
20}
21
22impl<'a> TableRef<'a> {
23 #[inline]
25 pub fn at(buf: &'a [u8], pos: usize) -> Result<Self, Error> {
26 let h = buf.get(pos..pos.checked_add(2).ok_or(Error::OutOfBounds)?).ok_or(Error::OutOfBounds)?;
27 let fixed_len = u16::read_le(h);
28 Self::inline(buf, pos + 2, fixed_len)
29 }
30
31 #[inline]
33 pub fn inline(buf: &'a [u8], fixed_start: usize, fixed_len: u16) -> Result<Self, Error> {
34 let end = fixed_start.checked_add(fixed_len as usize).ok_or(Error::OutOfBounds)?;
35 let fixed = buf.get(fixed_start..end).ok_or(Error::OutOfBounds)?;
36 Ok(TableRef { buf, fixed, fixed_start })
37 }
38
39 #[inline]
40 pub fn buf(&self) -> &'a [u8] {
41 self.buf
42 }
43
44 #[inline]
45 pub fn fixed_len(&self) -> u16 {
46 self.fixed.len() as u16
47 }
48
49 #[inline]
51 pub fn fixed_start(&self) -> usize {
52 self.fixed_start
53 }
54
55 #[inline]
57 fn fixed(&self) -> &'a [u8] {
58 self.fixed
59 }
60
61 #[inline(always)]
63 pub fn fixed_byte(&self, i: u16) -> u8 {
64 self.fixed.get(i as usize).copied().unwrap_or(0)
65 }
66
67 #[inline]
69 pub fn bit(&self, b: Bit) -> bool {
70 match self.fixed().get(b.byte as usize) {
71 Some(v) => (v >> (b.shift & 7)) & 1 == 1,
72 None => false,
73 }
74 }
75
76 #[inline]
79 pub fn slot_state(&self, off: u16, size: u16) -> Result<bool, Error> {
80 let (off, end) = (off as u32, off as u32 + size as u32);
81 let fl = self.fixed.len() as u32;
82 if end <= fl {
83 Ok(true)
84 } else if off >= fl {
85 Ok(false)
86 } else {
87 Err(Error::Truncated)
88 }
89 }
90
91 #[inline(always)]
92 fn slot_bytes(&self, off: u16, size: usize) -> Option<&'a [u8]> {
93 let o = off as usize;
94 self.fixed.get(o..o + size)
95 }
96
97 #[inline]
99 pub fn scalar<T: Le>(&self, off: u16, presence: Bit) -> Result<Option<T>, Error> {
100 if !self.slot_state(off, T::SIZE as u16)? || !self.bit(presence) {
101 return Ok(None);
102 }
103 Ok(self.slot_bytes(off, T::SIZE).map(T::read_le))
104 }
105
106 #[inline]
108 pub fn scalar_or<T: Le>(&self, off: u16, presence: Bit, default: T) -> T {
109 match self.scalar(off, presence) {
110 Ok(Some(v)) => v,
111 _ => default,
112 }
113 }
114
115 #[inline(always)]
118 pub fn raw<T: Le>(&self, off: u16) -> T {
119 match self.slot_bytes(off, T::SIZE) {
120 Some(b) => T::read_le(b),
121 None => T::default(),
122 }
123 }
124
125 #[inline]
127 pub fn bool(&self, presence: Bit) -> Option<bool> {
128 if !self.bit(presence) {
129 return None;
130 }
131 Some(self.bit(Bit { byte: presence.byte, shift: presence.shift + 1 }))
132 }
133}
134
135#[inline]
140fn read_at<T: Le>(buf: &[u8], pos: usize) -> Result<T, Error> {
141 let end = pos.checked_add(T::SIZE).ok_or(Error::OutOfBounds)?;
142 buf.get(pos..end).map(T::read_le).ok_or(Error::OutOfBounds)
143}
144
145#[inline]
147fn resolve(buf: &[u8], slot_abs: usize) -> Result<Option<usize>, Error> {
148 let rel = read_at::<i32>(buf, slot_abs)?;
149 if rel == 0 {
150 return Ok(None);
151 }
152 let target = slot_abs as i64 + rel as i64;
153 if target < 0 || target >= buf.len() as i64 {
154 return Err(Error::BadOffset);
155 }
156 Ok(Some(target as usize))
157}
158
159#[inline]
161fn counted(buf: &[u8], pos: usize, elem: usize) -> Result<(usize, usize), Error> {
162 let len = read_at::<u32>(buf, pos)? as usize;
163 let data = pos + 4;
164 let bytes = len.checked_mul(elem).ok_or(Error::OutOfBounds)?;
165 let end = data.checked_add(bytes).ok_or(Error::OutOfBounds)?;
166 if end > buf.len() {
167 return Err(Error::OutOfBounds);
168 }
169 Ok((len, data))
170}
171
172#[inline]
173fn bytes_at(buf: &[u8], pos: usize) -> Result<&[u8], Error> {
174 let (len, data) = counted(buf, pos, 1)?;
175 Ok(&buf[data..data + len])
176}
177
178#[inline]
179fn str_at(buf: &[u8], pos: usize) -> Result<&str, Error> {
180 core::str::from_utf8(bytes_at(buf, pos)?).map_err(|_| Error::InvalidUtf8)
181}
182
183impl<'a> TableRef<'a> {
184 #[inline]
186 pub fn ptr(&self, off: u16) -> Result<Option<usize>, Error> {
187 if !self.slot_state(off, 4)? {
188 return Ok(None);
189 }
190 resolve(self.buf, self.fixed_start + off as usize)
191 }
192
193 #[inline]
194 pub fn bytes(&self, off: u16) -> Result<Option<&'a [u8]>, Error> {
195 match self.ptr(off)? {
196 Some(p) => bytes_at(self.buf, p).map(Some),
197 None => Ok(None),
198 }
199 }
200
201 #[inline]
202 pub fn str(&self, off: u16) -> Result<Option<&'a str>, Error> {
203 match self.ptr(off)? {
204 Some(p) => str_at(self.buf, p).map(Some),
205 None => Ok(None),
206 }
207 }
208
209 #[doc(hidden)]
226 #[allow(unsafe_code)]
227 #[inline]
228 pub unsafe fn str_unchecked(&self, off: u16) -> Result<Option<&'a str>, Error> {
229 match self.bytes(off)? {
230 Some(b) => Ok(Some(unsafe { core::str::from_utf8_unchecked(b) })),
232 None => Ok(None),
233 }
234 }
235
236 #[inline]
237 pub fn table(&self, off: u16) -> Result<Option<TableRef<'a>>, Error> {
238 match self.ptr(off)? {
239 Some(p) => TableRef::at(self.buf, p).map(Some),
240 None => Ok(None),
241 }
242 }
243
244 #[inline]
246 pub fn union(&self, off: u16) -> Result<Option<(u16, TableRef<'a>)>, Error> {
247 if !self.slot_state(off, 6)? {
248 return Ok(None);
249 }
250 let tag = read_at::<u16>(self.buf, self.fixed_start + off as usize)?;
251 if tag == 0 {
252 return Ok(None);
253 }
254 match resolve(self.buf, self.fixed_start + off as usize + 2)? {
255 Some(p) => Ok(Some((tag, TableRef::at(self.buf, p)?))),
256 None => Ok(None),
257 }
258 }
259
260 #[inline]
261 pub fn scalars<T: Le>(&self, off: u16) -> Result<Option<ScalarList<'a, T>>, Error> {
262 match self.ptr(off)? {
263 Some(p) => ScalarList::at(self.buf, p).map(Some),
264 None => Ok(None),
265 }
266 }
267
268 #[inline]
269 pub fn tables(&self, off: u16) -> Result<Option<TableList<'a>>, Error> {
270 match self.ptr(off)? {
271 Some(p) => TableList::at(self.buf, p).map(Some),
272 None => Ok(None),
273 }
274 }
275
276 #[inline]
277 pub fn strs(&self, off: u16) -> Result<Option<StrList<'a>>, Error> {
278 match self.ptr(off)? {
279 Some(p) => {
280 let (len, data) = counted(self.buf, p, 4)?;
281 Ok(Some(StrList { buf: self.buf, slots: data, len }))
282 }
283 None => Ok(None),
284 }
285 }
286}
287
288pub fn frames(buf: &[u8]) -> Frames<'_> {
292 Frames { buf, failed: false }
293}
294
295pub struct Frames<'a> {
296 buf: &'a [u8],
297 failed: bool,
298}
299
300impl<'a> Iterator for Frames<'a> {
301 type Item = Result<&'a [u8], Error>;
302 #[inline]
303 fn next(&mut self) -> Option<Self::Item> {
304 if self.buf.is_empty() || self.failed {
305 return None;
306 }
307 let msg = (|| {
308 let len = read_at::<u32>(self.buf, 0)? as usize;
309 let end = 4usize.checked_add(len).ok_or(Error::OutOfBounds)?;
310 let m = self.buf.get(4..end).ok_or(Error::OutOfBounds)?;
311 Ok((m, end))
312 })();
313 match msg {
314 Ok((m, end)) => {
315 self.buf = &self.buf[end..];
316 Some(Ok(m))
317 }
318 Err(e) => {
319 self.failed = true;
320 Some(Err(e))
321 }
322 }
323 }
324}
325
326#[derive(Debug, Clone, Copy)]
328pub struct ScalarList<'a, T: Le> {
329 data: &'a [u8],
330 len: usize,
331 _t: core::marker::PhantomData<T>,
332}
333
334impl<'a, T: Le> ScalarList<'a, T> {
335 pub fn at(buf: &'a [u8], pos: usize) -> Result<Self, Error> {
336 let (len, data) = counted(buf, pos, T::SIZE)?;
337 Ok(ScalarList { data: &buf[data..data + len * T::SIZE], len, _t: core::marker::PhantomData })
338 }
339 #[inline]
340 pub fn len(&self) -> usize {
341 self.len
342 }
343 #[inline]
344 pub fn is_empty(&self) -> bool {
345 self.len == 0
346 }
347 #[inline]
348 pub fn get(&self, i: usize) -> Option<T> {
349 if i >= self.len {
350 return None;
351 }
352 self.data.get(i * T::SIZE..(i + 1) * T::SIZE).map(T::read_le)
353 }
354 #[inline]
356 pub fn as_bytes(&self) -> &'a [u8] {
357 self.data
358 }
359 pub fn iter(&self) -> impl ExactSizeIterator<Item = T> + 'a
360 where
361 T: 'a,
362 {
363 self.data.chunks_exact(T::SIZE).map(T::read_le)
364 }
365}
366
367#[derive(Debug, Clone, Copy)]
369pub struct TableList<'a> {
370 buf: &'a [u8],
371 first: usize,
372 len: usize,
373 elem_fixed_len: u16,
374}
375
376impl<'a> TableList<'a> {
377 pub fn at(buf: &'a [u8], pos: usize) -> Result<Self, Error> {
378 let len = read_at::<u32>(buf, pos)? as usize;
379 let elem_fixed_len = read_at::<u16>(buf, pos.checked_add(4).ok_or(Error::OutOfBounds)?)?;
380 let first = pos + 6;
381 let bytes = len.checked_mul(elem_fixed_len as usize).ok_or(Error::OutOfBounds)?;
382 let end = first.checked_add(bytes).ok_or(Error::OutOfBounds)?;
383 if end > buf.len() {
384 return Err(Error::OutOfBounds);
385 }
386 Ok(TableList { buf, first, len, elem_fixed_len })
387 }
388 #[inline]
389 pub fn len(&self) -> usize {
390 self.len
391 }
392 #[inline]
393 pub fn is_empty(&self) -> bool {
394 self.len == 0
395 }
396 #[inline]
397 pub fn elem_fixed_len(&self) -> u16 {
398 self.elem_fixed_len
399 }
400 #[inline]
401 pub fn get(&self, i: usize) -> Result<TableRef<'a>, Error> {
402 if i >= self.len {
403 return Err(Error::OutOfBounds);
404 }
405 TableRef::inline(self.buf, self.first + i * self.elem_fixed_len as usize, self.elem_fixed_len)
406 }
407 pub fn iter(&self) -> impl ExactSizeIterator<Item = Result<TableRef<'a>, Error>> + 'a {
408 let s = *self;
409 (0..s.len).map(move |i| s.get(i))
410 }
411}
412
413#[derive(Debug, Clone, Copy)]
415pub struct StrList<'a> {
416 buf: &'a [u8],
417 slots: usize,
418 len: usize,
419}
420
421impl<'a> StrList<'a> {
422 #[inline]
423 pub fn len(&self) -> usize {
424 self.len
425 }
426 #[inline]
427 pub fn is_empty(&self) -> bool {
428 self.len == 0
429 }
430 pub fn get_bytes(&self, i: usize) -> Result<&'a [u8], Error> {
431 if i >= self.len {
432 return Err(Error::OutOfBounds);
433 }
434 match resolve(self.buf, self.slots + i * 4)? {
435 Some(p) => bytes_at(self.buf, p),
436 None => Ok(&[]),
437 }
438 }
439 pub fn get(&self, i: usize) -> Result<&'a str, Error> {
440 core::str::from_utf8(self.get_bytes(i)?).map_err(|_| Error::InvalidUtf8)
441 }
442}
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447 use crate::{Error, Le};
448
449 fn sample() -> [u8; 9] {
451 [7, 0, 0b0000_1101, 42, 0, 0, 0, 0, 0]
452 }
453
454 #[test]
455 fn reads_present_scalar() {
456 let b = sample();
457 let t = TableRef::at(&b, 0).unwrap();
458 assert_eq!(t.scalar::<u32>(1, Bit { byte: 0, shift: 0 }).unwrap(), Some(42));
459 }
460
461 #[test]
462 fn absent_bit_is_none() {
463 let b = sample();
464 let t = TableRef::at(&b, 0).unwrap();
465 assert_eq!(t.scalar::<u16>(5, Bit { byte: 0, shift: 1 }).unwrap(), None);
466 }
467
468 #[test]
469 fn bool_two_bits() {
470 let b = sample();
471 let t = TableRef::at(&b, 0).unwrap();
472 assert_eq!(t.bool(Bit { byte: 0, shift: 2 }), Some(true));
473 assert_eq!(t.bool(Bit { byte: 0, shift: 4 }), None);
474 }
475
476 #[test]
477 fn slot_beyond_fixed_len_is_none() {
478 let b = sample();
479 let t = TableRef::at(&b, 0).unwrap();
480 assert_eq!(t.scalar::<u32>(7, Bit { byte: 0, shift: 4 }).unwrap(), None);
481 }
482
483 #[test]
484 fn bit_byte_beyond_fixed_len_is_none() {
485 let b = sample();
486 let t = TableRef::at(&b, 0).unwrap();
487 assert!(!t.bit(Bit { byte: 9, shift: 0 }));
488 assert_eq!(t.scalar::<u8>(1, Bit { byte: 9, shift: 0 }).unwrap(), None);
489 }
490
491 #[test]
492 fn partial_slot_is_truncated() {
493 let b = sample();
494 let t = TableRef::at(&b, 0).unwrap();
495 assert_eq!(t.slot_state(5, 4), Err(Error::Truncated));
496 assert_eq!(t.scalar::<u32>(5, Bit { byte: 0, shift: 1 }), Err(Error::Truncated));
497 }
498
499 #[test]
500 fn header_past_end_is_err() {
501 assert_eq!(TableRef::at(&[9, 0, 1], 0).err(), Some(Error::OutOfBounds));
502 assert_eq!(TableRef::at(&[9], 0).err(), Some(Error::OutOfBounds));
503 assert_eq!(TableRef::at(&[0, 0], 5).err(), Some(Error::OutOfBounds));
504 }
505
506 #[test]
507 fn scalar_or_never_panics() {
508 let b = sample();
509 let t = TableRef::at(&b, 0).unwrap();
510 assert_eq!(t.scalar_or::<u32>(1, Bit { byte: 0, shift: 0 }, 9), 42);
511 assert_eq!(t.scalar_or::<u32>(6, Bit { byte: 0, shift: 0 }, 9), 9);
512 }
513
514 fn rt<T: Le + PartialEq + core::fmt::Debug>(v: T) {
515 let mut buf = [0u8; 16];
516 v.write_le(&mut buf[..T::SIZE]);
517 assert_eq!(T::read_le(&buf[..T::SIZE]), v);
518 }
519
520 #[test]
521 fn le_roundtrip_all_types() {
522 rt(0xABu8);
523 rt(0xABCDu16);
524 rt(0xDEADBEEFu32);
525 rt(u64::MAX - 7);
526 rt(u128::MAX - 3);
527 rt(-5i8);
528 rt(i16::MIN);
529 rt(i32::MIN);
530 rt(i64::MIN);
531 rt(i128::MIN);
532 rt(1.5f32);
533 rt(-2.25f64);
534 let mut buf = [0u8; 8];
535 f64::NAN.write_le(&mut buf);
536 assert_eq!(f64::read_le(&buf).to_bits(), f64::NAN.to_bits());
537 let mut b4 = [0u8; 4];
538 0x01020304u32.write_le(&mut b4);
539 assert_eq!(b4, [4, 3, 2, 1]);
540 }
541
542 fn table_with_ptr(rel: i32, tail: &[u8]) -> alloc::vec::Vec<u8> {
546 let mut v = alloc::vec![4, 0];
547 v.extend_from_slice(&rel.to_le_bytes());
548 v.extend_from_slice(tail);
549 v
550 }
551
552 #[test]
553 fn string_forward_offset() {
554 let b = table_with_ptr(4, &[2, 0, 0, 0, b'o', b'i']);
556 let t = TableRef::at(&b, 0).unwrap();
557 assert_eq!(t.str(0).unwrap(), Some("oi"));
558 assert_eq!(t.bytes(0).unwrap(), Some(&b"oi"[..]));
559 }
560
561 #[test]
562 fn negative_offset_into_buffer() {
563 let mut b = alloc::vec![2, 0, 0, 0, b'h', b'i'];
565 b.extend_from_slice(&[4, 0]);
566 b.extend_from_slice(&(-8i32).to_le_bytes());
567 let t = TableRef::at(&b, 6).unwrap();
568 assert_eq!(t.str(0).unwrap(), Some("hi"));
569 }
570
571 #[test]
572 fn offset_before_zero_is_bad_offset() {
573 let b = table_with_ptr(-3, &[]);
574 assert_eq!(TableRef::at(&b, 0).unwrap().ptr(0), Err(Error::BadOffset));
575 let b = table_with_ptr(i32::MIN, &[]);
576 assert_eq!(TableRef::at(&b, 0).unwrap().ptr(0), Err(Error::BadOffset));
577 }
578
579 #[test]
580 fn offset_past_end_is_bad_offset() {
581 let b = table_with_ptr(4, &[]);
582 assert_eq!(TableRef::at(&b, 0).unwrap().ptr(0), Err(Error::BadOffset));
583 let b = table_with_ptr(i32::MAX, &[]);
584 assert_eq!(TableRef::at(&b, 0).unwrap().str(0), Err(Error::BadOffset));
585 }
586
587 #[test]
588 fn len_u32_max_is_out_of_bounds() {
589 let b = table_with_ptr(4, &u32::MAX.to_le_bytes());
590 let t = TableRef::at(&b, 0).unwrap();
591 assert_eq!(t.bytes(0), Err(Error::OutOfBounds));
592 assert_eq!(t.scalars::<u64>(0).err(), Some(Error::OutOfBounds));
593 assert_eq!(t.tables(0).err(), Some(Error::OutOfBounds));
594 assert_eq!(t.strs(0).err(), Some(Error::OutOfBounds));
595 }
596
597 #[test]
598 fn invalid_utf8_is_err() {
599 let b = table_with_ptr(4, &[1, 0, 0, 0, 0xFF]);
600 assert_eq!(TableRef::at(&b, 0).unwrap().str(0), Err(Error::InvalidUtf8));
601 }
602
603 #[test]
604 fn zero_offset_is_none() {
605 let b = table_with_ptr(0, &[]);
606 let t = TableRef::at(&b, 0).unwrap();
607 assert_eq!(t.ptr(0), Ok(None));
608 assert_eq!(t.str(0), Ok(None));
609 assert!(t.table(0).unwrap().is_none());
610 assert!(t.tables(0).unwrap().is_none());
611 assert_eq!(t.ptr(4), Ok(None));
613 assert_eq!(t.ptr(2), Err(Error::Truncated));
614 }
615
616 #[test]
617 fn table_list_stride_uses_elem_fixed_len() {
618 let mut tail = alloc::vec![2, 0, 0, 0, 5, 0];
620 tail.extend_from_slice(&[1, 10, 0, 0, 0, 1, 20, 0, 0, 0]);
621 let b = table_with_ptr(4, &tail);
622 let l = TableRef::at(&b, 0).unwrap().tables(0).unwrap().unwrap();
623 assert_eq!(l.len(), 2);
624 assert_eq!(l.elem_fixed_len(), 5);
625 let p = Bit { byte: 0, shift: 0 };
626 assert_eq!(l.get(0).unwrap().scalar::<u32>(1, p).unwrap(), Some(10));
627 assert_eq!(l.get(1).unwrap().scalar::<u32>(1, p).unwrap(), Some(20));
628 assert!(l.get(2).is_err());
629 assert_eq!(l.iter().count(), 2);
630 }
631
632 #[test]
633 fn scalar_list_reads() {
634 let mut tail = alloc::vec![3, 0, 0, 0];
635 for v in [7u16, 8, 9] {
636 tail.extend_from_slice(&v.to_le_bytes());
637 }
638 let b = table_with_ptr(4, &tail);
639 let l = TableRef::at(&b, 0).unwrap().scalars::<u16>(0).unwrap().unwrap();
640 assert_eq!(l.len(), 3);
641 assert_eq!(l.get(1), Some(8));
642 assert_eq!(l.get(3), None);
643 assert_eq!(l.iter().collect::<alloc::vec::Vec<_>>(), [7, 8, 9]);
644 }
645
646 #[test]
647 fn str_list_reads() {
648 let mut tail = alloc::vec![2, 0, 0, 0];
651 tail.extend_from_slice(&8i32.to_le_bytes());
652 tail.extend_from_slice(&9i32.to_le_bytes());
653 tail.extend_from_slice(&[1, 0, 0, 0, b'a', 2, 0, 0, 0, b'b', b'c']);
654 let b = table_with_ptr(4, &tail);
655 let l = TableRef::at(&b, 0).unwrap().strs(0).unwrap().unwrap();
656 assert_eq!(l.len(), 2);
657 assert_eq!(l.get(0), Ok("a"));
658 assert_eq!(l.get(1), Ok("bc"));
659 }
660
661 #[test]
662 fn union_unknown_tag_still_returns_tag() {
663 let mut b = alloc::vec![6, 0, 99, 0];
665 b.extend_from_slice(&4i32.to_le_bytes());
666 b.extend_from_slice(&[0, 0]); let t = TableRef::at(&b, 0).unwrap();
668 let (tag, child) = t.union(0).unwrap().unwrap();
669 assert_eq!(tag, 99);
670 assert_eq!(child.fixed_len(), 0);
671 let none = [6u8, 0, 0, 0, 0, 0, 0, 0];
672 assert!(TableRef::at(&none, 0).unwrap().union(0).unwrap().is_none());
673 }
674
675 #[test]
676 fn nested_table() {
677 let b = table_with_ptr(4, &[1, 0, 0]);
678 let c = TableRef::at(&b, 0).unwrap().table(0).unwrap().unwrap();
679 assert_eq!(c.fixed_len(), 1);
680 }
681
682 #[test]
683 fn raw_reads_slot_without_presence_and_never_panics() {
684 let b = sample();
685 let t = TableRef::at(&b, 0).unwrap();
686 assert_eq!(t.raw::<u32>(1), 42);
687 assert_eq!(t.raw::<u32>(5), 0); assert_eq!(t.raw::<u64>(100), 0);
689 }
690}