lutra_bin/value/
decode.rs1use crate::value::TyClass;
2use crate::{boxed, string, vec};
3
4use bytes::Buf;
5
6use super::Value;
7use super::encode::Context;
8
9use crate::ir;
10use crate::layout::{self, 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 TyClass::PrimText => {
36 let res = string::String::decode(r.chunk())?;
37 r.advance(string::String::head_size().div_ceil(8));
38 Value::Text(res)
39 }
40
41 TyClass::Tuple(fields) => {
42 let mut res = vec::Vec::with_capacity(fields.len());
43 for field in fields {
44 res.push(decode_inner(r, &field.ty, ctx)?);
45 }
46 Value::Tuple(res)
47 }
48 TyClass::Array(item_ty) => {
49 let mut body = r.clone();
50
51 let (offset, len) = ArrayReader::<&[u8]>::read_head(r.chunk());
52 r.advance(8);
53
54 body.advance(offset);
55
56 let mut buf = vec::Vec::with_capacity(len);
57 for _ in 0..len {
58 buf.push(decode_inner(&mut body, item_ty, ctx)?);
59 }
60
61 Value::Array(buf)
62 }
63
64 TyClass::Enum(variants) => {
65 let head = layout::enum_head_format(variants, &ty.variants_recursive);
66
67 let mut tag_bytes = vec![0; 8];
68 r.copy_to_slice(&mut tag_bytes[0..head.tag_bytes as usize]);
69 tag_bytes.resize(8, 0);
70 let tag = u64::from_le_bytes(tag_bytes.try_into().unwrap()) as usize;
71
72 let variant = variants.get(tag).unwrap();
73
74 let variant_format = layout::enum_variant_format(&head, &variant.ty);
75
76 let inner = if head.has_ptr {
77 if variant_format.is_unit {
78 Value::Tuple(vec![])
80 } else {
81 let mut body = r.clone();
82 body.advance(r.get_u32_le() as usize);
83 decode_inner(&mut body, &variant.ty, ctx)?
84 }
85 } else {
86 decode_inner(r, &variant.ty, ctx)?
87 };
88
89 r.advance(variant_format.padding_bytes as usize);
90 Value::Enum(tag, boxed::Box::new(inner))
91 }
92 })
93}
94
95fn decode<D: Decode + Sized>(reader: &mut impl bytes::Buf) -> Result<D> {
96 let res = D::decode(reader.chunk());
97 reader.advance(D::head_size().div_ceil(8));
98 res
99}