Skip to main content

lutra_bin/
visitor.rs

1use crate::vec;
2
3use crate::ArrayReader;
4use crate::Decode;
5use crate::Error;
6use crate::TupleReader;
7use crate::ir;
8use crate::layout;
9
10pub trait Visitor<'t, B>
11where
12    B: bytes::Buf + Clone,
13{
14    type Res;
15
16    fn get_ty(&self, name: &ir::Path) -> &'t ir::Ty;
17
18    fn get_mat_ty(&self, ty: &'t ir::Ty) -> &'t ir::Ty {
19        let mut ty = ty;
20        while let ir::TyKind::Ident(name) = &ty.kind {
21            ty = self.get_ty(name);
22        }
23        ty
24    }
25
26    fn visit(&mut self, buf: B, ty: &'t ir::Ty) -> Result<Self::Res, crate::Error> {
27        let ty = self.get_mat_ty(ty);
28
29        self.visit_concrete(buf, ty)
30    }
31
32    fn visit_concrete(&mut self, buf: B, ty: &'t ir::Ty) -> Result<Self::Res, crate::Error> {
33        match &ty.kind {
34            ir::TyKind::Primitive(ir::TyPrimitive::bool) => {
35                self.visit_bool(bool::decode(buf.chunk())?)
36            }
37            ir::TyKind::Primitive(ir::TyPrimitive::int8) => {
38                self.visit_int8(i8::decode(buf.chunk())?)
39            }
40            ir::TyKind::Primitive(ir::TyPrimitive::uint8) => {
41                self.visit_uint8(u8::decode(buf.chunk())?)
42            }
43            ir::TyKind::Primitive(ir::TyPrimitive::int16) => {
44                self.visit_int16(i16::decode(buf.chunk())?)
45            }
46            ir::TyKind::Primitive(ir::TyPrimitive::uint16) => {
47                self.visit_uint16(u16::decode(buf.chunk())?)
48            }
49            ir::TyKind::Primitive(ir::TyPrimitive::int32) => {
50                self.visit_int32(i32::decode(buf.chunk())?)
51            }
52            ir::TyKind::Primitive(ir::TyPrimitive::uint32) => {
53                self.visit_uint32(u32::decode(buf.chunk())?)
54            }
55            ir::TyKind::Primitive(ir::TyPrimitive::float32) => {
56                self.visit_float32(f32::decode(buf.chunk())?)
57            }
58            ir::TyKind::Primitive(ir::TyPrimitive::int64) => {
59                self.visit_int64(i64::decode(buf.chunk())?)
60            }
61            ir::TyKind::Primitive(ir::TyPrimitive::uint64) => {
62                self.visit_uint64(u64::decode(buf.chunk())?)
63            }
64            ir::TyKind::Primitive(ir::TyPrimitive::float64) => {
65                self.visit_float64(f64::decode(buf.chunk())?)
66            }
67            ir::TyKind::Primitive(ir::TyPrimitive::text) => {
68                let (offset, len) = ArrayReader::<&[u8]>::read_head(buf.chunk());
69
70                let mut buf = buf;
71                buf.advance(offset);
72
73                self.visit_text(buf, len)
74            }
75            ir::TyKind::Tuple(ty_fields) => {
76                let reader = TupleReader::new_for_ty(buf, ty);
77
78                let fields = ty_fields
79                    .iter()
80                    .enumerate()
81                    .map(|(i, t)| (reader.get_field(i), t));
82                self.visit_tuple(fields)
83            }
84            ir::TyKind::Array(ty_items) => {
85                let reader = ArrayReader::new_for_ty(buf, ty);
86                self.visit_array(reader, ty_items)
87            }
88            ir::TyKind::Enum(variants) => {
89                let head = layout::enum_head_format(variants, &ty.variants_recursive);
90
91                let mut buf = buf;
92
93                let mut tag_bytes = vec![0; 8];
94                buf.copy_to_slice(&mut tag_bytes[0..head.tag_bytes as usize]);
95                tag_bytes.resize(8, 0);
96                let tag = u64::from_le_bytes(tag_bytes.try_into().unwrap()) as usize;
97
98                let variant = variants.get(tag).unwrap();
99
100                let variant_format = layout::enum_variant_format(&head, &variant.ty);
101
102                let mut buf_inner = buf;
103                if head.has_ptr {
104                    if variant_format.is_unit {
105                        // no need to advance, inner is unit anyway
106                    } else {
107                        // read ptr without advancing
108                        let ptr = buf_inner.clone().get_u32_le() as usize;
109
110                        buf_inner.advance(ptr);
111                    }
112                } else {
113                    // no need to advance, inner is right after tag
114                };
115
116                self.visit_enum(tag, buf_inner, variants)
117            }
118
119            ir::TyKind::Function(..) => Err(Error::InvalidType),
120            ir::TyKind::Ident(..) => Err(Error::Bug),
121        }
122    }
123
124    fn visit_bool(&mut self, v: bool) -> Result<Self::Res, crate::Error>;
125    fn visit_int8(&mut self, v: i8) -> Result<Self::Res, crate::Error>;
126    fn visit_int16(&mut self, v: i16) -> Result<Self::Res, crate::Error>;
127    fn visit_int32(&mut self, v: i32) -> Result<Self::Res, crate::Error>;
128    fn visit_int64(&mut self, v: i64) -> Result<Self::Res, crate::Error>;
129    fn visit_uint8(&mut self, v: u8) -> Result<Self::Res, crate::Error>;
130    fn visit_uint16(&mut self, v: u16) -> Result<Self::Res, crate::Error>;
131    fn visit_uint32(&mut self, v: u32) -> Result<Self::Res, crate::Error>;
132    fn visit_uint64(&mut self, v: u64) -> Result<Self::Res, crate::Error>;
133    fn visit_float32(&mut self, v: f32) -> Result<Self::Res, crate::Error>;
134    fn visit_float64(&mut self, v: f64) -> Result<Self::Res, crate::Error>;
135    fn visit_text(&mut self, contents: B, len: usize) -> Result<Self::Res, crate::Error>;
136
137    fn visit_tuple(
138        &mut self,
139        fields: impl Iterator<Item = (B, &'t ir::TyTupleField)>,
140    ) -> Result<Self::Res, crate::Error>;
141
142    fn visit_array(
143        &mut self,
144        items: impl Iterator<Item = B>,
145        ty_items: &'t ir::Ty,
146    ) -> Result<Self::Res, crate::Error>;
147
148    fn visit_enum(
149        &mut self,
150        tag: usize,
151        inner: B,
152        ty_variants: &'t [ir::TyEnumVariant],
153    ) -> Result<Self::Res, crate::Error>;
154}