1use std::cell::Cell;
8
9use crate::encode::{FLAG_INLINE_SCHEMA, HEADER_LEN, MESSAGE_MAGIC};
10use crate::error::{Error, Result};
11use crate::resolve::{
12 ElemPlan, FieldSource, Load, MapPlan, NumKind, Resolver, StructPlan, UnionPlan,
13};
14use crate::schema::{Default, Schema, StructDef};
15
16#[derive(Debug)]
40pub struct Budget {
41 remaining: Cell<u64>,
42}
43
44impl Budget {
45 pub fn new(limit: u64) -> Self {
48 Budget {
49 remaining: Cell::new(limit),
50 }
51 }
52
53 pub fn remaining(&self) -> u64 {
55 self.remaining.get()
56 }
57
58 #[inline]
62 pub fn charge(&self, bytes: u64) -> Result<()> {
63 match self.remaining.get().checked_sub(bytes) {
64 Some(rem) => {
65 self.remaining.set(rem);
66 Ok(())
67 }
68 None => Err(Error::TraversalBudgetExceeded),
69 }
70 }
71}
72
73#[inline]
74fn charge(budget: Option<&Budget>, bytes: u64) -> Result<()> {
75 match budget {
76 Some(b) => b.charge(bytes),
77 None => Ok(()),
78 }
79}
80
81#[derive(Clone, Debug)]
82pub struct Message<'b> {
83 buf: &'b [u8],
84 schema_id: u128,
85 root_offset: u32,
86 schema_range: Option<(usize, usize)>,
87}
88
89impl<'b> Message<'b> {
90 pub fn parse(buf: &'b [u8]) -> Result<Message<'b>> {
91 if buf.len() < HEADER_LEN {
92 return Err(Error::Truncated);
93 }
94 if &buf[0..4] != MESSAGE_MAGIC {
98 if buf[0..3] == MESSAGE_MAGIC[0..3] {
99 return Err(Error::UnsupportedVersion {
100 found: buf[3],
101 supported: MESSAGE_MAGIC[3],
102 });
103 }
104 return Err(Error::BadMagic);
105 }
106 let flags = u16::from_le_bytes(buf[4..6].try_into().unwrap());
107 if flags & !FLAG_INLINE_SCHEMA != 0 {
111 return Err(Error::MalformedHeader("unknown flag bit set"));
112 }
113 let reserved = u16::from_le_bytes(buf[6..8].try_into().unwrap());
114 if reserved != 0 {
115 return Err(Error::MalformedHeader("reserved header field is not zero"));
116 }
117 let schema_id = u128::from_le_bytes(buf[8..24].try_into().unwrap());
118 let root_offset = u32::from_le_bytes(buf[24..28].try_into().unwrap());
119 let schema_len = u32::from_le_bytes(buf[28..32].try_into().unwrap()) as usize;
120 let schema_range = if flags & FLAG_INLINE_SCHEMA != 0 {
121 let end = HEADER_LEN.checked_add(schema_len).ok_or(Error::Truncated)?;
122 if end > buf.len() {
123 return Err(Error::Truncated);
124 }
125 Some((HEADER_LEN, end))
126 } else {
127 None
128 };
129 Ok(Message {
130 buf,
131 schema_id,
132 root_offset,
133 schema_range,
134 })
135 }
136
137 pub fn buffer(&self) -> &'b [u8] {
138 self.buf
139 }
140
141 pub fn schema_id(&self) -> u128 {
142 self.schema_id
143 }
144
145 pub fn root_offset(&self) -> u32 {
148 self.root_offset
149 }
150
151 pub fn has_inline_schema(&self) -> bool {
152 self.schema_range.is_some()
153 }
154
155 pub fn writer_schema(&self) -> Result<Option<Schema>> {
158 match self.schema_range {
159 None => Ok(None),
160 Some((start, end)) => {
161 let schema = Schema::from_canonical(&self.buf[start..end])?;
162 if schema.id() != self.schema_id {
163 return Err(Error::SchemaIdMismatch {
164 message: self.schema_id,
165 expected: schema.id(),
166 });
167 }
168 Ok(Some(schema))
169 }
170 }
171 }
172
173 pub fn root<'r>(&self, resolver: &'r Resolver) -> Result<StructReader<'b, 'r>> {
178 self.open_root(resolver, None)
179 }
180
181 pub fn root_bounded<'r>(
186 &self,
187 resolver: &'r Resolver,
188 budget: &'r Budget,
189 ) -> Result<StructReader<'b, 'r>> {
190 self.open_root(resolver, Some(budget))
191 }
192
193 pub fn verify(&self, resolver: &Resolver, budget: &Budget) -> Result<()> {
203 let root = self.root_bounded(resolver, budget)?;
204 verify_struct(&root, 0)
205 }
206
207 pub fn suggested_budget(&self) -> u64 {
212 (self.buf.len() as u64).saturating_mul(64).max(64 * 1024)
213 }
214
215 fn open_root<'r>(
216 &self,
217 resolver: &'r Resolver,
218 budget: Option<&'r Budget>,
219 ) -> Result<StructReader<'b, 'r>> {
220 if resolver.writer_id() != self.schema_id {
221 return Err(Error::SchemaIdMismatch {
222 message: self.schema_id,
223 expected: resolver.writer_id(),
224 });
225 }
226 Ok(StructReader {
227 buf: self.buf,
228 base: self.root_offset,
229 plan: resolver.plan(resolver.root_plan_index()),
230 resolver,
231 budget,
232 })
233 }
234}
235
236#[derive(Clone, Debug)]
239pub enum Ref<'b, 'r> {
240 Bool(bool),
241 U8(u8),
242 U16(u16),
243 U32(u32),
244 U64(u64),
245 I8(i8),
246 I16(i16),
247 I32(i32),
248 I64(i64),
249 F32(f32),
250 F64(f64),
251 Str(&'b str),
252 Bytes(&'b [u8]),
253 Enum(u32),
254 Struct(StructReader<'b, 'r>),
255 List(ListReader<'b, 'r>),
256 Map(MapReader<'b, 'r>),
257 Union(UnionReader<'b, 'r>),
258}
259
260impl<'b, 'r> Ref<'b, 'r> {
261 pub fn kind(&self) -> &'static str {
262 match self {
263 Ref::Bool(_) => "bool",
264 Ref::U8(_) => "u8",
265 Ref::U16(_) => "u16",
266 Ref::U32(_) => "u32",
267 Ref::U64(_) => "u64",
268 Ref::I8(_) => "i8",
269 Ref::I16(_) => "i16",
270 Ref::I32(_) => "i32",
271 Ref::I64(_) => "i64",
272 Ref::F32(_) => "f32",
273 Ref::F64(_) => "f64",
274 Ref::Str(_) => "string",
275 Ref::Bytes(_) => "bytes",
276 Ref::Enum(_) => "enum",
277 Ref::Struct(_) => "struct",
278 Ref::List(_) => "list",
279 Ref::Map(_) => "map",
280 Ref::Union(_) => "union",
281 }
282 }
283}
284
285#[derive(Clone, Debug)]
286pub struct StructReader<'b, 'r> {
287 buf: &'b [u8],
288 base: u32,
289 plan: &'r StructPlan,
290 resolver: &'r Resolver,
291 budget: Option<&'r Budget>,
294}
295
296macro_rules! typed_getter {
297 ($doc:literal, $name:ident, $variant:ident, $ret:ty) => {
298 #[doc = $doc]
299 pub fn $name(&self, id: u16) -> Result<Option<$ret>> {
300 match self.get(id)? {
301 None => Ok(None),
302 Some(Ref::$variant(x)) => Ok(Some(x)),
303 Some(other) => Err(Error::TypeMismatch {
304 expected: stringify!($variant).to_lowercase(),
305 got: other.kind().into(),
306 }),
307 }
308 }
309 };
310}
311
312impl<'b, 'r> StructReader<'b, 'r> {
313 pub fn get(&self, id: u16) -> Result<Option<Ref<'b, 'r>>> {
316 let pos = match self.plan.fields.binary_search_by_key(&id, |f| f.id) {
317 Ok(pos) => pos,
318 Err(_) => return Err(Error::UnknownFieldId(id)),
319 };
320 match &self.plan.fields[pos].source {
321 FieldSource::Absent => Ok(None),
322 FieldSource::Slot {
323 offset,
324 presence_byte,
325 presence_mask,
326 load,
327 } => {
328 if *presence_mask != 0 {
330 let pbyte = read_u8(
331 self.buf,
332 self.base as u64 + *presence_byte as u64,
333 self.budget,
334 )?;
335 if pbyte & presence_mask == 0 {
336 return Ok(None);
337 }
338 }
339 let at = self.base as u64 + *offset as u64;
340 load_at(self.buf, self.resolver, load, at, self.budget).map(Some)
341 }
342 FieldSource::Packed { writer_pos, load } => {
343 let lay = self
346 .resolver
347 .writer_schema()
348 .packed_layout_unchecked(self.plan.writer_type);
349 let bitmap =
350 read_bitmap(self.buf, self.base as u64, lay.bitmap_bytes, self.budget)?;
351 if bitmap & (1u64 << writer_pos) == 0 {
352 return Ok(None);
353 }
354 let at = self.base as u64 + lay.field_offset(bitmap, *writer_pos as usize) as u64;
355 load_at(self.buf, self.resolver, load, at, self.budget).map(Some)
356 }
357 }
358 }
359
360 pub fn get_or_default(&self, id: u16) -> Result<Option<Ref<'b, 'r>>> {
365 if let Some(v) = self.get(id)? {
366 return Ok(Some(v));
367 }
368 Ok(self
369 .struct_def()
370 .fields
371 .iter()
372 .find(|f| f.id == id)
373 .and_then(|f| f.default)
374 .map(default_to_ref))
375 }
376
377 pub fn struct_def(&self) -> &'r StructDef {
380 self.resolver
381 .reader_schema()
382 .struct_def_unchecked(self.plan.reader_type)
383 }
384
385 typed_getter!("Typed getter for `bool` fields.", get_bool, Bool, bool);
386 typed_getter!("Typed getter for `u8` fields.", get_u8, U8, u8);
387 typed_getter!("Typed getter for `u16` fields.", get_u16, U16, u16);
388 typed_getter!("Typed getter for `u32` fields.", get_u32, U32, u32);
389 typed_getter!("Typed getter for `u64` fields.", get_u64, U64, u64);
390 typed_getter!("Typed getter for `i8` fields.", get_i8, I8, i8);
391 typed_getter!("Typed getter for `i16` fields.", get_i16, I16, i16);
392 typed_getter!("Typed getter for `i32` fields.", get_i32, I32, i32);
393 typed_getter!("Typed getter for `i64` fields.", get_i64, I64, i64);
394 typed_getter!("Typed getter for `f32` fields.", get_f32, F32, f32);
395 typed_getter!("Typed getter for `f64` fields.", get_f64, F64, f64);
396 typed_getter!(
397 "Typed getter for string fields (borrows the buffer).",
398 get_str,
399 Str,
400 &'b str
401 );
402 typed_getter!(
403 "Typed getter for bytes fields (borrows the buffer).",
404 get_bytes,
405 Bytes,
406 &'b [u8]
407 );
408 typed_getter!(
409 "Typed getter for enum fields (raw open value).",
410 get_enum,
411 Enum,
412 u32
413 );
414 typed_getter!(
415 "Typed getter for nested struct fields.",
416 get_struct,
417 Struct,
418 StructReader<'b, 'r>
419 );
420 typed_getter!(
421 "Typed getter for list fields.",
422 get_list,
423 List,
424 ListReader<'b, 'r>
425 );
426 typed_getter!(
427 "Typed getter for map fields.",
428 get_map,
429 Map,
430 MapReader<'b, 'r>
431 );
432 typed_getter!(
433 "Typed getter for union fields.",
434 get_union,
435 Union,
436 UnionReader<'b, 'r>
437 );
438}
439
440#[derive(Clone, Debug)]
441pub struct ListReader<'b, 'r> {
442 buf: &'b [u8],
443 resolver: &'r Resolver,
444 elem: &'r ElemPlan,
445 elems_base: u64,
446 count: u32,
447 budget: Option<&'r Budget>,
448}
449
450impl<'b, 'r> ListReader<'b, 'r> {
451 pub fn len(&self) -> u32 {
452 self.count
453 }
454
455 pub fn is_empty(&self) -> bool {
456 self.count == 0
457 }
458
459 pub fn get(&self, index: u32) -> Result<Ref<'b, 'r>> {
460 if index >= self.count {
461 return Err(Error::IndexOutOfBounds);
462 }
463 let at = self.elems_base + index as u64 * self.elem.stride as u64;
464 match &self.elem.load {
465 Load::Struct(plan_idx) if self.elem.struct_inline => {
470 let base = u32::try_from(at).map_err(|_| Error::OutOfBounds)?;
471 Ok(Ref::Struct(StructReader {
472 buf: self.buf,
473 base,
474 plan: self.resolver.plan(*plan_idx),
475 resolver: self.resolver,
476 budget: self.budget,
477 }))
478 }
479 other => load_at(self.buf, self.resolver, other, at, self.budget),
480 }
481 }
482
483 pub fn iter(&self) -> impl Iterator<Item = Result<Ref<'b, 'r>>> + '_ {
484 (0..self.count).map(move |i| self.get(i))
485 }
486
487 pub fn as_u8_slice(&self) -> Result<&'b [u8]> {
495 match &self.elem.load {
496 Load::Num {
497 from: NumKind::U8,
498 to: NumKind::U8,
499 } if self.elem.stride == 1 => {
500 get_slice(self.buf, self.elems_base, self.count as u64, self.budget)
501 }
502 other => Err(Error::TypeMismatch {
503 expected: "list<u8>".into(),
504 got: elem_kind(other).into(),
505 }),
506 }
507 }
508}
509
510fn elem_kind(load: &Load) -> &'static str {
512 match load {
513 Load::Bool => "list<bool>",
514 Load::Num { to, .. } => match to {
515 NumKind::U8 => "list<u8>",
516 NumKind::U16 => "list<u16>",
517 NumKind::U32 => "list<u32>",
518 NumKind::U64 => "list<u64>",
519 NumKind::I8 => "list<i8>",
520 NumKind::I16 => "list<i16>",
521 NumKind::I32 => "list<i32>",
522 NumKind::I64 => "list<i64>",
523 NumKind::F32 => "list<f32>",
524 NumKind::F64 => "list<f64>",
525 },
526 Load::Enum => "list<enum>",
527 Load::Str => "list<string>",
528 Load::Bytes => "list<bytes>",
529 Load::Struct(_) => "list<struct>",
530 Load::List(_) => "list<list>",
531 Load::Map(_) => "list<map>",
532 Load::Union(_) => "list<union>",
533 }
534}
535
536macro_rules! bulk_num {
549 ($ty:ty, $kind:ident, $variant:ident, $copy:ident, $to_vec:ident, $name:literal) => {
550 impl<'b, 'r> ListReader<'b, 'r> {
551 #[doc = concat!("Bulk-copy a `", $name, "` list into `out`, returning how many elements were written.")]
552 pub fn $copy(&self, out: &mut [$ty]) -> Result<usize> {
556 const WIDTH: usize = std::mem::size_of::<$ty>();
557 let Load::Num { from, to } = &self.elem.load else {
558 return Err(Error::TypeMismatch {
559 expected: concat!("list<", $name, ">").into(),
560 got: elem_kind(&self.elem.load).into(),
561 });
562 };
563 if *to != NumKind::$kind {
564 return Err(Error::TypeMismatch {
565 expected: concat!("list<", $name, ">").into(),
566 got: elem_kind(&self.elem.load).into(),
567 });
568 }
569 let n = (self.count as usize).min(out.len());
570 if n == 0 {
571 return Ok(0);
572 }
573
574 if *from == NumKind::$kind && self.elem.stride as usize == WIDTH {
578 let span = (n as u64) * WIDTH as u64;
579 let bytes = get_slice(self.buf, self.elems_base, span, self.budget)?;
580 for (slot, chunk) in out.iter_mut().zip(bytes.chunks_exact(WIDTH)) {
581 *slot = <$ty>::from_le_bytes(chunk.try_into().unwrap());
582 }
583 return Ok(n);
584 }
585
586 for (i, slot) in out.iter_mut().enumerate().take(n) {
589 let at = self.elems_base + i as u64 * self.elem.stride as u64;
590 *slot = match num_ref(*to, read_wide(self.buf, at, *from, self.budget)?)? {
591 Ref::$variant(x) => x,
592 _ => return Err(Error::Internal("num kind mismatch in bulk list read")),
593 };
594 }
595 Ok(n)
596 }
597
598 #[doc = concat!("Read a whole `", $name, "` list into a new `Vec`.")]
599 #[doc = concat!("[`", stringify!($copy), "`](Self::", stringify!($copy), ")")]
602 pub fn $to_vec(&self) -> Result<Vec<$ty>> {
604 let span = (self.count as u64)
609 .checked_mul(self.elem.stride as u64)
610 .ok_or(Error::OutOfBounds)?;
611 get_slice(self.buf, self.elems_base, span, None)?;
612
613 let mut out: Vec<$ty> = Vec::new();
614 out.try_reserve_exact(self.count as usize)
615 .map_err(|_| Error::OutOfBounds)?;
616 out.resize(self.count as usize, <$ty>::default());
617 let n = self.$copy(&mut out)?;
618 out.truncate(n);
619 Ok(out)
620 }
621 }
622 };
623}
624
625bulk_num!(u8, U8, U8, copy_u8, to_vec_u8, "u8");
626bulk_num!(u16, U16, U16, copy_u16, to_vec_u16, "u16");
627bulk_num!(u32, U32, U32, copy_u32, to_vec_u32, "u32");
628bulk_num!(u64, U64, U64, copy_u64, to_vec_u64, "u64");
629bulk_num!(i8, I8, I8, copy_i8, to_vec_i8, "i8");
630bulk_num!(i16, I16, I16, copy_i16, to_vec_i16, "i16");
631bulk_num!(i32, I32, I32, copy_i32, to_vec_i32, "i32");
632bulk_num!(i64, I64, I64, copy_i64, to_vec_i64, "i64");
633bulk_num!(f32, F32, F32, copy_f32, to_vec_f32, "f32");
634bulk_num!(f64, F64, F64, copy_f64, to_vec_f64, "f64");
635
636#[derive(Clone, Debug)]
639pub struct MapReader<'b, 'r> {
640 buf: &'b [u8],
641 resolver: &'r Resolver,
642 plan: &'r MapPlan,
643 entries_base: u64,
644 count: u32,
645 budget: Option<&'r Budget>,
646}
647
648impl<'b, 'r> MapReader<'b, 'r> {
649 pub fn len(&self) -> u32 {
650 self.count
651 }
652
653 pub fn is_empty(&self) -> bool {
654 self.count == 0
655 }
656
657 pub fn get(&self, index: u32) -> Result<(Ref<'b, 'r>, Ref<'b, 'r>)> {
659 if index >= self.count {
660 return Err(Error::IndexOutOfBounds);
661 }
662 let entry = self.entries_base + index as u64 * self.plan.stride as u64;
663 let key = load_at(
664 self.buf,
665 self.resolver,
666 &self.plan.key,
667 entry + self.plan.key_off as u64,
668 self.budget,
669 )?;
670 let value = load_at(
671 self.buf,
672 self.resolver,
673 &self.plan.value,
674 entry + self.plan.value_off as u64,
675 self.budget,
676 )?;
677 Ok((key, value))
678 }
679
680 pub fn iter(&self) -> impl Iterator<Item = Result<(Ref<'b, 'r>, Ref<'b, 'r>)>> + '_ {
681 (0..self.count).map(move |i| self.get(i))
682 }
683}
684
685#[derive(Clone, Debug)]
688pub struct UnionReader<'b, 'r> {
689 buf: &'b [u8],
690 resolver: &'r Resolver,
691 plan: &'r UnionPlan,
692 base: u64,
693 tag: u32,
694 budget: Option<&'r Budget>,
695}
696
697impl<'b, 'r> UnionReader<'b, 'r> {
698 pub fn tag(&self) -> u32 {
700 self.tag
701 }
702
703 pub fn value(&self) -> Result<Ref<'b, 'r>> {
706 let vp = self
707 .plan
708 .variants
709 .get(self.tag as usize)
710 .ok_or(Error::BadUnionTag(self.tag))?;
711 load_at(
712 self.buf,
713 self.resolver,
714 &vp.load,
715 self.base + vp.payload_off as u64,
716 self.budget,
717 )
718 }
719}
720
721fn default_to_ref<'b, 'r>(d: Default) -> Ref<'b, 'r> {
724 match d {
725 Default::Bool(x) => Ref::Bool(x),
726 Default::U8(x) => Ref::U8(x),
727 Default::U16(x) => Ref::U16(x),
728 Default::U32(x) => Ref::U32(x),
729 Default::U64(x) => Ref::U64(x),
730 Default::I8(x) => Ref::I8(x),
731 Default::I16(x) => Ref::I16(x),
732 Default::I32(x) => Ref::I32(x),
733 Default::I64(x) => Ref::I64(x),
734 Default::F32(bits) => Ref::F32(f32::from_bits(bits)),
735 Default::F64(bits) => Ref::F64(f64::from_bits(bits)),
736 Default::Enum(x) => Ref::Enum(x),
737 }
738}
739
740const MAX_VERIFY_DEPTH: u32 = 128;
744
745fn verify_struct(sr: &StructReader, depth: u32) -> Result<()> {
746 if depth > MAX_VERIFY_DEPTH {
747 return Err(Error::DepthLimitExceeded);
748 }
749 let ids: Vec<u16> = sr.struct_def().fields.iter().map(|f| f.id).collect();
752 for id in ids {
753 if let Some(v) = sr.get(id)? {
754 verify_ref(&v, depth)?;
755 }
756 }
757 Ok(())
758}
759
760fn verify_ref(v: &Ref, depth: u32) -> Result<()> {
761 match v {
762 Ref::Struct(s) => verify_struct(s, depth + 1),
763 Ref::List(l) => {
764 for i in 0..l.len() {
765 verify_ref(&l.get(i)?, depth + 1)?;
766 }
767 Ok(())
768 }
769 Ref::Map(m) => {
770 for i in 0..m.len() {
771 let (k, v) = m.get(i)?;
772 verify_ref(&k, depth + 1)?;
773 verify_ref(&v, depth + 1)?;
774 }
775 Ok(())
776 }
777 Ref::Union(u) => verify_ref(&u.value()?, depth + 1),
778 _ => Ok(()),
779 }
780}
781
782fn get_slice<'b>(buf: &'b [u8], off: u64, len: u64, budget: Option<&Budget>) -> Result<&'b [u8]> {
791 charge(budget, len)?;
792 let start = usize::try_from(off).map_err(|_| Error::OutOfBounds)?;
793 let len = usize::try_from(len).map_err(|_| Error::OutOfBounds)?;
794 let end = start.checked_add(len).ok_or(Error::OutOfBounds)?;
795 buf.get(start..end).ok_or(Error::OutOfBounds)
796}
797
798fn read_u8(buf: &[u8], off: u64, budget: Option<&Budget>) -> Result<u8> {
799 Ok(get_slice(buf, off, 1, budget)?[0])
800}
801
802fn read_bitmap(buf: &[u8], base: u64, bitmap_bytes: u32, budget: Option<&Budget>) -> Result<u64> {
807 if bitmap_bytes > 8 {
808 return Err(Error::Internal("packed bitmap wider than 8 bytes"));
809 }
810 let bytes = get_slice(buf, base, bitmap_bytes as u64, budget)?;
811 let mut word = [0u8; 8];
812 word[..bytes.len()].copy_from_slice(bytes);
813 Ok(u64::from_le_bytes(word))
814}
815
816fn read_u32(buf: &[u8], off: u64, budget: Option<&Budget>) -> Result<u32> {
817 Ok(u32::from_le_bytes(
818 get_slice(buf, off, 4, budget)?.try_into().unwrap(),
819 ))
820}
821
822enum Wide {
823 U(u64),
824 I(i64),
825 F(f64),
826}
827
828fn read_wide(buf: &[u8], at: u64, kind: NumKind, budget: Option<&Budget>) -> Result<Wide> {
829 Ok(match kind {
830 NumKind::U8 => Wide::U(read_u8(buf, at, budget)? as u64),
831 NumKind::U16 => {
832 Wide::U(u16::from_le_bytes(get_slice(buf, at, 2, budget)?.try_into().unwrap()) as u64)
833 }
834 NumKind::U32 => Wide::U(read_u32(buf, at, budget)? as u64),
835 NumKind::U64 => Wide::U(u64::from_le_bytes(
836 get_slice(buf, at, 8, budget)?.try_into().unwrap(),
837 )),
838 NumKind::I8 => Wide::I(read_u8(buf, at, budget)? as i8 as i64),
839 NumKind::I16 => {
840 Wide::I(i16::from_le_bytes(get_slice(buf, at, 2, budget)?.try_into().unwrap()) as i64)
841 }
842 NumKind::I32 => {
843 Wide::I(i32::from_le_bytes(get_slice(buf, at, 4, budget)?.try_into().unwrap()) as i64)
844 }
845 NumKind::I64 => Wide::I(i64::from_le_bytes(
846 get_slice(buf, at, 8, budget)?.try_into().unwrap(),
847 )),
848 NumKind::F32 => {
849 Wide::F(f32::from_le_bytes(get_slice(buf, at, 4, budget)?.try_into().unwrap()) as f64)
850 }
851 NumKind::F64 => Wide::F(f64::from_le_bytes(
852 get_slice(buf, at, 8, budget)?.try_into().unwrap(),
853 )),
854 })
855}
856
857fn num_ref<'b, 'r>(to: NumKind, wide: Wide) -> Result<Ref<'b, 'r>> {
858 Ok(match (to, wide) {
859 (NumKind::U8, Wide::U(x)) => Ref::U8(x as u8),
860 (NumKind::U16, Wide::U(x)) => Ref::U16(x as u16),
861 (NumKind::U32, Wide::U(x)) => Ref::U32(x as u32),
862 (NumKind::U64, Wide::U(x)) => Ref::U64(x),
863 (NumKind::I8, Wide::I(x)) => Ref::I8(x as i8),
864 (NumKind::I16, Wide::I(x)) => Ref::I16(x as i16),
865 (NumKind::I32, Wide::I(x)) => Ref::I32(x as i32),
866 (NumKind::I64, Wide::I(x)) => Ref::I64(x),
867 (NumKind::F32, Wide::F(x)) => Ref::F32(x as f32),
868 (NumKind::F64, Wide::F(x)) => Ref::F64(x),
869 _ => return Err(Error::Internal("num kind mismatch in access plan")),
870 })
871}
872
873fn load_at<'b, 'r>(
876 buf: &'b [u8],
877 resolver: &'r Resolver,
878 load: &'r Load,
879 at: u64,
880 budget: Option<&'r Budget>,
881) -> Result<Ref<'b, 'r>> {
882 match load {
883 Load::Bool => Ok(Ref::Bool(read_u8(buf, at, budget)? != 0)),
884 Load::Num { from, to } => num_ref(*to, read_wide(buf, at, *from, budget)?),
885 Load::Enum => Ok(Ref::Enum(read_u32(buf, at, budget)?)),
886 Load::Str => {
887 let off = read_u32(buf, at, budget)? as u64;
888 let len = read_u32(buf, off, budget)? as u64;
889 let bytes = get_slice(buf, off + 4, len, budget)?;
890 let s = std::str::from_utf8(bytes).map_err(|_| Error::BadUtf8)?;
891 Ok(Ref::Str(s))
892 }
893 Load::Bytes => {
894 let off = read_u32(buf, at, budget)? as u64;
895 let len = read_u32(buf, off, budget)? as u64;
896 Ok(Ref::Bytes(get_slice(buf, off + 4, len, budget)?))
897 }
898 Load::Struct(plan_idx) => {
899 let off = read_u32(buf, at, budget)?;
900 Ok(Ref::Struct(StructReader {
901 buf,
902 base: off,
903 plan: resolver.plan(*plan_idx),
904 resolver,
905 budget,
906 }))
907 }
908 Load::List(elem) => {
909 let off = read_u32(buf, at, budget)?;
910 let count = read_u32(buf, off as u64, budget)?;
911 let x = off as u64 + 4;
914 let a = elem.align as u64;
915 let elems_base = (x + a - 1) & !(a - 1);
916 Ok(Ref::List(ListReader {
917 buf,
918 resolver,
919 elem,
920 elems_base,
921 count,
922 budget,
923 }))
924 }
925 Load::Map(plan) => {
926 let off = read_u32(buf, at, budget)?;
927 let count = read_u32(buf, off as u64, budget)?;
928 let x = off as u64 + 4;
929 let a = plan.align as u64;
930 let entries_base = (x + a - 1) & !(a - 1);
931 Ok(Ref::Map(MapReader {
932 buf,
933 resolver,
934 plan,
935 entries_base,
936 count,
937 budget,
938 }))
939 }
940 Load::Union(plan) => {
941 let off = read_u32(buf, at, budget)? as u64;
942 let tag = read_u32(buf, off, budget)?;
943 Ok(Ref::Union(UnionReader {
944 buf,
945 resolver,
946 plan,
947 base: off,
948 tag,
949 budget,
950 }))
951 }
952 }
953}