Skip to main content

lutra_bin/value/
decode.rs

1use 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    /// Convert .ld binary encoding into Lutra [Value].
15    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                    // unit variant
79                    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}