Skip to main content

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