1use crate::vec;
2
3#[cfg(not(feature = "std"))]
4use alloc::collections::BTreeMap as Map;
5#[cfg(feature = "std")]
6use std::collections::HashMap as Map;
7
8use bytes::{BufMut, BytesMut};
9
10use super::{TyClass, Value};
11use crate::encode::ReversePointer;
12use crate::ir;
13use crate::layout::{self, EnumHeadFormat, EnumVariantFormat};
14use crate::{Encode, Error, Result};
15
16impl Value {
17 pub fn encode(&self, ty: &ir::Ty, ty_defs: &[ir::TyDef]) -> Result<vec::Vec<u8>> {
19 let mut buf = BytesMut::new();
20
21 let mut ctx = Context::new(ty_defs);
22
23 let head_ptr = encode_head(&mut buf, self, ty, &mut ctx)?;
24 encode_body(&mut buf, self, head_ptr, ty, &mut ctx)?;
25 Ok(buf.to_vec())
26 }
27}
28
29fn encode_head<'t>(
30 buf: &mut BytesMut,
31 value: &Value,
32 ty: &'t ir::Ty,
33 ctx: &mut Context<'t>,
34) -> Result<ValueHeadPtr> {
35 let ty = ctx.get_mat_ty(ty);
36
37 match TyClass::of_ty(ty)? {
38 TyClass::Prim8 => {
39 let v = value.expect_prim8()?;
40 v.encode_head(buf);
41 Ok(ValueHeadPtr::None)
42 }
43 TyClass::Prim16 => {
44 let v = value.expect_prim16()?;
45 v.encode_head(buf);
46 Ok(ValueHeadPtr::None)
47 }
48 TyClass::Prim32 => {
49 let v = value.expect_prim32()?;
50 v.encode_head(buf);
51 Ok(ValueHeadPtr::None)
52 }
53
54 TyClass::Prim64 => {
55 let v = value.expect_prim64()?;
56 v.encode_head(buf);
57 Ok(ValueHeadPtr::None)
58 }
59
60 TyClass::PrimText => {
61 let v = value.expect_text()?;
62 Ok(ValueHeadPtr::Offset(v.encode_head(buf)))
63 }
64
65 TyClass::Tuple(ty_fields) => {
66 let fields = value.expect_tuple()?;
67
68 let mut head_ptrs = vec::Vec::with_capacity(fields.len());
69 for (f, f_ty) in fields.iter().zip(ty_fields) {
70 head_ptrs.push(encode_head(buf, f, &f_ty.ty, ctx)?);
71 }
72
73 Ok(ValueHeadPtr::Tuple(head_ptrs))
74 }
75 TyClass::Array(_ty_items) => {
76 let items = value.expect_array()?;
77
78 let offset_ptr = ReversePointer::new(buf);
79 buf.put_u32_le(items.len() as u32);
80 Ok(ValueHeadPtr::Offset(offset_ptr))
81 }
82 TyClass::Enum(ty_variants) => {
83 let (tag, inner) = value.expect_enum()?;
84
85 let (head, variant, tag, variant_ty) =
86 enum_params_encode(tag, ty_variants, &ty.variants_recursive)?;
87
88 let tag_bytes = &(tag as u64).to_le_bytes()[0..head.tag_bytes as usize];
89 buf.put_slice(tag_bytes);
90
91 let r = if head.has_ptr {
92 if variant.is_unit {
93 ValueHeadPtr::None
95 } else {
96 let offset = ReversePointer::new(buf);
97
98 ValueHeadPtr::Offset(offset)
99 }
100 } else {
101 encode_head(buf, inner, variant_ty, ctx)?
102 };
103
104 if variant.padding_bytes > 0 {
105 buf.put_bytes(0, variant.padding_bytes as usize);
106 }
107 Ok(r)
108 }
109 }
110}
111
112enum ValueHeadPtr {
113 None,
114 Offset(ReversePointer),
115 Tuple(vec::Vec<ValueHeadPtr>),
116}
117
118fn encode_body<'t>(
119 w: &mut BytesMut,
120 value: &Value,
121 head_ptr: ValueHeadPtr,
122 ty: &'t ir::Ty,
123 ctx: &mut Context<'t>,
124) -> Result<()> {
125 let ty = ctx.get_mat_ty(ty);
126
127 match TyClass::of_ty(ty)? {
128 TyClass::Prim8 | TyClass::Prim16 | TyClass::Prim32 | TyClass::Prim64 => {}
129 TyClass::PrimText => {
130 let v = value.expect_text()?;
131
132 let ValueHeadPtr::Offset(offset_ptr) = head_ptr else {
133 return Err(Error::Bug);
134 };
135
136 v.encode_body(offset_ptr, w);
137 }
138 TyClass::Tuple(ty_fields) => {
139 let fields = value.expect_tuple()?;
140
141 let ValueHeadPtr::Tuple(tuple_ptrs) = head_ptr else {
142 return Err(Error::Bug);
143 };
144
145 for ((f, h), f_ty) in fields.iter().zip(tuple_ptrs.into_iter()).zip(ty_fields) {
146 encode_body(w, f, h, &f_ty.ty, ctx)?
147 }
148 }
149 TyClass::Array(items_ty) => {
150 let items = value.expect_array()?;
151
152 let ValueHeadPtr::Offset(offset_ptr) = head_ptr else {
153 return Err(Error::Bug);
154 };
155 offset_ptr.write_cur_len(w);
156
157 let mut head_ptrs = vec::Vec::with_capacity(items.len());
158 for i in items {
159 head_ptrs.push(encode_head(w, i, items_ty, ctx)?);
160 }
161
162 for (i, h) in items.iter().zip(head_ptrs.into_iter()) {
163 encode_body(w, i, h, items_ty, ctx)?;
164 }
165 }
166 TyClass::Enum(variants) => {
167 let (tag, inner) = value.expect_enum()?;
168
169 let (head_format, _, _, variant_ty) =
170 enum_params_encode(tag, variants, &ty.variants_recursive)?;
171
172 if head_format.has_ptr {
173 match head_ptr {
174 ValueHeadPtr::None => {
175 }
177 ValueHeadPtr::Offset(offset_ptr) => {
178 offset_ptr.write_cur_len(w);
179
180 let head_ptr = encode_head(w, inner, variant_ty, ctx)?;
181 encode_body(w, inner, head_ptr, variant_ty, ctx)?;
182 }
183 ValueHeadPtr::Tuple(_) => return Err(Error::Bug),
184 }
185 } else {
186 encode_body(w, inner, head_ptr, variant_ty, ctx)?;
187 }
188 }
189 }
190
191 Ok(())
192}
193
194fn enum_params_encode<'a>(
195 tag: usize,
196 variants: &'a [ir::TyEnumVariant],
197 variants_recursive: &[u16],
198) -> Result<(EnumHeadFormat, EnumVariantFormat, usize, &'a ir::Ty)> {
199 let head_format = layout::enum_head_format(variants, variants_recursive);
200
201 let variant = variants.get(tag).ok_or(Error::InvalidData)?;
202
203 let variant_format = layout::enum_variant_format(&head_format, &variant.ty);
204 Ok((head_format, variant_format, tag, &variant.ty))
205}
206
207pub(super) struct Context<'t> {
208 ty_defs: Map<&'t ir::Path, &'t ir::Ty>,
209}
210
211impl<'t> Context<'t> {
212 pub(super) fn new(ty_defs: &'t [ir::TyDef]) -> Self {
213 Context {
214 ty_defs: ty_defs.iter().map(|def| (&def.name, &def.ty)).collect(),
215 }
216 }
217
218 pub(super) fn get_mat_ty(&self, ty: &'t ir::Ty) -> &'t ir::Ty {
219 if let ir::TyKind::Ident(ident) = &ty.kind {
220 self.ty_defs.get(ident).unwrap()
221 } else {
222 ty
223 }
224 }
225}