lutra_bin/value/
decode.rs1use crate::value::TyClass;
2use crate::{boxed, vec};
3
4use bytes::Buf;
5
6use super::Value;
7use super::encode::Context;
8
9use crate::ir;
10use crate::layout;
11use crate::{ArrayReader, Decode, Result};
12
13impl Value {
14 pub fn decode(buf: &[u8], ty: &ir::Ty, ty_defs: &[ir::TyDef]) -> Result<Value> {
16 let mut ctx = Context::new(ty_defs);
17
18 let mut buf = buf;
19 decode_inner(&mut buf, ty, &mut ctx)
20 }
21}
22
23fn decode_inner<'t>(
24 r: &mut (impl bytes::Buf + Clone),
25 ty: &'t ir::Ty,
26 ctx: &mut Context<'t>,
27) -> Result<Value> {
28 let ty = ctx.get_mat_ty(ty);
29
30 Ok(match TyClass::of_ty(ty)? {
31 TyClass::Prim8 => Value::Prim8(decode::<u8>(r)?),
32 TyClass::Prim16 => Value::Prim16(decode::<u16>(r)?),
33 TyClass::Prim32 => Value::Prim32(decode::<u32>(r)?),
34 TyClass::Prim64 => Value::Prim64(decode::<u64>(r)?),
35
36 TyClass::Tuple(fields) => {
37 let mut res = vec::Vec::with_capacity(fields.len());
38 for field in fields {
39 res.push(decode_inner(r, &field.ty, ctx)?);
40 }
41 Value::Tuple(res)
42 }
43 TyClass::Array(item_ty) => {
44 let mut body = r.clone();
45
46 let (offset, len) = ArrayReader::<&[u8]>::read_head(r.chunk());
47 r.advance(8);
48
49 body.advance(offset);
50
51 let mut buf = vec::Vec::with_capacity(len);
52 for _ in 0..len {
53 buf.push(decode_inner(&mut body, item_ty, ctx)?);
54 }
55
56 Value::Array(buf)
57 }
58
59 TyClass::Enum(variants) => {
60 let head = layout::enum_head_format(variants, &ty.variants_recursive);
61
62 let mut tag_bytes = vec![0; 8];
63 r.copy_to_slice(&mut tag_bytes[0..head.tag_bytes as usize]);
64 tag_bytes.resize(8, 0);
65 let tag = u64::from_le_bytes(tag_bytes.try_into().unwrap()) as usize;
66
67 let variant = variants.get(tag).unwrap();
68
69 let variant_format = layout::enum_variant_format(&head, &variant.ty);
70
71 let inner = if head.has_ptr {
72 if variant_format.is_unit {
73 Value::Tuple(vec![])
75 } else {
76 let mut body = r.clone();
77 body.advance(r.get_u32_le() as usize);
78 decode_inner(&mut body, &variant.ty, ctx)?
79 }
80 } else {
81 decode_inner(r, &variant.ty, ctx)?
82 };
83
84 r.advance(variant_format.padding_bytes as usize);
85 Value::Enum(tag, boxed::Box::new(inner))
86 }
87 })
88}
89
90fn decode<D: Decode + Sized>(reader: &mut impl bytes::Buf) -> Result<D> {
91 let res = D::decode(reader.chunk());
92 reader.advance(D::head_size().div_ceil(8));
93 res
94}