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)?;
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)?;
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
449macro_rules! impl_const_elem {
450  ($feature:literal, $t:ty, $align:expr) => {
451    paste!{
452      #[cfg(feature = $feature)]
453      impl ConstElem for $t {
454        fn write_le(&self, out: &mut Vec<u8>) {
455          out.[<write_ $t>]::<LittleEndian>(*self).expect(concat!("write ", stringify!($t)));
456        }
457        fn from_le(bytes: &[u8]) -> Self {
458          let mut rdr = std::io::Cursor::new(bytes);
459          rdr.[<read_ $t>]::<LittleEndian>().expect(concat!("read ", stringify!($t)))
460        }
461        fn value_kind(&self) -> ValueKind { ValueKind::[<$t:upper>] }
462        fn align() -> u8 { $align }
463      }
464    }
465  };
466}
467
468#[cfg(feature = "u16")]
469impl_const_elem!("u16", u16, 2);
470#[cfg(feature = "u32")]
471impl_const_elem!("u32", u32, 4);
472#[cfg(feature = "u64")]
473impl_const_elem!("u64", u64, 8);
474#[cfg(feature = "u128")]
475impl_const_elem!("u128", u128, 16);
476#[cfg(feature = "i16")]
477impl_const_elem!("i16", i16, 2);
478#[cfg(feature = "i32")]
479impl_const_elem!("i32", i32, 4);
480#[cfg(feature = "i64")]
481impl_const_elem!("i64", i64, 8);
482#[cfg(feature = "i128")]
483impl_const_elem!("i128", i128, 16);
484#[cfg(feature = "f32")]
485impl_const_elem!("f32", f32, 4);
486#[cfg(feature = "f64")]
487impl_const_elem!("f64", f64, 8);
488
489#[cfg(feature = "u8")]
490impl ConstElem for u8 {
491  fn write_le(&self, out: &mut Vec<u8>) {
492    out.write_u8(*self).expect("write u8");
493  }
494  fn from_le(bytes: &[u8]) -> Self {
495    bytes[0]
496  }
497  fn value_kind(&self) -> ValueKind { ValueKind::U8 }
498  fn align() -> u8 { 1 }
499} 
500
501#[cfg(feature = "i8")]
502impl ConstElem for i8 {
503  fn write_le(&self, out: &mut Vec<u8>) {
504    out.write_i8(*self).expect("write i8");
505  }
506  fn from_le(bytes: &[u8]) -> Self {
507    bytes[0] as i8
508  }
509  fn value_kind(&self) -> ValueKind { ValueKind::I8 }
510  fn align() -> u8 { 1 }
511}
512
513#[cfg(feature = "rational")]
514impl ConstElem for R64 {
515  fn write_le(&self, out: &mut Vec<u8>) {
516    out.write_i64::<LittleEndian>(*self.numer()).expect("write rational numer");
517    out.write_i64::<LittleEndian>(*self.denom()).expect("write rational denom");
518  }
519  fn from_le(bytes: &[u8]) -> Self {
520    let numer = match bytes[0..8].try_into() {
521      Ok(arr) => i64::from_le_bytes(arr),
522      Err(_) => panic!("Failed to read numerator from bytes"),
523    };
524    let denom = match bytes[8..16].try_into() {
525      Ok(arr) => i64::from_le_bytes(arr),
526      Err(_) => panic!("Failed to read denominator from bytes"),
527    };
528    if denom == 0 {
529      panic!("Denominator cannot be zero");
530    }
531    R64::new(numer, denom)
532  }
533  fn value_kind(&self) -> ValueKind { ValueKind::R64 }
534  fn align() -> u8 { 16 }
535}
536
537#[cfg(feature = "complex")]
538impl ConstElem for C64 {
539  fn write_le(&self, out: &mut Vec<u8>) {
540    out.write_f64::<LittleEndian>(self.0.re).expect("write complex real");
541    out.write_f64::<LittleEndian>(self.0.im).expect("write complex imag");
542  }
543  fn from_le(bytes: &[u8]) -> Self {
544    let real = match bytes[0..8].try_into() {
545      Ok(arr) => f64::from_le_bytes(arr),
546      Err(_) => panic!("Failed to read real part from bytes"),
547    };
548    let imag = match bytes[8..16].try_into() {
549      Ok(arr) => f64::from_le_bytes(arr),
550      Err(_) => panic!("Failed to read imaginary part from bytes"),
551    };
552    C64::new(real, imag)
553  }
554  fn value_kind(&self) -> ValueKind { ValueKind::C64 }
555  fn align() -> u8 { 16 }
556}
557
558#[cfg(feature = "string")]
559impl ConstElem for String {
560  fn write_le(&self, out: &mut Vec<u8>) {
561    use byteorder::{LittleEndian, WriteBytesExt};
562    out.write_u32::<LittleEndian>(self.len() as u32).expect("write string length");
563    out.extend_from_slice(self.as_bytes());
564  }
565  fn from_le(bytes: &[u8]) -> Self {
566    use byteorder::{LittleEndian, ReadBytesExt};
567    use std::io::Cursor;
568    let mut cursor = Cursor::new(bytes);
569    // read length safely
570    let len = match cursor.read_u32::<LittleEndian>() {
571      Ok(n) => n as usize,
572      Err(_) => panic!("Failed to read string length from bytes"),
573    };
574    let start = cursor.position() as usize;
575    let end = start + len;
576    if end > bytes.len() {
577      panic!(
578        "String::from_le: declared length {} exceeds available bytes ({})",
579        len, bytes.len()
580      );
581    }
582    let str_bytes = &bytes[start..end];
583    match std::str::from_utf8(str_bytes) {
584      Ok(s) => s.to_string(),
585      Err(_) => panic!("Failed to convert bytes to UTF-8 string"),
586    }
587  }
588  fn value_kind(&self) -> ValueKind { ValueKind::String }
589  fn align() -> u8 { 1 }
590}
591
592#[cfg(feature = "bool")]
593impl ConstElem for bool {
594  fn write_le(&self, out: &mut Vec<u8>) {
595    out.write_u8(if *self { 1 } else { 0 }).expect("write bool");
596  }
597  fn from_le(bytes: &[u8]) -> Self {
598    bytes[0] != 0
599  }
600  fn value_kind(&self) -> ValueKind { ValueKind::Bool }
601  fn align() -> u8 { 1 }
602}
603
604impl ConstElem for usize {
605  fn write_le(&self, out: &mut Vec<u8>) {
606    out.write_u64::<LittleEndian>(*self as u64).expect("write usize");
607  }
608  fn from_le(bytes: &[u8]) -> Self {
609    let val = match bytes[0..8].try_into() {
610      Ok(arr) => u64::from_le_bytes(arr),
611      Err(_) => panic!("Failed to read usize from bytes"),
612    };
613    val as usize
614  }
615  fn value_kind(&self) -> ValueKind { ValueKind::Index }
616  fn align() -> u8 { 8 }
617}
618
619macro_rules! impl_const_elem_matrix {
620  ($matrix_type:ty) => {
621    impl<T> ConstElem for $matrix_type
622    where
623      T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
624    {
625      fn write_le(&self, out: &mut Vec<u8>) {
626        out.write_u32::<LittleEndian>(self.nrows() as u32).unwrap();
627        out.write_u32::<LittleEndian>(self.ncols() as u32).unwrap();
628        for c in 0..self.ncols() {
629          for r in 0..self.nrows() {
630            self[(r, c)].write_le(out);
631          }
632        }
633      }
634      fn from_le(bytes: &[u8]) -> Self {
635        let mut cursor = Cursor::new(bytes);
636        let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
637        let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
638        let mut elements: Vec<T> = Vec::with_capacity(rows * cols);
639
640        // Read in column-major order
641        for _c in 0..cols {
642          for _r in 0..rows {
643            let elem = T::from_le(&bytes[cursor.position() as usize..]);
644            let mut buf = Vec::new();
645            elem.write_le(&mut buf);
646            cursor.set_position(cursor.position() + buf.len() as u64);
647            elements.push(elem);
648          }
649        }
650        // Now construct the fixed-size matrix
651        // All nalgebra fixed-size matrices implement `from_row_slice`
652        <$matrix_type>::from_row_slice(&elements)
653      }
654      fn value_kind(&self) -> ValueKind { self.value_kind() }
655      fn align() -> u8 { 8 }
656    }
657  };
658}
659
660#[cfg(feature = "matrixd")]
661impl<T> ConstElem for DMatrix<T>
662where
663  T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
664{
665  fn write_le(&self, out: &mut Vec<u8>) {
666    out.write_u32::<LittleEndian>(self.nrows() as u32).unwrap();
667    out.write_u32::<LittleEndian>(self.ncols() as u32).unwrap();
668    for c in 0..self.ncols() {
669      for r in 0..self.nrows() {
670        self[(r, c)].write_le(out);
671      }
672    }
673  }
674  fn from_le(bytes: &[u8]) -> Self {
675    let mut cursor = Cursor::new(bytes);
676    let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
677    let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
678    let mut elements = Vec::with_capacity(rows * cols);
679    // Read in column-major order
680    for _c in 0..cols {
681      for _r in 0..rows {
682        let elem = T::from_le(&bytes[cursor.position() as usize..]);
683        let mut buf = Vec::new();
684        elem.write_le(&mut buf);
685        cursor.set_position(cursor.position() + buf.len() as u64);
686        elements.push(elem);
687      }
688    }
689    DMatrix::from_vec(rows, cols, elements)
690  }
691  fn value_kind(&self) -> ValueKind { self.value_kind() }
692  fn align() -> u8 { 8 }
693}
694
695#[cfg(feature = "vectord")]
696impl<T> ConstElem for DVector<T>
697where
698  T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
699{
700  fn write_le(&self, out: &mut Vec<u8>) {
701    out.write_u32::<LittleEndian>(self.nrows() as u32).unwrap();
702    out.write_u32::<LittleEndian>(self.ncols() as u32).unwrap();
703    for c in 0..self.ncols() {
704      for r in 0..self.nrows() {
705        self[(r, c)].write_le(out);
706      }
707    }
708  }
709  fn from_le(bytes: &[u8]) -> Self {
710    let mut cursor = Cursor::new(bytes);
711    let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
712    let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
713    let mut elements = Vec::with_capacity(rows * cols);
714    // Read in column-major order
715    for _c in 0..cols {
716      for _r in 0..rows {
717        let elem = T::from_le(&bytes[cursor.position() as usize..]);
718        let mut buf = Vec::new();
719        elem.write_le(&mut buf);
720        cursor.set_position(cursor.position() + buf.len() as u64);
721        elements.push(elem);
722      }
723    }
724    DVector::from_vec(elements)
725  }
726  fn value_kind(&self) -> ValueKind { self.value_kind() }
727  fn align() -> u8 { 8 }
728}
729
730#[cfg(feature = "row_vectord")]
731impl<T> ConstElem for RowDVector<T>
732where
733  T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
734{
735  fn write_le(&self, out: &mut Vec<u8>) {
736    out.write_u32::<LittleEndian>(self.nrows() as u32).unwrap();
737    out.write_u32::<LittleEndian>(self.ncols() as u32).unwrap();
738    for c in 0..self.ncols() {
739      for r in 0..self.nrows() {
740        self[(r, c)].write_le(out);
741      }
742    }
743  }
744  fn from_le(bytes: &[u8]) -> Self {
745    let mut cursor = Cursor::new(bytes);
746    let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
747    let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
748    let mut elements = Vec::with_capacity(rows * cols);
749    // Read in column-major order
750    for _c in 0..cols {
751      for _r in 0..rows {
752        let elem = T::from_le(&bytes[cursor.position() as usize..]);
753        let mut buf = Vec::new();
754        elem.write_le(&mut buf);
755        cursor.set_position(cursor.position() + buf.len() as u64);
756        elements.push(elem);
757      }
758    }
759    RowDVector::from_vec(elements)
760  }
761  fn value_kind(&self) -> ValueKind { self.value_kind() }
762  fn align() -> u8 { 8 }
763}
764
765#[cfg(feature = "matrix1")]
766impl_const_elem_matrix!(Matrix1<T>);
767#[cfg(feature = "matrix2")]
768impl_const_elem_matrix!(Matrix2<T>);
769#[cfg(feature = "matrix3")]
770impl_const_elem_matrix!(Matrix3<T>);
771#[cfg(feature = "matrix4")]
772impl_const_elem_matrix!(Matrix4<T>);
773#[cfg(feature = "matrix2x3")]
774impl_const_elem_matrix!(Matrix2x3<T>);
775#[cfg(feature = "matrix3x2")]
776impl_const_elem_matrix!(Matrix3x2<T>);
777#[cfg(feature = "row_vector2")]
778impl_const_elem_matrix!(RowVector2<T>);
779#[cfg(feature = "row_vector3")]
780impl_const_elem_matrix!(RowVector3<T>);
781#[cfg(feature = "row_vector4")]
782impl_const_elem_matrix!(RowVector4<T>);
783#[cfg(feature = "vector2")]
784impl_const_elem_matrix!(Vector2<T>);
785#[cfg(feature = "vector3")]
786impl_const_elem_matrix!(Vector3<T>);
787#[cfg(feature = "vector4")]
788impl_const_elem_matrix!(Vector4<T>);
789
790#[cfg(feature = "matrix")]
791impl<T> ConstElem for Matrix<T> 
792where
793  T: ConstElem + std::fmt::Debug + std::clone::Clone + PartialEq + 'static,
794{
795  fn write_le(&self, out: &mut Vec<u8>) {
796    match self {
797      #[cfg(feature = "matrixd")]
798      Matrix::DMatrix(mat) => mat.borrow().write_le(out),
799      #[cfg(feature = "vectord")]
800      Matrix::DVector(mat) => mat.borrow().write_le(out),
801      #[cfg(feature = "row_vectord")]
802      Matrix::RowDVector(mat) => mat.borrow().write_le(out),
803      #[cfg(feature = "matrix1")]
804      Matrix::Matrix1(mat) => mat.borrow().write_le(out),
805      #[cfg(feature = "matrix2")]
806      Matrix::Matrix2(mat) => mat.borrow().write_le(out),
807      #[cfg(feature = "matrix3")]
808      Matrix::Matrix3(mat) => mat.borrow().write_le(out),
809      #[cfg(feature = "matrix4")]
810      Matrix::Matrix4(mat) => mat.borrow().write_le(out),
811      #[cfg(feature = "matrix2x3")]
812      Matrix::Matrix2x3(mat) => mat.borrow().write_le(out),
813      #[cfg(feature = "matrix3x2")]
814      Matrix::Matrix3x2(mat) => mat.borrow().write_le(out),
815      #[cfg(feature = "row_vector2")]
816      Matrix::RowVector2(mat) => mat.borrow().write_le(out),
817      #[cfg(feature = "row_vector3")]
818      Matrix::RowVector3(mat) => mat.borrow().write_le(out),
819      #[cfg(feature = "row_vector4")]
820      Matrix::RowVector4(mat) => mat.borrow().write_le(out),
821      #[cfg(feature = "vector2")]
822      Matrix::Vector2(mat) => mat.borrow().write_le(out),
823      #[cfg(feature = "vector3")]
824      Matrix::Vector3(mat) => mat.borrow().write_le(out),
825      #[cfg(feature = "vector4")]
826      Matrix::Vector4(mat) => mat.borrow().write_le(out),
827    }
828  }
829  fn from_le(bytes: &[u8]) -> Self {
830    let mut cursor = Cursor::new(bytes);
831    let rows = cursor.read_u32::<LittleEndian>().unwrap() as usize;
832    let cols = cursor.read_u32::<LittleEndian>().unwrap() as usize;
833    let mut elements = Vec::with_capacity(rows * cols);
834    // Read in column-major order
835    for _c in 0..cols {
836      for _r in 0..rows {
837        let elem = T::from_le(&bytes[cursor.position() as usize..]);
838        let mut buf = Vec::new();
839        elem.write_le(&mut buf);
840        cursor.set_position(cursor.position() + buf.len() as u64);
841        elements.push(elem);
842      }
843    }
844    if rows == 0 || cols == 0 {
845      panic!("Cannot create Matrix with zero rows or columns");
846    } else if cols == 1 {
847      match rows {
848        #[cfg(feature = "matrix1")]
849        1 => Matrix::Matrix1(Ref::new(Matrix1::from_vec(elements))),
850        #[cfg(all(feature = "matrixd", not(feature = "matrix1")))]
851        1 => Matrix::DMatrix(Ref::new(DMatrix::from_vec(1,1, elements))),
852        #[cfg(feature = "vector2")]
853        2 => Matrix::Vector2(Ref::new(Vector2::from_vec(elements))),
854        #[cfg(feature = "vector3")]
855        3 => Matrix::Vector3(Ref::new(Vector3::from_vec(elements))),
856        #[cfg(feature = "vector4")]
857        4 => Matrix::Vector4(Ref::new(Vector4::from_vec(elements))),
858        #[cfg(feature = "vectord")]
859        _ => Matrix::DVector(Ref::new(DVector::from_vec(elements))),
860        _ => panic!("No suitable Matrix variant for dimensions {}x{}", rows, cols),
861      }
862    } else if rows == 1 {
863      match cols {
864        #[cfg(feature = "row_vector2")]
865        2 => Matrix::RowVector2(Ref::new(RowVector2::from_vec(elements))),
866        #[cfg(feature = "row_vector3")]
867        3 => Matrix::RowVector3(Ref::new(RowVector3::from_vec(elements))),
868        #[cfg(feature = "row_vector4")]
869        4 => Matrix::RowVector4(Ref::new(RowVector4::from_vec(elements))),
870        #[cfg(feature = "row_vectord")]
871        _ => Matrix::RowDVector(Ref::new(RowDVector::from_vec(elements))),
872        _ => panic!("No suitable Matrix variant for dimensions {}x{}", rows, cols),
873      }
874    } else {
875      match (rows, cols) {
876        #[cfg(feature = "matrix1")]
877        (1, 1) => Matrix::Matrix1(Ref::new(Matrix1::from_row_slice(&elements))),
878        #[cfg(feature = "matrix2")]
879        (2, 2) => Matrix::Matrix2(Ref::new(Matrix2::from_row_slice(&elements))),
880        #[cfg(feature = "matrix3")]
881        (3, 3) => Matrix::Matrix3(Ref::new(Matrix3::from_row_slice(&elements))),
882        #[cfg(feature = "matrix4")]
883        (4, 4) => Matrix::Matrix4(Ref::new(Matrix4::from_row_slice(&elements))),
884        #[cfg(feature = "matrix2x3")]
885        (2, 3) => Matrix::Matrix2x3(Ref::new(Matrix2x3::from_row_slice(&elements))),
886        #[cfg(feature = "matrix3x2")]
887        (3, 2) => Matrix::Matrix3x2(Ref::new(Matrix3x2::from_row_slice(&elements))),
888        #[cfg(feature = "matrixd")]
889        _ => Matrix::DMatrix(Ref::new(DMatrix::from_vec(rows, cols, elements))),
890        _ => panic!("No suitable Matrix variant for dimensions {}x{}", rows, cols),
891      }
892    }
893  }
894  fn value_kind(&self) -> ValueKind { self.value_kind() }
895  fn align() -> u8 { T::align() }
896}
897
898
899impl ConstElem for Value {
900  fn write_le(&self, out: &mut Vec<u8>) {
901    // Write the kind tag first
902    self.kind().write_le(out);
903
904    // Then write the payload
905    match self {
906      Value::Empty => { 
907        // no payload for Empty 
908      },
909      #[cfg(feature = "bool")]
910      Value::Bool(x) => x.borrow().write_le(out),
911      #[cfg(feature = "string")]
912      Value::String(x) => x.borrow().write_le(out),
913      #[cfg(feature = "u8")]
914      Value::U8(x) => x.borrow().write_le(out),
915      #[cfg(feature = "u16")]
916      Value::U16(x) => x.borrow().write_le(out),
917      #[cfg(feature = "u32")]
918      Value::U32(x) => x.borrow().write_le(out),
919      #[cfg(feature = "u64")]
920      Value::U64(x) => x.borrow().write_le(out),
921      #[cfg(feature = "u128")]
922      Value::U128(x) => x.borrow().write_le(out),
923      #[cfg(feature = "i8")]
924      Value::I8(x) => x.borrow().write_le(out),
925      #[cfg(feature = "i16")]
926      Value::I16(x) => x.borrow().write_le(out),
927      #[cfg(feature = "i32")]
928      Value::I32(x) => x.borrow().write_le(out),
929      #[cfg(feature = "i64")]
930      Value::I64(x) => x.borrow().write_le(out),
931      #[cfg(feature = "i128")]
932      Value::I128(x) => x.borrow().write_le(out),
933      #[cfg(feature = "f32")]
934      Value::F32(x) => x.borrow().write_le(out),
935      #[cfg(feature = "f64")]
936      Value::F64(x) => x.borrow().write_le(out),
937      #[cfg(feature = "rational")]
938      Value::R64(x) => x.borrow().write_le(out),
939      #[cfg(feature = "complex")]
940      Value::C64(x) => x.borrow().write_le(out),
941      #[cfg(feature = "set")]
942      Value::Set(x) => x.borrow().write_le(out),
943      _ => unimplemented!("write_le not implemented for this Value variant"),
944    }
945  }
946  fn from_le(bytes: &[u8]) -> Self {
947    let mut cursor = std::io::Cursor::new(bytes);
948
949    // 1. read ValueKind
950    let kind = ValueKind::from_le(cursor.get_ref());
951
952    // 2. determine the offset of the payload (length of encoded kind)
953    let mut kind_buf = Vec::new();
954    kind.write_le(&mut kind_buf);
955    let payload = &bytes[kind_buf.len()..];
956
957    // 3. dispatch based on ValueKind
958    match kind {
959      ValueKind::Empty => Value::Empty,
960      #[cfg(feature = "bool")]
961      ValueKind::Bool => Value::Bool(Ref::new(<bool as ConstElem>::from_le(payload))),
962      #[cfg(feature = "string")]
963      ValueKind::String => Value::String(Ref::new(<String as ConstElem>::from_le(payload))),
964      #[cfg(feature = "u8")]
965      ValueKind::U8 => Value::U8(Ref::new(<u8 as ConstElem>::from_le(payload))),
966      #[cfg(feature = "u16")]
967      ValueKind::U16 => Value::U16(Ref::new(<u16 as ConstElem>::from_le(payload))),
968      #[cfg(feature = "u32")]
969      ValueKind::U32 => Value::U32(Ref::new(<u32 as ConstElem>::from_le(payload))),
970      #[cfg(feature = "u64")]
971      ValueKind::U64 => Value::U64(Ref::new(<u64 as ConstElem>::from_le(payload))),
972      #[cfg(feature = "u128")]
973      ValueKind::U128 => Value::U128(Ref::new(<u128 as ConstElem>::from_le(payload))),
974      #[cfg(feature = "i8")]
975      ValueKind::I8 => Value::I8(Ref::new(<i8 as ConstElem>::from_le(payload))),
976      #[cfg(feature = "i16")]
977      ValueKind::I16 => Value::I16(Ref::new(<i16 as ConstElem>::from_le(payload))),
978      #[cfg(feature = "i32")]
979      ValueKind::I32 => Value::I32(Ref::new(<i32 as ConstElem>::from_le(payload))),
980      #[cfg(feature = "i64")]
981      ValueKind::I64 => Value::I64(Ref::new(<i64 as ConstElem>::from_le(payload))),
982      #[cfg(feature = "i128")]
983      ValueKind::I128 => Value::I128(Ref::new(<i128 as ConstElem>::from_le(payload))),
984      #[cfg(feature = "f32")]
985      ValueKind::F32 => Value::F32(Ref::new(<f32 as ConstElem>::from_le(payload))),
986      #[cfg(feature = "f64")]
987      ValueKind::F64 => Value::F64(Ref::new(<f64 as ConstElem>::from_le(payload))),
988      #[cfg(feature = "rational")]
989      ValueKind::R64 => Value::R64(Ref::new(<R64 as ConstElem>::from_le(payload))),
990      #[cfg(feature = "complex")]
991      ValueKind::C64 => Value::C64(Ref::new(<C64 as ConstElem>::from_le(payload))),
992      x => unimplemented!("from_le not implemented for this ValueKind variant: {:?}", x),
993    }
994  }
995  fn value_kind(&self) -> ValueKind {
996    self.value_kind()
997  }
998  fn align() -> u8 {
999    1
1000  }
1001}
1002
1003impl ConstElem for ValueKind {
1004  fn write_le(&self, out: &mut Vec<u8>) {
1005    match self {
1006      ValueKind::U8 => out.write_u8(1).expect("write value kind"),
1007      ValueKind::U16 => out.write_u8(2).expect("write value kind"),
1008      ValueKind::U32 => out.write_u8(3).expect("write value kind"),
1009      ValueKind::U64 => out.write_u8(4).expect("write value kind"),
1010      ValueKind::U128 => out.write_u8(5).expect("write value kind"),
1011      ValueKind::I8 => out.write_u8(6).expect("write value kind"),
1012      ValueKind::I16 => out.write_u8(7).expect("write value kind"),
1013      ValueKind::I32 => out.write_u8(8).expect("write value kind"),
1014      ValueKind::I64 => out.write_u8(9).expect("write value kind"),
1015      ValueKind::I128 => out.write_u8(10).expect("write value kind"),
1016      ValueKind::F32 => out.write_u8(11).expect("write value kind"),
1017      ValueKind::F64 => out.write_u8(12).expect("write value kind"),
1018      ValueKind::C64 => out.write_u8(13).expect("write value kind"),
1019      ValueKind::R64 => out.write_u8(14).expect("write value kind"),
1020      ValueKind::String => out.write_u8(15).expect("write value kind"),
1021      ValueKind::Bool => out.write_u8(16).expect("write value kind"),
1022      ValueKind::Id => out.write_u8(17).expect("write value kind"),
1023      ValueKind::Index => out.write_u8(18).expect("write value kind"),
1024      ValueKind::Empty => out.write_u8(19).expect("write value kind"),
1025      ValueKind::Any => out.write_u8(20).expect("write value kind"),
1026      ValueKind::Matrix(elem_vk, dims) => {
1027        out.write_u8(21).expect("write value kind");
1028        elem_vk.write_le(out);
1029        out.write_u32::<LittleEndian>(dims.len() as u32).expect("write matrix dims length");
1030        for d in dims.iter() {
1031          out.write_u32::<LittleEndian>(*d as u32).expect("write matrix dim");
1032        }
1033      },
1034      ValueKind::Enum(id) => {
1035        out.write_u8(22).expect("write value kind");
1036        out.write_u64::<LittleEndian>(*id).expect("write enum id");
1037      },
1038      #[cfg(feature = "record")]
1039      ValueKind::Record(fields) => {
1040        out.write_u8(23).expect("write value kind");
1041        out.write_u32::<LittleEndian>(fields.len() as u32).expect("write record fields length");
1042        for (name, vk) in fields.iter() {
1043          name.write_le(out);
1044          vk.write_le(out);
1045        }
1046      },
1047      ValueKind::Map(key_vk, val_vk) => {
1048        out.write_u8(24).expect("write value kind");
1049        key_vk.write_le(out);
1050        val_vk.write_le(out);
1051      },
1052      ValueKind::Atom(id) => {
1053        out.write_u8(25).expect("write value kind");
1054        out.write_u64::<LittleEndian>(*id).expect("write atom id");
1055      },
1056      #[cfg(feature = "table")]
1057      ValueKind::Table(fields, row_count) => {
1058        out.write_u8(26).expect("write value kind");
1059        out.write_u32::<LittleEndian>(fields.len() as u32).expect("write table fields length");
1060        for (name, vk) in fields.iter() {
1061          name.write_le(out);
1062          vk.write_le(out);
1063        }
1064        out.write_u32::<LittleEndian>(*row_count as u32).expect("write table row count");
1065      },
1066      ValueKind::Tuple(vks) => {
1067        out.write_u8(27).expect("write value kind");
1068        out.write_u32::<LittleEndian>(vks.len() as u32).expect("write tuple length");
1069        for vk in vks.iter() {
1070          vk.write_le(out);
1071        }
1072      },
1073      ValueKind::Reference(vk) => {
1074        out.write_u8(28).expect("write value kind");
1075        vk.write_le(out);
1076      },
1077      ValueKind::Set(vk, opt_size) => {
1078        out.write_u8(29).expect("write value kind");
1079        vk.write_le(out);
1080        match opt_size {
1081          Some(sz) => {
1082            out.write_u8(1).expect("write set size flag");
1083            out.write_u32::<LittleEndian>(*sz as u32).expect("write set size");
1084          },
1085          None => {
1086            out.write_u8(0).expect("write set size flag");
1087          }
1088        }
1089      },
1090      ValueKind::Option(vk) => {
1091        out.write_u8(30).expect("write value kind");
1092        vk.write_le(out);
1093      },
1094      _ => unimplemented!("write_le not implemented for this ValueKind variant"),
1095    }
1096  }
1097  fn from_le(bytes: &[u8]) -> Self {
1098    let mut cursor = Cursor::new(bytes);
1099    let tag = cursor.read_u8().expect("read value kind tag");
1100
1101    match tag {
1102      0 => ValueKind::Empty,
1103      1 => ValueKind::U8,
1104      2 => ValueKind::U16,
1105      3 => ValueKind::U32,
1106      4 => ValueKind::U64,
1107      5 => ValueKind::U128,
1108      6 => ValueKind::I8,
1109      7 => ValueKind::I16,
1110      8 => ValueKind::I32,
1111      9 => ValueKind::I64,
1112      10 => ValueKind::I128,
1113      11 => ValueKind::F32,
1114      12 => ValueKind::F64,
1115      13 => ValueKind::C64,
1116      14 => ValueKind::R64,
1117      15 => ValueKind::String,
1118      16 => ValueKind::Bool,
1119      17 => ValueKind::Id,
1120      18 => ValueKind::Index,
1121      19 => ValueKind::Empty,
1122      20 => ValueKind::Any,
1123      #[cfg(feature = "matrix")]
1124      21 => {
1125        let elem_vk = ValueKind::from_le(&bytes[cursor.position() as usize..]);
1126        cursor.set_position(cursor.position() + 1); // advance past elem_vk tag
1127        let dim_count = cursor.read_u32::<LittleEndian>().expect("read matrix dim count") as usize;
1128        let mut dims = Vec::with_capacity(dim_count);
1129        for _ in 0..dim_count {
1130            dims.push(cursor.read_u32::<LittleEndian>().expect("read matrix dim") as usize);
1131        }
1132        ValueKind::Matrix(Box::new(elem_vk), dims)
1133      }
1134      #[cfg(feature = "enum")]
1135      22 => ValueKind::Enum(cursor.read_u64::<LittleEndian>().expect("read enum id")),
1136      #[cfg(feature = "table")]
1137      26 => {
1138        let field_count = cursor.read_u32::<LittleEndian>().expect("read table fields length") as usize;
1139        let mut fields = Vec::with_capacity(field_count);
1140        for _ in 0..field_count {
1141          let name = String::from_le(&bytes[cursor.position() as usize..]);
1142          let mut buf = Vec::new();
1143          name.write_le(&mut buf);
1144          cursor.set_position(cursor.position() + buf.len() as u64);
1145          let vk = ValueKind::from_le(&bytes[cursor.position() as usize..]);
1146          let mut buf = Vec::new();
1147          vk.write_le(&mut buf);
1148          cursor.set_position(cursor.position() + buf.len() as u64);
1149          fields.push((name, vk));
1150        }
1151        let row_count = cursor.read_u32::<LittleEndian>().expect("read table row count") as usize;
1152        ValueKind::Table(fields, row_count)
1153      }
1154      #[cfg(feature = "set")]
1155      29 => {
1156        let elem_vk = ValueKind::from_le(&bytes[cursor.position() as usize..]);
1157        cursor.set_position(cursor.position() + 1);
1158        let size_flag = cursor.read_u8().expect("read set size flag");
1159        let opt_size = if size_flag != 0 {
1160            Some(cursor.read_u32::<LittleEndian>().expect("read set size") as usize)
1161        } else {
1162            None
1163        };
1164        ValueKind::Set(Box::new(elem_vk), opt_size)
1165      }
1166      x => unimplemented!("from_le not implemented for this ValueKind variant: {:?}", x),
1167    }
1168  }
1169  fn value_kind(&self) -> ValueKind { self.clone() }
1170  fn align() -> u8 { 1 }
1171}
1172
1173// helper to read a length-prefixed string from cursor
1174fn read_string_from_cursor(cursor: &mut std::io::Cursor<&[u8]>) -> Vec<u8> {
1175  let len = cursor.read_u32::<LittleEndian>().expect("read string len") as usize;
1176  let mut buf = vec![0u8; len];
1177  cursor.read_exact(&mut buf).expect("read string bytes");
1178  buf
1179}
1180
1181#[cfg(feature = "enum")]
1182impl ConstElem for MechEnum {
1183  fn write_le(&self, out: &mut Vec<u8>) {
1184    // write the enum id
1185    out.write_u64::<LittleEndian>(self.id).expect("write enum id");
1186
1187    // write the number of variants
1188    out.write_u32::<LittleEndian>(self.variants.len() as u32).expect("write enum variants length");
1189
1190    // write each variant: (variant id, has value, value data)
1191    for (variant_id, variant_value) in self.variants.iter() {
1192      // variant id
1193      out.write_u64::<LittleEndian>(*variant_id).expect("write enum variant id");
1194      match variant_value {
1195        Some(v) => {
1196          // has value
1197          out.write_u8(1).expect("write enum variant has value");
1198          // value kind
1199          let value_kind = v.kind();
1200          value_kind.write_le(out);
1201          // value data
1202          v.write_le(out);
1203        },
1204        None => {
1205          // has no value
1206          out.write_u8(0).expect("write enum variant has no value");
1207        }
1208      }
1209    }
1210  }
1211  fn from_le(_bytes: &[u8]) -> Self {
1212    unimplemented!("from_le not implemented for MechEnum")
1213  }
1214  fn value_kind(&self) -> ValueKind { ValueKind::Enum(0) } // id 0 as placeholder
1215  fn align() -> u8 { 8 }
1216}
1217
1218#[cfg(feature = "table")]
1219impl ConstElem for MechTable {
1220  fn write_le(&self, out: &mut Vec<u8>) {
1221    // Write kind
1222    self.value_kind().write_le(out);
1223    // Write number of rows and columns
1224    out.write_u32::<LittleEndian>(self.rows as u32).expect("write table rows");
1225    out.write_u32::<LittleEndian>(self.cols as u32).expect("write table cols");
1226    // Write each column: (id, kind, data, name)
1227    for (col_id, (vk, col_data)) in &self.data {
1228      // Column id
1229      out.write_u64::<LittleEndian>(*col_id).expect("write column id");
1230      // Value kind
1231      vk.write_le(out);
1232      // Column data matrix
1233      col_data.write_le(out);
1234      // Column name
1235      if let Some(name) = self.col_names.get(col_id) {
1236        name.write_le(out);
1237      } else {
1238        String::from("").write_le(out);
1239      }
1240    }
1241  }
1242  fn from_le(data: &[u8]) -> Self {
1243    use indexmap::IndexMap;
1244    let mut cursor = Cursor::new(data);
1245    // Kind
1246    let kind = ValueKind::from_le(cursor.get_ref());
1247    let mut buf = Vec::new();
1248    kind.write_le(&mut buf);
1249    cursor.set_position(buf.len() as u64);
1250
1251    // Read row and column counts
1252    let rows = cursor.read_u32::<LittleEndian>().expect("read rows") as usize;
1253    let cols = cursor.read_u32::<LittleEndian>().expect("read cols") as usize;
1254
1255    let mut data_map: IndexMap<u64, (ValueKind, Matrix<Value>)> = IndexMap::new();
1256    let mut col_names: HashMap<u64, String> = HashMap::new();
1257
1258    // Decode each column
1259    for _ in 0..cols {
1260      let col_id = cursor.read_u64::<LittleEndian>().expect("read column id");
1261
1262      // read value kind
1263      let kind = ValueKind::from_le(&data[cursor.position() as usize..]);
1264      let mut tmp = Vec::new();
1265      kind.write_le(&mut tmp);
1266      cursor.set_position(cursor.position() + tmp.len() as u64);
1267
1268      // read matrix
1269      let matrix = Matrix::<Value>::from_le(&data[cursor.position() as usize..]);
1270      let mut tmp = Vec::new();
1271      matrix.write_le(&mut tmp);
1272      cursor.set_position(cursor.position() + tmp.len() as u64);
1273
1274      // read column name
1275      let name = String::from_le(&data[cursor.position() as usize..]);
1276      let mut tmp = Vec::new();
1277      name.write_le(&mut tmp);
1278      cursor.set_position(cursor.position() + tmp.len() as u64);
1279
1280      data_map.insert(col_id, (kind, matrix));
1281      col_names.insert(col_id, name);
1282    }
1283
1284    MechTable { rows, cols, data: data_map, col_names }
1285  }
1286  fn value_kind(&self) -> ValueKind { self.kind() }
1287  fn align() -> u8 { 8 }
1288}
1289
1290#[cfg(feature = "table")]
1291impl CompileConst for MechTable {
1292  fn compile_const(&self, ctx: &mut CompileCtx) -> MResult<u32> {
1293    let mut payload = Vec::<u8>::new();
1294    self.value_kind().write_le(&mut payload);
1295    payload.write_u32::<LittleEndian>(self.rows as u32)?;
1296    payload.write_u32::<LittleEndian>(self.cols as u32)?;
1297    for (col_id, (vk, col_data)) in &self.data {
1298      payload.write_u64::<LittleEndian>(*col_id)?;
1299      vk.write_le(&mut payload);
1300      col_data.write_le(&mut payload);
1301
1302      if let Some(name) = self.col_names.get(col_id) {
1303        name.write_le(&mut payload);
1304      } else {
1305        String::from("").write_le(&mut payload);
1306      }
1307    }
1308    ctx.compile_const(&payload, self.value_kind())
1309  }
1310}
1311
1312#[cfg(feature = "set")]
1313impl ConstElem for MechSet {
1314  fn write_le(&self, out: &mut Vec<u8>) {
1315    // write kind
1316    self.kind.write_le(out);
1317    // write element count
1318    out.write_u32::<LittleEndian>(self.num_elements as u32)
1319      .expect("write set element count");
1320    // write each element
1321    for value in &self.set {
1322      value.write_le(out);
1323    }
1324  }
1325  fn from_le(data: &[u8]) -> Self {
1326    use indexmap::IndexSet;
1327    let mut cursor = Cursor::new(data);
1328    // 1) read kind from current position
1329    let start = cursor.position() as usize;
1330    let kind = ValueKind::from_le(&data[start..]);
1331    // compute how many bytes the kind encoding consumes (so we can advance)
1332    let mut kind_buf = Vec::new();
1333    kind.write_le(&mut kind_buf);
1334    cursor.set_position(start as u64 + kind_buf.len() as u64);
1335    // 2) element count (little endian)
1336    let num_elements = cursor
1337      .read_u32::<LittleEndian>()
1338      .expect("read set element count") as usize;
1339    // 3) read each Value (advance cursor using each value's encoded length)
1340    let mut set = IndexSet::with_capacity(num_elements);
1341    for _ in 0..num_elements {
1342      let pos = cursor.position() as usize;
1343      let value = Value::from_le(&data[pos..]);
1344      // measure its encoded length by re-serializing
1345      let mut tmp = Vec::new();
1346      value.write_le(&mut tmp);
1347      cursor.set_position(pos as u64 + tmp.len() as u64);
1348      set.insert(value);
1349    }
1350    Self { kind, num_elements, set }
1351  }
1352  fn value_kind(&self) -> ValueKind { self.kind.clone() }
1353  fn align() -> u8 { 8 }
1354}
1355
1356#[cfg(feature = "tuple")]
1357impl ConstElem for MechTuple {
1358  fn write_le(&self, out: &mut Vec<u8>) {
1359    self.value_kind().write_le(out);
1360    out.write_u32::<LittleEndian>(self.elements.len() as u32)
1361      .expect("write tuple element count");
1362    for elem in &self.elements {
1363      elem.write_le(out);
1364    }
1365  }
1366  fn from_le(data: &[u8]) -> Self {
1367    let mut cursor = Cursor::new(data);
1368    // 1) Read ValueKind (tuple kind)
1369    let start = cursor.position() as usize;
1370    let kind = ValueKind::from_le(&data[start..]);
1371    // Determine how many bytes were used for kind
1372    let mut kind_buf = Vec::new();
1373    kind.write_le(&mut kind_buf);
1374    cursor.set_position(start as u64 + kind_buf.len() as u64);
1375    // 2) Read element count
1376    let num_elements = cursor
1377      .read_u32::<LittleEndian>()
1378      .expect("read tuple element count") as usize;
1379    // 3) Read each element
1380    let mut elements: Vec<Box<Value>> = Vec::with_capacity(num_elements);
1381    for _ in 0..num_elements {
1382      let pos = cursor.position() as usize;
1383      let value = Value::from_le(&data[pos..]);
1384      // Measure how many bytes were consumed by this value
1385      let mut tmp = Vec::new();
1386      value.write_le(&mut tmp);
1387      cursor.set_position(pos as u64 + tmp.len() as u64);
1388      elements.push(Box::new(value));
1389    }
1390    Self { elements }
1391  }
1392  fn value_kind(&self) -> ValueKind {
1393    ValueKind::Tuple(
1394      self.elements
1395        .iter()
1396        .map(|v| v.value_kind())
1397        .collect::<Vec<_>>()
1398    )
1399  }  
1400  fn align() -> u8 { 8 }
1401}