mech_core/program/compiler/
constants.rs

1use crate::*;
2use super::*;
3#[cfg(feature = "matrix")]
4use crate::structures::Matrix;
5
6// CompileConst Trait
7// ----------------------------------------------------------------------------
8
9pub trait CompileConst {
10  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32>;
11}
12
13#[cfg(feature = "compiler")]
14impl CompileConst for Value {
15
16  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
17    let reg = match self {
18      #[cfg(feature = "bool")]
19      Value::Bool(x) => x.borrow().compile_const(ctx)?,
20      #[cfg(feature = "string")]
21      Value::String(x) => x.borrow().compile_const(ctx)?,
22      #[cfg(feature = "u8")]
23      Value::U8(x) => x.borrow().compile_const(ctx)?,
24      #[cfg(feature = "u16")]
25      Value::U16(x) => x.borrow().compile_const(ctx)?,
26      #[cfg(feature = "u32")]
27      Value::U32(x) => x.borrow().compile_const(ctx)?,
28      #[cfg(feature = "u64")]
29      Value::U64(x) => x.borrow().compile_const(ctx)?,
30      #[cfg(feature = "u128")]
31      Value::U128(x) => x.borrow().compile_const(ctx)?,
32      #[cfg(feature = "i8")]
33      Value::I8(x) => x.borrow().compile_const(ctx)?,
34      #[cfg(feature = "i16")]
35      Value::I16(x) => x.borrow().compile_const(ctx)?,
36      #[cfg(feature = "i32")]
37      Value::I32(x) => x.borrow().compile_const(ctx)?,
38      #[cfg(feature = "i64")]
39      Value::I64(x) => x.borrow().compile_const(ctx)?,
40      #[cfg(feature = "i128")]
41      Value::I128(x) => x.borrow().compile_const(ctx)?,
42      #[cfg(feature = "f32")]
43      Value::F32(x) => x.borrow().compile_const(ctx)?,
44      #[cfg(feature = "f64")]
45      Value::F64(x) => x.borrow().compile_const(ctx)?,
46      #[cfg(feature = "atom")]
47      Value::Atom(x) => x.borrow().compile_const(ctx)?,
48      #[cfg(feature = "index")]
49      Value::Index(x) => x.borrow().compile_const(ctx)?,
50      #[cfg(feature = "complex")]
51      Value::C64(x) => x.borrow().compile_const(ctx)?,
52      #[cfg(feature = "rational")]
53      Value::R64(x) => x.borrow().compile_const(ctx)?,
54      #[cfg(all(feature = "matrix", feature = "f64"))]
55      Value::MatrixF64(x) => x.compile_const(ctx)?,
56      #[cfg(all(feature = "matrix", feature = "f32"))]
57      Value::MatrixF32(x) => x.compile_const(ctx)?,
58      #[cfg(all(feature = "matrix", feature = "u8"))]
59      Value::MatrixU8(x) => x.compile_const(ctx)?,
60      #[cfg(all(feature = "matrix", feature = "u16"))]
61      Value::MatrixU16(x) => x.compile_const(ctx)?,
62      #[cfg(all(feature = "matrix", feature = "u32"))]
63      Value::MatrixU32(x) => x.compile_const(ctx)?,
64      #[cfg(all(feature = "matrix", feature = "u64"))]
65      Value::MatrixU64(x) => x.compile_const(ctx)?,
66      #[cfg(all(feature = "matrix", feature = "u128"))]
67      Value::MatrixU128(x) => x.compile_const(ctx)?,
68      #[cfg(all(feature = "matrix", feature = "i8"))]
69      Value::MatrixI8(x) => x.compile_const(ctx)?,
70      #[cfg(all(feature = "matrix", feature = "i16"))]
71      Value::MatrixI16(x) => x.compile_const(ctx)?,
72      #[cfg(all(feature = "matrix", feature = "i32"))]
73      Value::MatrixI32(x) => x.compile_const(ctx)?,
74      #[cfg(all(feature = "matrix", feature = "i64"))]
75      Value::MatrixI64(x) => x.compile_const(ctx)?,
76      #[cfg(all(feature = "matrix", feature = "i128"))]
77      Value::MatrixI128(x) => x.compile_const(ctx)?,
78      #[cfg(all(feature = "matrix", feature = "bool"))]
79      Value::MatrixBool(x) => x.compile_const(ctx)?,
80      #[cfg(all(feature = "matrix", feature = "rational"))]
81      Value::MatrixR64(x) => x.compile_const(ctx)?,
82      #[cfg(all(feature = "matrix", feature = "complex"))]
83      Value::MatrixC64(x) => x.compile_const(ctx)?,
84      #[cfg(all(feature = "matrix", feature = "string"))]
85      Value::MatrixString(x) => x.compile_const(ctx)?,
86      #[cfg(feature = "matrix")]
87      Value::MatrixIndex(x) => x.compile_const(ctx)?,
88      #[cfg(feature = "matrix")]
89      Value::MatrixValue(x) => x.compile_const(ctx)?,
90      #[cfg(feature = "table")]
91      Value::Table(x) => x.borrow().compile_const(ctx)?,
92      #[cfg(feature = "record")]
93      Value::Record(x) => x.borrow().compile_const(ctx)?,
94      #[cfg(feature = "set")]
95      Value::Set(x) => x.borrow().compile_const(ctx)?,
96      x => todo!("CompileConst not implemented for {:?}", x),
97    };
98    Ok(reg)
99  }
100}
101
102#[cfg(all(feature = "f64", feature = "compiler"))]
103impl CompileConst for F64 {
104  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
105    let mut payload = Vec::<u8>::new();
106    payload.write_f64::<LittleEndian>(self.0)?;
107    ctx.compile_const(&payload, ValueKind::F64)
108  }
109}
110
111#[cfg(feature = "f32")]
112impl CompileConst for F32 {
113  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
114    let mut payload = Vec::<u8>::new();
115    payload.write_f32::<LittleEndian>(self.0)?;
116    ctx.compile_const(&payload, ValueKind::F32)
117  }
118}
119
120#[cfg(feature = "u8")]
121impl CompileConst for u8 {
122  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
123    let mut payload = Vec::<u8>::new();
124    payload.write_u8(*self)?;
125    ctx.compile_const(&payload, ValueKind::U8)
126  }
127}
128
129#[cfg(feature = "i8")]
130impl CompileConst for i8 {
131  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
132    let mut payload = Vec::<u8>::new();
133    payload.write_i8(*self)?;
134    ctx.compile_const(&payload, ValueKind::I8)
135  }
136}
137
138#[cfg(feature = "compiler")]
139impl CompileConst for usize {
140  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
141    let mut payload = Vec::<u8>::new();
142    payload.write_u64::<LittleEndian>(*self as u64)?;
143    ctx.compile_const(&payload, ValueKind::Index)
144  }
145}
146
147macro_rules! impl_compile_const {
148  ($feature:literal, $t:tt) => {
149    paste! {
150      #[cfg(feature = $feature)]
151      impl CompileConst for $t {
152        fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
153          let mut payload = Vec::<u8>::new();
154          payload.[<write_ $t>]::<LittleEndian>(*self)?;
155          ctx.compile_const(&payload, ValueKind::[<$t:upper>])
156        }
157      }
158    }
159  };
160}
161
162#[cfg(feature = "u16")]
163impl_compile_const!("u16", u16);
164#[cfg(feature = "u32")]
165impl_compile_const!("u32", u32);
166#[cfg(feature = "u64")]
167impl_compile_const!("u64", u64);
168#[cfg(feature = "u128")]
169impl_compile_const!("u128", u128);
170#[cfg(feature = "i16")]
171impl_compile_const!("i16", i16);
172#[cfg(feature = "i32")]
173impl_compile_const!("i32", i32);
174#[cfg(feature = "i64")]
175impl_compile_const!("i64", i64);
176#[cfg(feature = "i128")]
177impl_compile_const!("i128", i128);
178
179#[cfg(any(feature = "bool", feature = "variable_define"))]
180impl CompileConst for bool {
181  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
182    let mut payload = Vec::<u8>::new();
183    payload.write_u8(if *self { 1 } else { 0 })?;
184    ctx.compile_const(&payload, ValueKind::Bool)
185  }
186}
187
188#[cfg(any(feature = "string", feature = "variable_define"))]
189impl CompileConst for String {
190  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
191    let mut payload = Vec::<u8>::new();
192    payload.write_u32::<LittleEndian>(self.len() as u32)?;
193    payload.extend_from_slice(self.as_bytes());
194    ctx.compile_const(&payload, ValueKind::String)
195  }
196}
197
198#[cfg(feature = "rational")]
199impl CompileConst for R64 {
200  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
201    let mut payload = Vec::<u8>::new();
202    payload.write_i64::<LittleEndian>(*self.numer())?;
203    payload.write_i64::<LittleEndian>(*self.denom())?;
204    ctx.compile_const(&payload, ValueKind::R64)
205  }
206}
207
208#[cfg(feature = "complex")]
209impl CompileConst for C64 {
210  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
211    let mut payload = Vec::<u8>::new();
212    payload.write_f64::<LittleEndian>(self.0.re)?;
213    payload.write_f64::<LittleEndian>(self.0.im)?;
214    ctx.compile_const(&payload, ValueKind::C64)
215  }
216}
217
218macro_rules! impl_compile_const_matrix {
219  ($matrix_type:ty) => {
220    impl<T> CompileConst for $matrix_type
221    where
222      T: ConstElem + AsValueKind,
223    {
224      fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
225        let rows = self.nrows() as u32;
226        let cols = self.ncols() as u32;
227        let mut payload = Vec::<u8>::with_capacity((rows * cols) as usize * 8);
228
229        // write header: rows, cols
230        payload.write_u32::<LittleEndian>(rows)?;
231        payload.write_u32::<LittleEndian>(cols)?;
232
233        // write elements column-major
234        for c in 0..cols as usize {
235          for r in 0..rows as usize {
236            self[(r, c)].write_le(&mut payload);
237          }
238        }
239        let elem_vk = T::as_value_kind();
240        let mat_vk = ValueKind::Matrix(Box::new(elem_vk), vec![rows as usize, cols as usize]);
241        ctx.compile_const(&payload, mat_vk)
242      }
243    }
244  };
245}
246
247#[cfg(feature = "matrix1")]
248impl_compile_const_matrix!(na::Matrix1<T>);
249#[cfg(feature = "matrix2")]
250impl_compile_const_matrix!(na::Matrix2<T>);
251#[cfg(feature = "matrix3")]
252impl_compile_const_matrix!(na::Matrix3<T>);
253#[cfg(feature = "matrix4")]
254impl_compile_const_matrix!(na::Matrix4<T>);
255#[cfg(feature = "matrix2x3")]
256impl_compile_const_matrix!(na::Matrix2x3<T>);
257#[cfg(feature = "matrix3x2")]
258impl_compile_const_matrix!(na::Matrix3x2<T>);
259#[cfg(feature = "row_vector2")]
260impl_compile_const_matrix!(na::RowVector2<T>);
261#[cfg(feature = "row_vector3")]
262impl_compile_const_matrix!(na::RowVector3<T>);
263#[cfg(feature = "row_vector4")]
264impl_compile_const_matrix!(na::RowVector4<T>);
265#[cfg(feature = "vector2")]
266impl_compile_const_matrix!(na::Vector2<T>);
267#[cfg(feature = "vector3")]
268impl_compile_const_matrix!(na::Vector3<T>);
269#[cfg(feature = "vector4")]
270impl_compile_const_matrix!(na::Vector4<T>);
271#[cfg(feature = "matrixd")]
272impl_compile_const_matrix!(na::DMatrix<T>);
273#[cfg(feature = "vectord")]
274impl_compile_const_matrix!(na::DVector<T>);
275#[cfg(feature = "row_vectord")]
276impl_compile_const_matrix!(na::RowDVector<T>);
277
278#[cfg(feature = "matrix")]
279impl<T> CompileConst for Matrix<T> 
280where
281  T: CompileConst + ConstElem + AsValueKind
282{
283  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
284    match self {
285      #[cfg(feature = "matrixd")]
286      Matrix::DMatrix(mat) => mat.borrow().compile_const(ctx),
287      #[cfg(feature = "vectord")]
288      Matrix::DVector(mat) => mat.borrow().compile_const(ctx),
289      #[cfg(feature = "row_vectord")]
290      Matrix::RowDVector(mat) => mat.borrow().compile_const(ctx),
291      #[cfg(feature = "matrix1")]
292      Matrix::Matrix1(mat) => mat.borrow().compile_const(ctx),
293      #[cfg(feature = "matrix2")]
294      Matrix::Matrix2(mat) => mat.borrow().compile_const(ctx),
295      #[cfg(feature = "matrix3")]
296      Matrix::Matrix3(mat) => mat.borrow().compile_const(ctx),
297      #[cfg(feature = "matrix4")]
298      Matrix::Matrix4(mat) => mat.borrow().compile_const(ctx),
299      #[cfg(feature = "matrix2x3")]
300      Matrix::Matrix2x3(mat) => mat.borrow().compile_const(ctx),
301      #[cfg(feature = "matrix3x2")]
302      Matrix::Matrix3x2(mat) => mat.borrow().compile_const(ctx),
303      #[cfg(feature = "row_vector2")]
304      Matrix::RowVector2(mat) => mat.borrow().compile_const(ctx),
305      #[cfg(feature = "row_vector3")]
306      Matrix::RowVector3(mat) => mat.borrow().compile_const(ctx),
307      #[cfg(feature = "row_vector4")]
308      Matrix::RowVector4(mat) => mat.borrow().compile_const(ctx),
309      #[cfg(feature = "vector2")]
310      Matrix::Vector2(mat) => mat.borrow().compile_const(ctx),
311      #[cfg(feature = "vector3")]
312      Matrix::Vector3(mat) => mat.borrow().compile_const(ctx),
313      #[cfg(feature = "vector4")]
314      Matrix::Vector4(mat) => mat.borrow().compile_const(ctx),
315    }
316  }
317}
318
319#[cfg(feature = "matrixd")]
320impl<T> CompileConst for Ref<DMatrix<T>> 
321where
322  T: CompileConst + ConstElem + AsValueKind
323{
324  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
325    self.borrow().compile_const(ctx)
326  }
327}
328
329#[cfg(feature = "vectord")]
330impl<T> CompileConst for Ref<DVector<T>> 
331where
332  T: CompileConst + ConstElem + AsValueKind
333{
334  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
335    self.borrow().compile_const(ctx)
336  }
337}
338
339#[cfg(feature = "row_vectord")]
340impl<T> CompileConst for Ref<RowDVector<T>> 
341where
342  T: CompileConst + ConstElem + AsValueKind
343{
344  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
345    self.borrow().compile_const(ctx)
346  }
347}
348
349#[cfg(feature = "record")]
350impl CompileConst for MechRecord {
351  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
352    let mut payload = Vec::<u8>::new();
353
354    // write the number of columns
355    payload.write_u32::<LittleEndian>(self.cols as u32)?;
356
357    // write each column: (name hash, value kind, data)
358    for (col_id, value) in self.data.iter() {
359      // column name hash
360      payload.write_u64::<LittleEndian>(*col_id)?;
361      // value kind
362      let value_kind = value.kind();
363      value_kind.write_le(&mut payload);
364      // value data
365      value.write_le(&mut payload);
366    }
367
368    // Write the field name strings into the payload
369    for (_col_id, col_name) in self.field_names.iter() {
370      col_name.write_le(&mut payload);
371    }
372    ctx.compile_const(&payload, self.kind())
373  }
374}
375
376#[cfg(feature = "enum")]
377impl CompileConst for MechEnum {
378  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
379    let mut payload = Vec::<u8>::new();
380    payload.write_u64::<LittleEndian>(self.id)?;
381    payload.write_u32::<LittleEndian>(self.variants.len() as u32)?;
382    for (variant_id, variant_value) in self.variants.iter() {
383      payload.write_u64::<LittleEndian>(*variant_id)?;
384      match variant_value {
385        Some(v) => {
386          // has value
387          payload.write_u8(1)?;
388          // value kind
389          let value_kind = v.kind();
390          value_kind.write_le(&mut payload);
391          // value data
392          v.write_le(&mut payload);
393        },
394        None => {
395          // has no value
396          payload.write_u8(0)?;
397        }
398      }
399    }
400    ctx.compile_const(&payload, ValueKind::Enum(self.id))
401  }
402}
403
404#[cfg(feature = "atom")]
405impl CompileConst for MechAtom {
406  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
407    let mut payload = Vec::<u8>::new();
408    payload.write_u64::<LittleEndian>(self.0)?;
409    ctx.compile_const(&payload, ValueKind::Atom(self.0))
410  }
411}
412
413#[cfg(feature = "set")]
414impl CompileConst for MechSet {
415  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
416    let mut payload = Vec::<u8>::new();
417    self.kind.write_le(&mut payload);
418    payload.write_u32::<LittleEndian>(self.num_elements as u32)?;
419    for element in &self.set {
420      element.write_le(&mut payload);
421    }
422    ctx.compile_const(&payload, self.kind())
423  }
424}
425
426#[cfg(feature = "tuple")]
427impl CompileConst for MechTuple {
428  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
429    let mut payload = Vec::<u8>::new();
430    self.value_kind().write_le(&mut payload);
431    payload.write_u32::<LittleEndian>(self.elements.len() as u32)?;
432    for elem in &self.elements {
433      elem.write_le(&mut payload);
434    }
435    ctx.compile_const(&payload, self.value_kind())
436  }
437}
438
439// ConstElem Trait
440// ----------------------------------------------------------------------------
441
442pub trait ConstElem {
443  fn write_le(&self, out: &mut Vec<u8>);
444  fn from_le(bytes: &[u8]) -> Self;
445  fn value_kind(&self) -> ValueKind;
446  fn align() -> u8 { 1 }
447}
448
449#[cfg(feature = "f64")]
450impl ConstElem for F64 {
451  fn write_le(&self, out: &mut Vec<u8>) {
452    out.write_f64::<LittleEndian>(self.0).expect("write f64");
453  }
454  fn from_le(bytes: &[u8]) -> Self {
455    let mut rdr = std::io::Cursor::new(bytes);
456    let val = rdr.read_f64::<LittleEndian>().expect("read f64");
457    F64(val)
458  }
459  fn value_kind(&self) -> ValueKind { ValueKind::F64 }
460  fn align() -> u8 { 8 }
461}
462
463#[cfg(feature = "f32")]
464impl ConstElem for F32 {
465  fn write_le(&self, out: &mut Vec<u8>) {
466    out.write_f32::<LittleEndian>(self.0).expect("write f32");
467  }
468  fn from_le(bytes: &[u8]) -> Self {
469    let mut rdr = std::io::Cursor::new(bytes);
470    let val = rdr.read_f32::<LittleEndian>().expect("read f32");
471    F32(val)
472  }
473  fn value_kind(&self) -> ValueKind { ValueKind::F32 }
474  fn align() -> u8 { 4 }
475} 
476
477macro_rules! impl_const_elem {
478  ($feature:literal, $t:ty, $align:expr) => {
479    paste!{
480      #[cfg(feature = $feature)]
481      impl ConstElem for $t {
482        fn write_le(&self, out: &mut Vec<u8>) {
483          out.[<write_ $t>]::<LittleEndian>(*self).expect(concat!("write ", stringify!($t)));
484        }
485        fn from_le(bytes: &[u8]) -> Self {
486          let mut rdr = std::io::Cursor::new(bytes);
487          rdr.[<read_ $t>]::<LittleEndian>().expect(concat!("read ", stringify!($t)))
488        }
489        fn value_kind(&self) -> ValueKind { ValueKind::[<$t:upper>] }
490        fn align() -> u8 { $align }
491      }
492    }
493  };
494}
495
496#[cfg(feature = "u16")]
497impl_const_elem!("u16", u16, 2);
498#[cfg(feature = "u32")]
499impl_const_elem!("u32", u32, 4);
500#[cfg(feature = "u64")]
501impl_const_elem!("u64", u64, 8);
502#[cfg(feature = "u128")]
503impl_const_elem!("u128", u128, 16);
504#[cfg(feature = "i16")]
505impl_const_elem!("i16", i16, 2);
506#[cfg(feature = "i32")]
507impl_const_elem!("i32", i32, 4);
508#[cfg(feature = "i64")]
509impl_const_elem!("i64", i64, 8);
510#[cfg(feature = "i128")]
511impl_const_elem!("i128", i128, 16);
512
513#[cfg(feature = "u8")]
514impl ConstElem for u8 {
515  fn write_le(&self, out: &mut Vec<u8>) {
516    out.write_u8(*self).expect("write u8");
517  }
518  fn from_le(bytes: &[u8]) -> Self {
519    bytes[0]
520  }
521  fn value_kind(&self) -> ValueKind { ValueKind::U8 }
522  fn align() -> u8 { 1 }
523} 
524
525#[cfg(feature = "i8")]
526impl ConstElem for i8 {
527  fn write_le(&self, out: &mut Vec<u8>) {
528    out.write_i8(*self).expect("write i8");
529  }
530  fn from_le(bytes: &[u8]) -> Self {
531    bytes[0] as i8
532  }
533  fn value_kind(&self) -> ValueKind { ValueKind::I8 }
534  fn align() -> u8 { 1 }
535}
536
537#[cfg(feature = "rational")]
538impl ConstElem for R64 {
539  fn write_le(&self, out: &mut Vec<u8>) {
540    out.write_i64::<LittleEndian>(*self.numer()).expect("write rational numer");
541    out.write_i64::<LittleEndian>(*self.denom()).expect("write rational denom");
542  }
543  fn from_le(bytes: &[u8]) -> Self {
544    let numer = match bytes[0..8].try_into() {
545      Ok(arr) => i64::from_le_bytes(arr),
546      Err(_) => panic!("Failed to read numerator from bytes"),
547    };
548    let denom = match bytes[8..16].try_into() {
549      Ok(arr) => i64::from_le_bytes(arr),
550      Err(_) => panic!("Failed to read denominator from bytes"),
551    };
552    if denom == 0 {
553      panic!("Denominator cannot be zero");
554    }
555    R64::new(numer, denom)
556  }
557  fn value_kind(&self) -> ValueKind { ValueKind::R64 }
558  fn align() -> u8 { 16 }
559}
560
561#[cfg(feature = "complex")]
562impl ConstElem for C64 {
563  fn write_le(&self, out: &mut Vec<u8>) {
564    out.write_f64::<LittleEndian>(self.0.re).expect("write complex real");
565    out.write_f64::<LittleEndian>(self.0.im).expect("write complex imag");
566  }
567  fn from_le(bytes: &[u8]) -> Self {
568    let real = match bytes[0..8].try_into() {
569      Ok(arr) => f64::from_le_bytes(arr),
570      Err(_) => panic!("Failed to read real part from bytes"),
571    };
572    let imag = match bytes[8..16].try_into() {
573      Ok(arr) => f64::from_le_bytes(arr),
574      Err(_) => panic!("Failed to read imaginary part from bytes"),
575    };
576    C64::new(real, imag)
577  }
578  fn value_kind(&self) -> ValueKind { ValueKind::C64 }
579  fn align() -> u8 { 16 }
580}
581
582#[cfg(feature = "string")]
583impl ConstElem for String {
584  fn write_le(&self, out: &mut Vec<u8>) {
585    use byteorder::{LittleEndian, WriteBytesExt};
586    out.write_u32::<LittleEndian>(self.len() as u32).expect("write string length");
587    out.extend_from_slice(self.as_bytes());
588  }
589  fn from_le(bytes: &[u8]) -> Self {
590    use byteorder::{LittleEndian, ReadBytesExt};
591    use std::io::Cursor;
592    let mut cursor = Cursor::new(bytes);
593    // read length safely
594    let len = match cursor.read_u32::<LittleEndian>() {
595      Ok(n) => n as usize,
596      Err(_) => panic!("Failed to read string length from bytes"),
597    };
598    let start = cursor.position() as usize;
599    let end = start + len;
600    if end > bytes.len() {
601      panic!(
602        "String::from_le: declared length {} exceeds available bytes ({})",
603        len, bytes.len()
604      );
605    }
606    let str_bytes = &bytes[start..end];
607    match std::str::from_utf8(str_bytes) {
608      Ok(s) => s.to_string(),
609      Err(_) => panic!("Failed to convert bytes to UTF-8 string"),
610    }
611  }
612  fn value_kind(&self) -> ValueKind { ValueKind::String }
613  fn align() -> u8 { 1 }
614}
615
616#[cfg(feature = "bool")]
617impl ConstElem for bool {
618  fn write_le(&self, out: &mut Vec<u8>) {
619    out.write_u8(if *self { 1 } else { 0 }).expect("write bool");
620  }
621  fn from_le(bytes: &[u8]) -> Self {
622    bytes[0] != 0
623  }
624  fn value_kind(&self) -> ValueKind { ValueKind::Bool }
625  fn align() -> u8 { 1 }
626}
627
628impl ConstElem for usize {
629  fn write_le(&self, out: &mut Vec<u8>) {
630    out.write_u64::<LittleEndian>(*self as u64).expect("write usize");
631  }
632  fn from_le(bytes: &[u8]) -> Self {
633    let val = match bytes[0..8].try_into() {
634      Ok(arr) => u64::from_le_bytes(arr),
635      Err(_) => panic!("Failed to read usize from bytes"),
636    };
637    val as usize
638  }
639  fn value_kind(&self) -> ValueKind { ValueKind::Index }
640  fn align() -> u8 { 8 }
641}
642
643macro_rules! impl_const_elem_matrix {
644  ($matrix_type:ty) => {
645    impl<T> ConstElem for $matrix_type
646    where
647      T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
648    {
649      fn write_le(&self, out: &mut Vec<u8>) {
650        out.write_u32::<LittleEndian>(self.nrows() as u32).unwrap();
651        out.write_u32::<LittleEndian>(self.ncols() as u32).unwrap();
652        for c in 0..self.ncols() {
653          for r in 0..self.nrows() {
654            self[(r, c)].write_le(out);
655          }
656        }
657      }
658      fn from_le(bytes: &[u8]) -> Self {
659        let mut cursor = Cursor::new(bytes);
660        let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
661        let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
662        let mut elements: Vec<T> = Vec::with_capacity(rows * cols);
663
664        // Read in column-major order
665        for _c in 0..cols {
666          for _r in 0..rows {
667            let elem = T::from_le(&bytes[cursor.position() as usize..]);
668            let mut buf = Vec::new();
669            elem.write_le(&mut buf);
670            cursor.set_position(cursor.position() + buf.len() as u64);
671            elements.push(elem);
672          }
673        }
674        // Now construct the fixed-size matrix
675        // All nalgebra fixed-size matrices implement `from_row_slice`
676        <$matrix_type>::from_row_slice(&elements)
677      }
678      fn value_kind(&self) -> ValueKind { self.value_kind() }
679      fn align() -> u8 { 8 }
680    }
681  };
682}
683
684#[cfg(feature = "matrixd")]
685impl<T> ConstElem for DMatrix<T>
686where
687  T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
688{
689  fn write_le(&self, out: &mut Vec<u8>) {
690    out.write_u32::<LittleEndian>(self.nrows() as u32).unwrap();
691    out.write_u32::<LittleEndian>(self.ncols() as u32).unwrap();
692    for c in 0..self.ncols() {
693      for r in 0..self.nrows() {
694        self[(r, c)].write_le(out);
695      }
696    }
697  }
698  fn from_le(bytes: &[u8]) -> Self {
699    let mut cursor = Cursor::new(bytes);
700    let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
701    let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
702    let mut elements = Vec::with_capacity(rows * cols);
703    // Read in column-major order
704    for _c in 0..cols {
705      for _r in 0..rows {
706        let elem = T::from_le(&bytes[cursor.position() as usize..]);
707        let mut buf = Vec::new();
708        elem.write_le(&mut buf);
709        cursor.set_position(cursor.position() + buf.len() as u64);
710        elements.push(elem);
711      }
712    }
713    DMatrix::from_vec(rows, cols, elements)
714  }
715  fn value_kind(&self) -> ValueKind { self.value_kind() }
716  fn align() -> u8 { 8 }
717}
718
719#[cfg(feature = "vectord")]
720impl<T> ConstElem for DVector<T>
721where
722  T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
723{
724  fn write_le(&self, out: &mut Vec<u8>) {
725    out.write_u32::<LittleEndian>(self.nrows() as u32).unwrap();
726    out.write_u32::<LittleEndian>(self.ncols() as u32).unwrap();
727    for c in 0..self.ncols() {
728      for r in 0..self.nrows() {
729        self[(r, c)].write_le(out);
730      }
731    }
732  }
733  fn from_le(bytes: &[u8]) -> Self {
734    let mut cursor = Cursor::new(bytes);
735    let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
736    let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
737    let mut elements = Vec::with_capacity(rows * cols);
738    // Read in column-major order
739    for _c in 0..cols {
740      for _r in 0..rows {
741        let elem = T::from_le(&bytes[cursor.position() as usize..]);
742        let mut buf = Vec::new();
743        elem.write_le(&mut buf);
744        cursor.set_position(cursor.position() + buf.len() as u64);
745        elements.push(elem);
746      }
747    }
748    DVector::from_vec(elements)
749  }
750  fn value_kind(&self) -> ValueKind { self.value_kind() }
751  fn align() -> u8 { 8 }
752}
753
754#[cfg(feature = "row_vectord")]
755impl<T> ConstElem for RowDVector<T>
756where
757  T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
758{
759  fn write_le(&self, out: &mut Vec<u8>) {
760    out.write_u32::<LittleEndian>(self.nrows() as u32).unwrap();
761    out.write_u32::<LittleEndian>(self.ncols() as u32).unwrap();
762    for c in 0..self.ncols() {
763      for r in 0..self.nrows() {
764        self[(r, c)].write_le(out);
765      }
766    }
767  }
768  fn from_le(bytes: &[u8]) -> Self {
769    let mut cursor = Cursor::new(bytes);
770    let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
771    let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
772    let mut elements = Vec::with_capacity(rows * cols);
773    // Read in column-major order
774    for _c in 0..cols {
775      for _r in 0..rows {
776        let elem = T::from_le(&bytes[cursor.position() as usize..]);
777        let mut buf = Vec::new();
778        elem.write_le(&mut buf);
779        cursor.set_position(cursor.position() + buf.len() as u64);
780        elements.push(elem);
781      }
782    }
783    RowDVector::from_vec(elements)
784  }
785  fn value_kind(&self) -> ValueKind { self.value_kind() }
786  fn align() -> u8 { 8 }
787}
788
789#[cfg(feature = "matrix1")]
790impl_const_elem_matrix!(Matrix1<T>);
791#[cfg(feature = "matrix2")]
792impl_const_elem_matrix!(Matrix2<T>);
793#[cfg(feature = "matrix3")]
794impl_const_elem_matrix!(Matrix3<T>);
795#[cfg(feature = "matrix4")]
796impl_const_elem_matrix!(Matrix4<T>);
797#[cfg(feature = "matrix2x3")]
798impl_const_elem_matrix!(Matrix2x3<T>);
799#[cfg(feature = "matrix3x2")]
800impl_const_elem_matrix!(Matrix3x2<T>);
801#[cfg(feature = "row_vector2")]
802impl_const_elem_matrix!(RowVector2<T>);
803#[cfg(feature = "row_vector3")]
804impl_const_elem_matrix!(RowVector3<T>);
805#[cfg(feature = "row_vector4")]
806impl_const_elem_matrix!(RowVector4<T>);
807#[cfg(feature = "vector2")]
808impl_const_elem_matrix!(Vector2<T>);
809#[cfg(feature = "vector3")]
810impl_const_elem_matrix!(Vector3<T>);
811#[cfg(feature = "vector4")]
812impl_const_elem_matrix!(Vector4<T>);
813
814#[cfg(feature = "matrix")]
815impl<T> ConstElem for Matrix<T> 
816where
817  T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
818{
819  fn write_le(&self, out: &mut Vec<u8>) {
820    match self {
821      #[cfg(feature = "matrixd")]
822      Matrix::DMatrix(mat) => mat.borrow().write_le(out),
823      #[cfg(feature = "vectord")]
824      Matrix::DVector(mat) => mat.borrow().write_le(out),
825      #[cfg(feature = "row_vectord")]
826      Matrix::RowDVector(mat) => mat.borrow().write_le(out),
827      #[cfg(feature = "matrix1")]
828      Matrix::Matrix1(mat) => mat.borrow().write_le(out),
829      #[cfg(feature = "matrix2")]
830      Matrix::Matrix2(mat) => mat.borrow().write_le(out),
831      #[cfg(feature = "matrix3")]
832      Matrix::Matrix3(mat) => mat.borrow().write_le(out),
833      #[cfg(feature = "matrix4")]
834      Matrix::Matrix4(mat) => mat.borrow().write_le(out),
835      #[cfg(feature = "matrix2x3")]
836      Matrix::Matrix2x3(mat) => mat.borrow().write_le(out),
837      #[cfg(feature = "matrix3x2")]
838      Matrix::Matrix3x2(mat) => mat.borrow().write_le(out),
839      #[cfg(feature = "row_vector2")]
840      Matrix::RowVector2(mat) => mat.borrow().write_le(out),
841      #[cfg(feature = "row_vector3")]
842      Matrix::RowVector3(mat) => mat.borrow().write_le(out),
843      #[cfg(feature = "row_vector4")]
844      Matrix::RowVector4(mat) => mat.borrow().write_le(out),
845      #[cfg(feature = "vector2")]
846      Matrix::Vector2(mat) => mat.borrow().write_le(out),
847      #[cfg(feature = "vector3")]
848      Matrix::Vector3(mat) => mat.borrow().write_le(out),
849      #[cfg(feature = "vector4")]
850      Matrix::Vector4(mat) => mat.borrow().write_le(out),
851    }
852  }
853  fn from_le(bytes: &[u8]) -> Self {
854    let mut cursor = Cursor::new(bytes);
855    let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
856    let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
857    let mut elements = Vec::with_capacity(rows * cols);
858    // Read in column-major order
859    for _c in 0..cols {
860      for _r in 0..rows {
861        let elem = T::from_le(&bytes[cursor.position() as usize..]);
862        let mut buf = Vec::new();
863        elem.write_le(&mut buf);
864        cursor.set_position(cursor.position() + buf.len() as u64);
865        elements.push(elem);
866      }
867    }
868    if rows == 0 || cols == 0 {
869      panic!("Cannot create Matrix with zero rows or columns");
870    } else if cols == 1 {
871      match rows {
872        #[cfg(feature = "matrix1")]
873        1 => Matrix::Matrix1(Ref::new(Matrix1::from_vec(elements))),
874        #[cfg(all(feature = "matrixd", not(feature = "matrix1")))]
875        1 => Matrix::DMatrix(Ref::new(DMatrix::from_vec(1,1, elements))),
876        #[cfg(feature = "vector2")]
877        2 => Matrix::Vector2(Ref::new(Vector2::from_vec(elements))),
878        #[cfg(feature = "vector3")]
879        3 => Matrix::Vector3(Ref::new(Vector3::from_vec(elements))),
880        #[cfg(feature = "vector4")]
881        4 => Matrix::Vector4(Ref::new(Vector4::from_vec(elements))),
882        #[cfg(feature = "vectord")]
883        _ => Matrix::DVector(Ref::new(DVector::from_vec(elements))),
884        _ => panic!("No suitable Matrix variant for dimensions {}x{}", rows, cols),
885      }
886    } else if rows == 1 {
887      match cols {
888        #[cfg(feature = "row_vector2")]
889        2 => Matrix::RowVector2(Ref::new(RowVector2::from_vec(elements))),
890        #[cfg(feature = "row_vector3")]
891        3 => Matrix::RowVector3(Ref::new(RowVector3::from_vec(elements))),
892        #[cfg(feature = "row_vector4")]
893        4 => Matrix::RowVector4(Ref::new(RowVector4::from_vec(elements))),
894        #[cfg(feature = "row_vectord")]
895        _ => Matrix::RowDVector(Ref::new(RowDVector::from_vec(elements))),
896        _ => panic!("No suitable Matrix variant for dimensions {}x{}", rows, cols),
897      }
898    } else {
899      match (rows, cols) {
900        #[cfg(feature = "matrix1")]
901        (1, 1) => Matrix::Matrix1(Ref::new(Matrix1::from_row_slice(&elements))),
902        #[cfg(feature = "matrix2")]
903        (2, 2) => Matrix::Matrix2(Ref::new(Matrix2::from_row_slice(&elements))),
904        #[cfg(feature = "matrix3")]
905        (3, 3) => Matrix::Matrix3(Ref::new(Matrix3::from_row_slice(&elements))),
906        #[cfg(feature = "matrix4")]
907        (4, 4) => Matrix::Matrix4(Ref::new(Matrix4::from_row_slice(&elements))),
908        #[cfg(feature = "matrix2x3")]
909        (2, 3) => Matrix::Matrix2x3(Ref::new(Matrix2x3::from_row_slice(&elements))),
910        #[cfg(feature = "matrix3x2")]
911        (3, 2) => Matrix::Matrix3x2(Ref::new(Matrix3x2::from_row_slice(&elements))),
912        #[cfg(feature = "matrixd")]
913        _ => Matrix::DMatrix(Ref::new(DMatrix::from_vec(rows, cols, elements))),
914        _ => panic!("No suitable Matrix variant for dimensions {}x{}", rows, cols),
915      }
916    }
917  }
918  fn value_kind(&self) -> ValueKind { self.value_kind() }
919  fn align() -> u8 { T::align() }
920}
921
922
923impl ConstElem for Value {
924  fn write_le(&self, out: &mut Vec<u8>) {
925    // Write the kind tag first
926    self.kind().write_le(out);
927
928    // Then write the payload
929    match self {
930      Value::Empty => { 
931        // no payload for Empty 
932      },
933      #[cfg(feature = "bool")]
934      Value::Bool(x) => x.borrow().write_le(out),
935      #[cfg(feature = "string")]
936      Value::String(x) => x.borrow().write_le(out),
937      #[cfg(feature = "u8")]
938      Value::U8(x) => x.borrow().write_le(out),
939      #[cfg(feature = "u16")]
940      Value::U16(x) => x.borrow().write_le(out),
941      #[cfg(feature = "u32")]
942      Value::U32(x) => x.borrow().write_le(out),
943      #[cfg(feature = "u64")]
944      Value::U64(x) => x.borrow().write_le(out),
945      #[cfg(feature = "u128")]
946      Value::U128(x) => x.borrow().write_le(out),
947      #[cfg(feature = "i8")]
948      Value::I8(x) => x.borrow().write_le(out),
949      #[cfg(feature = "i16")]
950      Value::I16(x) => x.borrow().write_le(out),
951      #[cfg(feature = "i32")]
952      Value::I32(x) => x.borrow().write_le(out),
953      #[cfg(feature = "i64")]
954      Value::I64(x) => x.borrow().write_le(out),
955      #[cfg(feature = "i128")]
956      Value::I128(x) => x.borrow().write_le(out),
957      #[cfg(feature = "f32")]
958      Value::F32(x) => x.borrow().write_le(out),
959      #[cfg(feature = "f64")]
960      Value::F64(x) => x.borrow().write_le(out),
961      #[cfg(feature = "rational")]
962      Value::R64(x) => x.borrow().write_le(out),
963      #[cfg(feature = "complex")]
964      Value::C64(x) => x.borrow().write_le(out),
965      #[cfg(feature = "set")]
966      Value::Set(x) => x.borrow().write_le(out),
967      _ => unimplemented!("write_le not implemented for this Value variant"),
968    }
969  }
970  fn from_le(bytes: &[u8]) -> Self {
971    let mut cursor = std::io::Cursor::new(bytes);
972
973    // 1. read ValueKind
974    let kind = ValueKind::from_le(cursor.get_ref());
975
976    // 2. determine the offset of the payload (length of encoded kind)
977    let mut kind_buf = Vec::new();
978    kind.write_le(&mut kind_buf);
979    let payload = &bytes[kind_buf.len()..];
980
981    // 3. dispatch based on ValueKind
982    match kind {
983      ValueKind::Empty => Value::Empty,
984      #[cfg(feature = "bool")]
985      ValueKind::Bool => Value::Bool(Ref::new(<bool as ConstElem>::from_le(payload))),
986      #[cfg(feature = "string")]
987      ValueKind::String => Value::String(Ref::new(<String as ConstElem>::from_le(payload))),
988      #[cfg(feature = "u8")]
989      ValueKind::U8 => Value::U8(Ref::new(<u8 as ConstElem>::from_le(payload))),
990      #[cfg(feature = "u16")]
991      ValueKind::U16 => Value::U16(Ref::new(<u16 as ConstElem>::from_le(payload))),
992      #[cfg(feature = "u32")]
993      ValueKind::U32 => Value::U32(Ref::new(<u32 as ConstElem>::from_le(payload))),
994      #[cfg(feature = "u64")]
995      ValueKind::U64 => Value::U64(Ref::new(<u64 as ConstElem>::from_le(payload))),
996      #[cfg(feature = "u128")]
997      ValueKind::U128 => Value::U128(Ref::new(<u128 as ConstElem>::from_le(payload))),
998      #[cfg(feature = "i8")]
999      ValueKind::I8 => Value::I8(Ref::new(<i8 as ConstElem>::from_le(payload))),
1000      #[cfg(feature = "i16")]
1001      ValueKind::I16 => Value::I16(Ref::new(<i16 as ConstElem>::from_le(payload))),
1002      #[cfg(feature = "i32")]
1003      ValueKind::I32 => Value::I32(Ref::new(<i32 as ConstElem>::from_le(payload))),
1004      #[cfg(feature = "i64")]
1005      ValueKind::I64 => Value::I64(Ref::new(<i64 as ConstElem>::from_le(payload))),
1006      #[cfg(feature = "i128")]
1007      ValueKind::I128 => Value::I128(Ref::new(<i128 as ConstElem>::from_le(payload))),
1008      #[cfg(feature = "f32")]
1009      ValueKind::F32 => Value::F32(Ref::new(<F32 as ConstElem>::from_le(payload))),
1010      #[cfg(feature = "f64")]
1011      ValueKind::F64 => Value::F64(Ref::new(<F64 as ConstElem>::from_le(payload))),
1012      #[cfg(feature = "rational")]
1013      ValueKind::R64 => Value::R64(Ref::new(<R64 as ConstElem>::from_le(payload))),
1014      #[cfg(feature = "complex")]
1015      ValueKind::C64 => Value::C64(Ref::new(<C64 as ConstElem>::from_le(payload))),
1016      x => unimplemented!("from_le not implemented for this ValueKind variant: {:?}", x),
1017    }
1018  }
1019  fn value_kind(&self) -> ValueKind {
1020    self.value_kind()
1021  }
1022  fn align() -> u8 {
1023    1
1024  }
1025}
1026
1027impl ConstElem for ValueKind {
1028  fn write_le(&self, out: &mut Vec<u8>) {
1029    match self {
1030      ValueKind::U8 => out.write_u8(1).expect("write value kind"),
1031      ValueKind::U16 => out.write_u8(2).expect("write value kind"),
1032      ValueKind::U32 => out.write_u8(3).expect("write value kind"),
1033      ValueKind::U64 => out.write_u8(4).expect("write value kind"),
1034      ValueKind::U128 => out.write_u8(5).expect("write value kind"),
1035      ValueKind::I8 => out.write_u8(6).expect("write value kind"),
1036      ValueKind::I16 => out.write_u8(7).expect("write value kind"),
1037      ValueKind::I32 => out.write_u8(8).expect("write value kind"),
1038      ValueKind::I64 => out.write_u8(9).expect("write value kind"),
1039      ValueKind::I128 => out.write_u8(10).expect("write value kind"),
1040      ValueKind::F32 => out.write_u8(11).expect("write value kind"),
1041      ValueKind::F64 => out.write_u8(12).expect("write value kind"),
1042      ValueKind::C64 => out.write_u8(13).expect("write value kind"),
1043      ValueKind::R64 => out.write_u8(14).expect("write value kind"),
1044      ValueKind::String => out.write_u8(15).expect("write value kind"),
1045      ValueKind::Bool => out.write_u8(16).expect("write value kind"),
1046      ValueKind::Id => out.write_u8(17).expect("write value kind"),
1047      ValueKind::Index => out.write_u8(18).expect("write value kind"),
1048      ValueKind::Empty => out.write_u8(19).expect("write value kind"),
1049      ValueKind::Any => out.write_u8(20).expect("write value kind"),
1050      ValueKind::Matrix(elem_vk, dims) => {
1051        out.write_u8(21).expect("write value kind");
1052        elem_vk.write_le(out);
1053        out.write_u32::<LittleEndian>(dims.len() as u32).expect("write matrix dims length");
1054        for d in dims.iter() {
1055          out.write_u32::<LittleEndian>(*d as u32).expect("write matrix dim");
1056        }
1057      },
1058      ValueKind::Enum(id) => {
1059        out.write_u8(22).expect("write value kind");
1060        out.write_u64::<LittleEndian>(*id).expect("write enum id");
1061      },
1062      #[cfg(feature = "record")]
1063      ValueKind::Record(fields) => {
1064        out.write_u8(23).expect("write value kind");
1065        out.write_u32::<LittleEndian>(fields.len() as u32).expect("write record fields length");
1066        for (name, vk) in fields.iter() {
1067          name.write_le(out);
1068          vk.write_le(out);
1069        }
1070      },
1071      ValueKind::Map(key_vk, val_vk) => {
1072        out.write_u8(24).expect("write value kind");
1073        key_vk.write_le(out);
1074        val_vk.write_le(out);
1075      },
1076      ValueKind::Atom(id) => {
1077        out.write_u8(25).expect("write value kind");
1078        out.write_u64::<LittleEndian>(*id).expect("write atom id");
1079      },
1080      #[cfg(feature = "table")]
1081      ValueKind::Table(fields, row_count) => {
1082        out.write_u8(26).expect("write value kind");
1083        out.write_u32::<LittleEndian>(fields.len() as u32).expect("write table fields length");
1084        for (name, vk) in fields.iter() {
1085          name.write_le(out);
1086          vk.write_le(out);
1087        }
1088        out.write_u32::<LittleEndian>(*row_count as u32).expect("write table row count");
1089      },
1090      ValueKind::Tuple(vks) => {
1091        out.write_u8(27).expect("write value kind");
1092        out.write_u32::<LittleEndian>(vks.len() as u32).expect("write tuple length");
1093        for vk in vks.iter() {
1094          vk.write_le(out);
1095        }
1096      },
1097      ValueKind::Reference(vk) => {
1098        out.write_u8(28).expect("write value kind");
1099        vk.write_le(out);
1100      },
1101      ValueKind::Set(vk, opt_size) => {
1102        out.write_u8(29).expect("write value kind");
1103        vk.write_le(out);
1104        match opt_size {
1105          Some(sz) => {
1106            out.write_u8(1).expect("write set size flag");
1107            out.write_u32::<LittleEndian>(*sz as u32).expect("write set size");
1108          },
1109          None => {
1110            out.write_u8(0).expect("write set size flag");
1111          }
1112        }
1113      },
1114      ValueKind::Option(vk) => {
1115        out.write_u8(30).expect("write value kind");
1116        vk.write_le(out);
1117      },
1118      _ => unimplemented!("write_le not implemented for this ValueKind variant"),
1119    }
1120  }
1121  fn from_le(bytes: &[u8]) -> Self {
1122    let mut cursor = Cursor::new(bytes);
1123    let tag = cursor.read_u8().expect("read value kind tag");
1124
1125    match tag {
1126      0 => ValueKind::Empty,
1127      1 => ValueKind::U8,
1128      2 => ValueKind::U16,
1129      3 => ValueKind::U32,
1130      4 => ValueKind::U64,
1131      5 => ValueKind::U128,
1132      6 => ValueKind::I8,
1133      7 => ValueKind::I16,
1134      8 => ValueKind::I32,
1135      9 => ValueKind::I64,
1136      10 => ValueKind::I128,
1137      11 => ValueKind::F32,
1138      12 => ValueKind::F64,
1139      13 => ValueKind::C64,
1140      14 => ValueKind::R64,
1141      15 => ValueKind::String,
1142      16 => ValueKind::Bool,
1143      17 => ValueKind::Id,
1144      18 => ValueKind::Index,
1145      19 => ValueKind::Empty,
1146      20 => ValueKind::Any,
1147      #[cfg(feature = "matrix")]
1148      21 => {
1149        let elem_vk = ValueKind::from_le(&bytes[cursor.position() as usize..]);
1150        cursor.set_position(cursor.position() + 1); // advance past elem_vk tag
1151        let dim_count = cursor.read_u32::<LittleEndian>().expect("read matrix dim count") as usize;
1152        let mut dims = Vec::with_capacity(dim_count);
1153        for _ in 0..dim_count {
1154            dims.push(cursor.read_u32::<LittleEndian>().expect("read matrix dim") as usize);
1155        }
1156        ValueKind::Matrix(Box::new(elem_vk), dims)
1157      }
1158      #[cfg(feature = "enum")]
1159      22 => ValueKind::Enum(cursor.read_u64::<LittleEndian>().expect("read enum id")),
1160      #[cfg(feature = "table")]
1161      26 => {
1162        let field_count = cursor.read_u32::<LittleEndian>().expect("read table fields length") as usize;
1163        let mut fields = Vec::with_capacity(field_count);
1164        for _ in 0..field_count {
1165          let name = String::from_le(&bytes[cursor.position() as usize..]);
1166          let mut buf = Vec::new();
1167          name.write_le(&mut buf);
1168          cursor.set_position(cursor.position() + buf.len() as u64);
1169          let vk = ValueKind::from_le(&bytes[cursor.position() as usize..]);
1170          let mut buf = Vec::new();
1171          vk.write_le(&mut buf);
1172          cursor.set_position(cursor.position() + buf.len() as u64);
1173          fields.push((name, vk));
1174        }
1175        let row_count = cursor.read_u32::<LittleEndian>().expect("read table row count") as usize;
1176        ValueKind::Table(fields, row_count)
1177      }
1178      #[cfg(feature = "set")]
1179      29 => {
1180        let elem_vk = ValueKind::from_le(&bytes[cursor.position() as usize..]);
1181        cursor.set_position(cursor.position() + 1);
1182        let size_flag = cursor.read_u8().expect("read set size flag");
1183        let opt_size = if size_flag != 0 {
1184            Some(cursor.read_u32::<LittleEndian>().expect("read set size") as usize)
1185        } else {
1186            None
1187        };
1188        ValueKind::Set(Box::new(elem_vk), opt_size)
1189      }
1190      x => unimplemented!("from_le not implemented for this ValueKind variant: {:?}", x),
1191    }
1192  }
1193  fn value_kind(&self) -> ValueKind { self.clone() }
1194  fn align() -> u8 { 1 }
1195}
1196
1197// helper to read a length-prefixed string from cursor
1198fn read_string_from_cursor(cursor: &mut std::io::Cursor<&[u8]>) -> Vec<u8> {
1199  let len = cursor.read_u32::<LittleEndian>().expect("read string len") as usize;
1200  let mut buf = vec![0u8; len];
1201  cursor.read_exact(&mut buf).expect("read string bytes");
1202  buf
1203}
1204
1205#[cfg(feature = "enum")]
1206impl ConstElem for MechEnum {
1207  fn write_le(&self, out: &mut Vec<u8>) {
1208    // write the enum id
1209    out.write_u64::<LittleEndian>(self.id).expect("write enum id");
1210
1211    // write the number of variants
1212    out.write_u32::<LittleEndian>(self.variants.len() as u32).expect("write enum variants length");
1213
1214    // write each variant: (variant id, has value, value data)
1215    for (variant_id, variant_value) in self.variants.iter() {
1216      // variant id
1217      out.write_u64::<LittleEndian>(*variant_id).expect("write enum variant id");
1218      match variant_value {
1219        Some(v) => {
1220          // has value
1221          out.write_u8(1).expect("write enum variant has value");
1222          // value kind
1223          let value_kind = v.kind();
1224          value_kind.write_le(out);
1225          // value data
1226          v.write_le(out);
1227        },
1228        None => {
1229          // has no value
1230          out.write_u8(0).expect("write enum variant has no value");
1231        }
1232      }
1233    }
1234  }
1235  fn from_le(_bytes: &[u8]) -> Self {
1236    unimplemented!("from_le not implemented for MechEnum")
1237  }
1238  fn value_kind(&self) -> ValueKind { ValueKind::Enum(0) } // id 0 as placeholder
1239  fn align() -> u8 { 8 }
1240}
1241
1242#[cfg(feature = "table")]
1243impl ConstElem for MechTable {
1244  fn write_le(&self, out: &mut Vec<u8>) {
1245    // Write kind
1246    self.value_kind().write_le(out);
1247    // Write number of rows and columns
1248    out.write_u32::<LittleEndian>(self.rows as u32).expect("write table rows");
1249    out.write_u32::<LittleEndian>(self.cols as u32).expect("write table cols");
1250    // Write each column: (id, kind, data, name)
1251    for (col_id, (vk, col_data)) in &self.data {
1252      // Column id
1253      out.write_u64::<LittleEndian>(*col_id).expect("write column id");
1254      // Value kind
1255      vk.write_le(out);
1256      // Column data matrix
1257      col_data.write_le(out);
1258      // Column name
1259      if let Some(name) = self.col_names.get(col_id) {
1260        name.write_le(out);
1261      } else {
1262        String::from("").write_le(out);
1263      }
1264    }
1265  }
1266  fn from_le(data: &[u8]) -> Self {
1267    use indexmap::IndexMap;
1268    let mut cursor = Cursor::new(data);
1269    // Kind
1270    let kind = ValueKind::from_le(cursor.get_ref());
1271    let mut buf = Vec::new();
1272    kind.write_le(&mut buf);
1273    cursor.set_position(buf.len() as u64);
1274
1275    // Read row and column counts
1276    let rows = cursor.read_u32::<LittleEndian>().expect("read rows") as usize;
1277    let cols = cursor.read_u32::<LittleEndian>().expect("read cols") as usize;
1278
1279    let mut data_map: IndexMap<u64, (ValueKind, Matrix<Value>)> = IndexMap::new();
1280    let mut col_names: HashMap<u64, String> = HashMap::new();
1281
1282    // Decode each column
1283    for _ in 0..cols {
1284      let col_id = cursor.read_u64::<LittleEndian>().expect("read column id");
1285
1286      // read value kind
1287      let kind = ValueKind::from_le(&data[cursor.position() as usize..]);
1288      let mut tmp = Vec::new();
1289      kind.write_le(&mut tmp);
1290      cursor.set_position(cursor.position() + tmp.len() as u64);
1291
1292      // read matrix
1293      let matrix = Matrix::<Value>::from_le(&data[cursor.position() as usize..]);
1294      let mut tmp = Vec::new();
1295      matrix.write_le(&mut tmp);
1296      cursor.set_position(cursor.position() + tmp.len() as u64);
1297
1298      // read column name
1299      let name = String::from_le(&data[cursor.position() as usize..]);
1300      let mut tmp = Vec::new();
1301      name.write_le(&mut tmp);
1302      cursor.set_position(cursor.position() + tmp.len() as u64);
1303
1304      data_map.insert(col_id, (kind, matrix));
1305      col_names.insert(col_id, name);
1306    }
1307
1308    MechTable { rows, cols, data: data_map, col_names }
1309  }
1310  fn value_kind(&self) -> ValueKind { self.kind() }
1311  fn align() -> u8 { 8 }
1312}
1313
1314#[cfg(feature = "table")]
1315impl CompileConst for MechTable {
1316  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
1317    let mut payload = Vec::<u8>::new();
1318    self.value_kind().write_le(&mut payload);
1319    payload.write_u32::<LittleEndian>(self.rows as u32)?;
1320    payload.write_u32::<LittleEndian>(self.cols as u32)?;
1321    for (col_id, (vk, col_data)) in &self.data {
1322      payload.write_u64::<LittleEndian>(*col_id)?;
1323      vk.write_le(&mut payload);
1324      col_data.write_le(&mut payload);
1325
1326      if let Some(name) = self.col_names.get(col_id) {
1327        name.write_le(&mut payload);
1328      } else {
1329        String::from("").write_le(&mut payload);
1330      }
1331    }
1332    ctx.compile_const(&payload, self.value_kind())
1333  }
1334}
1335
1336#[cfg(feature = "set")]
1337impl ConstElem for MechSet {
1338  fn write_le(&self, out: &mut Vec<u8>) {
1339    // write kind
1340    self.kind.write_le(out);
1341    // write element count
1342    out.write_u32::<LittleEndian>(self.num_elements as u32)
1343      .expect("write set element count");
1344    // write each element
1345    for value in &self.set {
1346      value.write_le(out);
1347    }
1348  }
1349  fn from_le(data: &[u8]) -> Self {
1350    use indexmap::IndexSet;
1351    let mut cursor = Cursor::new(data);
1352    // 1) read kind from current position
1353    let start = cursor.position() as usize;
1354    let kind = ValueKind::from_le(&data[start..]);
1355    // compute how many bytes the kind encoding consumes (so we can advance)
1356    let mut kind_buf = Vec::new();
1357    kind.write_le(&mut kind_buf);
1358    cursor.set_position(start as u64 + kind_buf.len() as u64);
1359    // 2) element count (little endian)
1360    let num_elements = cursor
1361      .read_u32::<LittleEndian>()
1362      .expect("read set element count") as usize;
1363    // 3) read each Value (advance cursor using each value's encoded length)
1364    let mut set = IndexSet::with_capacity(num_elements);
1365    for _ in 0..num_elements {
1366      let pos = cursor.position() as usize;
1367      let value = Value::from_le(&data[pos..]);
1368      // measure its encoded length by re-serializing
1369      let mut tmp = Vec::new();
1370      value.write_le(&mut tmp);
1371      cursor.set_position(pos as u64 + tmp.len() as u64);
1372      set.insert(value);
1373    }
1374    Self { kind, num_elements, set }
1375  }
1376  fn value_kind(&self) -> ValueKind { self.kind.clone() }
1377  fn align() -> u8 { 8 }
1378}
1379
1380#[cfg(feature = "tuple")]
1381impl ConstElem for MechTuple {
1382  fn write_le(&self, out: &mut Vec<u8>) {
1383    self.value_kind().write_le(out);
1384    out.write_u32::<LittleEndian>(self.elements.len() as u32)
1385      .expect("write tuple element count");
1386    for elem in &self.elements {
1387      elem.write_le(out);
1388    }
1389  }
1390  fn from_le(data: &[u8]) -> Self {
1391    let mut cursor = Cursor::new(data);
1392    // 1) Read ValueKind (tuple kind)
1393    let start = cursor.position() as usize;
1394    let kind = ValueKind::from_le(&data[start..]);
1395    // Determine how many bytes were used for kind
1396    let mut kind_buf = Vec::new();
1397    kind.write_le(&mut kind_buf);
1398    cursor.set_position(start as u64 + kind_buf.len() as u64);
1399    // 2) Read element count
1400    let num_elements = cursor
1401      .read_u32::<LittleEndian>()
1402      .expect("read tuple element count") as usize;
1403    // 3) Read each element
1404    let mut elements: Vec<Box<Value>> = Vec::with_capacity(num_elements);
1405    for _ in 0..num_elements {
1406      let pos = cursor.position() as usize;
1407      let value = Value::from_le(&data[pos..]);
1408      // Measure how many bytes were consumed by this value
1409      let mut tmp = Vec::new();
1410      value.write_le(&mut tmp);
1411      cursor.set_position(pos as u64 + tmp.len() as u64);
1412      elements.push(Box::new(value));
1413    }
1414    Self { elements }
1415  }
1416  fn value_kind(&self) -> ValueKind {
1417    ValueKind::Tuple(
1418      self.elements
1419        .iter()
1420        .map(|v| v.value_kind())
1421        .collect::<Vec<_>>()
1422    )
1423  }  
1424  fn align() -> u8 { 8 }
1425}