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