mech_core/program/compiler/
constants.rs

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