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