vexil_codegen_rust/
delta.rs1use vexil_lang::ast::PrimitiveType;
2use vexil_lang::ir::{Encoding, FieldEncoding, MessageDef, ResolvedType, TypeRegistry};
3
4use crate::emit::CodeWriter;
5use crate::message::{emit_read, emit_write};
6use crate::types::rust_type;
7
8use std::collections::HashSet;
9use vexil_lang::ir::TypeId;
10
11fn is_delta(enc: &FieldEncoding) -> bool {
17 matches!(enc.encoding, Encoding::Delta(_))
18}
19
20fn is_float(ty: &ResolvedType) -> bool {
22 matches!(
23 ty,
24 ResolvedType::Primitive(PrimitiveType::F32) | ResolvedType::Primitive(PrimitiveType::F64)
25 )
26}
27
28fn zero_literal(ty: &ResolvedType) -> &'static str {
30 match ty {
31 ResolvedType::Primitive(PrimitiveType::F32) => "0.0_f32",
32 ResolvedType::Primitive(PrimitiveType::F64) => "0.0_f64",
33 _ => "0",
34 }
35}
36
37fn strip_delta(enc: &FieldEncoding) -> FieldEncoding {
40 match &enc.encoding {
41 Encoding::Delta(inner) => FieldEncoding {
42 encoding: *inner.clone(),
43 limit: enc.limit,
44 },
45 _ => enc.clone(),
46 }
47}
48
49pub fn emit_delta(w: &mut CodeWriter, msg: &MessageDef, registry: &TypeRegistry) {
58 let delta_fields: Vec<_> = msg
60 .fields
61 .iter()
62 .filter(|f| is_delta(&f.encoding))
63 .collect();
64
65 if delta_fields.is_empty() {
66 return;
67 }
68
69 let name = msg.name.as_str();
70 let empty_needs_box: HashSet<(TypeId, usize)> = HashSet::new();
73
74 w.open_block(&format!("pub struct {name}Encoder"));
79 for field in &delta_fields {
80 let rust_ty = rust_type(&field.resolved_type, registry, &empty_needs_box, None);
81 w.line(&format!("prev_{}: {},", field.name, rust_ty));
82 }
83 w.close_block();
84 w.blank();
85
86 w.open_block(&format!("impl {name}Encoder"));
87
88 w.open_block("pub fn new() -> Self");
90 w.open_block("Self");
91 for field in &delta_fields {
92 let zero = zero_literal(&field.resolved_type);
93 w.line(&format!("prev_{}: {},", field.name, zero));
94 }
95 w.close_block();
96 w.close_block();
97 w.blank();
98
99 w.open_block(&format!(
101 "pub fn pack(&mut self, val: &{name}, w: &mut vexil_runtime::BitWriter) -> Result<(), vexil_runtime::EncodeError>"
102 ));
103 for field in &msg.fields {
104 let fname = field.name.as_str();
105 if is_delta(&field.encoding) {
106 if is_float(&field.resolved_type) {
107 w.line(&format!(
108 "let delta_{fname} = val.{fname} - self.prev_{fname};"
109 ));
110 } else {
111 w.line(&format!(
112 "let delta_{fname} = val.{fname}.wrapping_sub(self.prev_{fname});"
113 ));
114 }
115 let inner_enc = strip_delta(&field.encoding);
117 emit_write(
118 w,
119 &format!("delta_{fname}"),
120 &field.resolved_type,
121 &inner_enc,
122 registry,
123 fname,
124 );
125 w.line(&format!("self.prev_{fname} = val.{fname};"));
126 } else {
127 let access = format!("val.{fname}");
128 emit_write(
129 w,
130 &access,
131 &field.resolved_type,
132 &field.encoding,
133 registry,
134 fname,
135 );
136 }
137 }
138 w.line("w.flush_to_byte_boundary();");
139 w.open_block("if !val._unknown.is_empty()");
140 w.line("w.write_raw_bytes(&val._unknown);");
141 w.close_block();
142 w.line("Ok(())");
143 w.close_block();
144 w.blank();
145
146 w.open_block("pub fn reset(&mut self)");
148 for field in &delta_fields {
149 let zero = zero_literal(&field.resolved_type);
150 w.line(&format!("self.prev_{} = {};", field.name, zero));
151 }
152 w.close_block();
153
154 w.close_block(); w.blank();
156
157 w.open_block(&format!("pub struct {name}Decoder"));
162 for field in &delta_fields {
163 let rust_ty = rust_type(&field.resolved_type, registry, &empty_needs_box, None);
164 w.line(&format!("prev_{}: {},", field.name, rust_ty));
165 }
166 w.close_block();
167 w.blank();
168
169 w.open_block(&format!("impl {name}Decoder"));
170
171 w.open_block("pub fn new() -> Self");
173 w.open_block("Self");
174 for field in &delta_fields {
175 let zero = zero_literal(&field.resolved_type);
176 w.line(&format!("prev_{}: {},", field.name, zero));
177 }
178 w.close_block();
179 w.close_block();
180 w.blank();
181
182 w.open_block(&format!(
184 "pub fn unpack(&mut self, r: &mut vexil_runtime::BitReader<'_>) -> Result<{name}, vexil_runtime::DecodeError>"
185 ));
186 for field in &msg.fields {
187 let fname = field.name.as_str();
188 if is_delta(&field.encoding) {
189 let inner_enc = strip_delta(&field.encoding);
190 let delta_var = format!("delta_{fname}");
191 emit_read(
193 w,
194 &delta_var,
195 &field.resolved_type,
196 &inner_enc,
197 registry,
198 fname,
199 );
200 if is_float(&field.resolved_type) {
202 w.line(&format!("let {fname} = self.prev_{fname} + {delta_var};"));
203 } else {
204 w.line(&format!(
205 "let {fname} = self.prev_{fname}.wrapping_add({delta_var});"
206 ));
207 }
208 w.line(&format!("self.prev_{fname} = {fname};"));
209 } else {
210 emit_read(
211 w,
212 fname,
213 &field.resolved_type,
214 &field.encoding,
215 registry,
216 fname,
217 );
218 }
219 }
220 w.line("r.flush_to_byte_boundary();");
221 w.line("let _unknown = Vec::new();");
222 w.open_block(&format!("Ok({name}"));
223 for field in &msg.fields {
224 w.line(&format!("{},", field.name));
225 }
226 w.line("_unknown,");
227 w.dedent();
228 w.line("})");
229
230 w.close_block(); w.blank();
232
233 w.open_block("pub fn reset(&mut self)");
235 for field in &delta_fields {
236 let zero = zero_literal(&field.resolved_type);
237 w.line(&format!("self.prev_{} = {};", field.name, zero));
238 }
239 w.close_block();
240
241 w.close_block(); w.blank();
243}