dmap/
types.rs

1//! Low-level data types within DMAP records.
2use crate::error::DmapError;
3use indexmap::IndexMap;
4use numpy::array::PyArray;
5use numpy::ndarray::ArrayD;
6use numpy::PyArrayMethods;
7use paste::paste;
8use pyo3::exceptions::PyValueError;
9use pyo3::prelude::*;
10use pyo3::{Bound, FromPyObject, PyAny, PyResult, Python};
11use std::cmp::PartialEq;
12use std::fmt::{Display, Formatter};
13use std::io::Cursor;
14use zerocopy::{AsBytes, ByteOrder, FromBytes, LittleEndian};
15
16type Result<T> = std::result::Result<T, DmapError>;
17
18/// Defines the fields of a record and their [`Type`].
19pub struct Fields<'a> {
20    /// The names of all fields of the record type
21    pub all_fields: Vec<&'a str>,
22    /// The name and Type of each required scalar field
23    pub scalars_required: Vec<(&'a str, Type)>,
24    /// The name and Type of each optional scalar field
25    pub scalars_optional: Vec<(&'a str, Type)>,
26    /// The name and Type of each required vector field
27    pub vectors_required: Vec<(&'a str, Type)>,
28    /// The name and Type of each optional vector field
29    pub vectors_optional: Vec<(&'a str, Type)>,
30    /// Groups of vector fields which must have identical dimensions
31    pub vector_dim_groups: Vec<Vec<&'a str>>,
32    /// The name of each field which is a data (as opposed to metadata) field
33    pub data_fields: Vec<&'a str>,
34}
35
36/// The possible data types that a scalar or vector field may have.
37///
38/// **Note**: `String` type is not supported for vector fields.
39#[derive(Debug, PartialEq, Clone)]
40pub enum Type {
41    Char,
42    Short,
43    Int,
44    Long,
45    Uchar,
46    Ushort,
47    Uint,
48    Ulong,
49    Float,
50    Double,
51    String,
52}
53impl Display for Type {
54    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55        match self {
56            Self::Char => write!(f, "CHAR"),
57            Self::Short => write!(f, "SHORT"),
58            Self::Int => write!(f, "INT"),
59            Self::Float => write!(f, "FLOAT"),
60            Self::Double => write!(f, "DOUBLE"),
61            Self::String => write!(f, "STRING"),
62            Self::Long => write!(f, "LONG"),
63            Self::Uchar => write!(f, "UCHAR"),
64            Self::Ushort => write!(f, "USHORT"),
65            Self::Uint => write!(f, "UINT"),
66            Self::Ulong => write!(f, "ULONG"),
67        }
68    }
69}
70impl Type {
71    /// Converts from DMAP key to corresponding `Type` (see [here](https://github.com/SuperDARN/rst/blob/main/codebase/general/src.lib/dmap.1.25/include/dmap.h)).
72    /// Returns the `Type` if the key is supported, otherwise raises `DmapError`
73    fn from_key(key: i8) -> Result<Self> {
74        let data = match key {
75            1 => Self::Char,
76            2 => Self::Short,
77            3 => Self::Int,
78            10 => Self::Long,
79            16 => Self::Uchar,
80            17 => Self::Ushort,
81            18 => Self::Uint,
82            19 => Self::Ulong,
83            4 => Self::Float,
84            8 => Self::Double,
85            9 => Self::String,
86            x => Err(DmapError::InvalidKey(x))?,
87        };
88        Ok(data)
89    }
90    /// Returns the corresponding key for the `Type` variant.
91    fn key(&self) -> i8 {
92        match self {
93            Self::Char => 1,
94            Self::Short => 2,
95            Self::Int => 3,
96            Self::Long => 10,
97            Self::Uchar => 16,
98            Self::Ushort => 17,
99            Self::Uint => 18,
100            Self::Ulong => 19,
101            Self::Float => 4,
102            Self::Double => 8,
103            Self::String => 9,
104        }
105    }
106    /// The size in bytes of the data for `Type`
107    pub fn size(&self) -> usize {
108        match self {
109            Self::Char => 1,
110            Self::Short => 2,
111            Self::Int => 4,
112            Self::Long => 8,
113            Self::Uchar => 1,
114            Self::Ushort => 2,
115            Self::Uint => 4,
116            Self::Ulong => 8,
117            Self::Float => 4,
118            Self::Double => 8,
119            Self::String => 0,
120        }
121    }
122}
123
124/// A scalar field in a DMAP record.
125#[derive(Debug, Clone, PartialEq, FromPyObject, IntoPyObject)]
126#[repr(C)]
127pub enum DmapScalar {
128    Char(i8),
129    Short(i16),
130    Int(i32),
131    Long(i64),
132    Uchar(u8),
133    Ushort(u16),
134    Uint(u32),
135    Ulong(u64),
136    Float(f32),
137    Double(f64),
138    String(String),
139}
140impl DmapScalar {
141    /// Gets the corresponding `Type`
142    pub(crate) fn get_type(&self) -> Type {
143        match self {
144            Self::Char(_) => Type::Char,
145            Self::Short(_) => Type::Short,
146            Self::Int(_) => Type::Int,
147            Self::Long(_) => Type::Long,
148            Self::Uchar(_) => Type::Uchar,
149            Self::Ushort(_) => Type::Ushort,
150            Self::Uint(_) => Type::Uint,
151            Self::Ulong(_) => Type::Ulong,
152            Self::Float(_) => Type::Float,
153            Self::Double(_) => Type::Double,
154            Self::String(_) => Type::String,
155        }
156    }
157
158    /// Converts `self` into a new `Type`, if possible.
159    pub(crate) fn cast_as(&self, new_type: &Type) -> Result<Self> {
160        match new_type {
161            Type::Char => Ok(Self::Char(i8::try_from(self.clone())?)),
162            Type::Short => Ok(Self::Short(i16::try_from(self.clone())?)),
163            Type::Int => Ok(Self::Int(i32::try_from(self.clone())?)),
164            Type::Long => Ok(Self::Long(i64::try_from(self.clone())?)),
165            Type::Uchar => Ok(Self::Uchar(u8::try_from(self.clone())?)),
166            Type::Ushort => Ok(Self::Ushort(u16::try_from(self.clone())?)),
167            Type::Uint => Ok(Self::Uint(u32::try_from(self.clone())?)),
168            Type::Ulong => Ok(Self::Ulong(u64::try_from(self.clone())?)),
169            Type::Float => Ok(Self::Float(f32::try_from(self.clone())?)),
170            Type::Double => Ok(Self::Double(f64::try_from(self.clone())?)),
171            Type::String => Err(DmapError::InvalidScalar(
172                "Unable to cast value to String".to_string(),
173            )),
174        }
175    }
176    /// Copies the data and metadata (`Type` key) to raw bytes
177    pub(crate) fn as_bytes(&self) -> Vec<u8> {
178        let mut bytes: Vec<u8> = DmapType::as_bytes(&self.get_type().key()).to_vec();
179        let mut data_bytes: Vec<u8> = match self {
180            Self::Char(x) => DmapType::as_bytes(x),
181            Self::Short(x) => DmapType::as_bytes(x),
182            Self::Int(x) => DmapType::as_bytes(x),
183            Self::Long(x) => DmapType::as_bytes(x),
184            Self::Uchar(x) => DmapType::as_bytes(x),
185            Self::Ushort(x) => DmapType::as_bytes(x),
186            Self::Uint(x) => DmapType::as_bytes(x),
187            Self::Ulong(x) => DmapType::as_bytes(x),
188            Self::Float(x) => DmapType::as_bytes(x),
189            Self::Double(x) => DmapType::as_bytes(x),
190            Self::String(x) => DmapType::as_bytes(x),
191        };
192        bytes.append(&mut data_bytes);
193        bytes
194    }
195}
196impl Display for DmapScalar {
197    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
198        match self {
199            Self::Char(x) => write!(f, "CHAR {x}"),
200            Self::Short(x) => write!(f, "SHORT {x}"),
201            Self::Int(x) => write!(f, "INT {x}"),
202            Self::Float(x) => write!(f, "FLOAT {x}"),
203            Self::Double(x) => write!(f, "DOUBLE {x}"),
204            Self::String(x) => write!(f, "STRING {x}"),
205            Self::Long(x) => write!(f, "LONG {x}"),
206            Self::Uchar(x) => write!(f, "UCHAR {x}"),
207            Self::Ushort(x) => write!(f, "USHORT {x}"),
208            Self::Uint(x) => write!(f, "UINT {x}"),
209            Self::Ulong(x) => write!(f, "ULONG {x}"),
210        }
211    }
212}
213// impl IntoPy<PyObject> for DmapScalar {
214//     fn into_py(self, py: Python<'_>) -> PyObject {
215//         match self {
216//             Self::Char(x) => x.into_py(py),
217//             Self::Short(x) => x.into_py(py),
218//             Self::Int(x) => x.into_py(py),
219//             Self::Long(x) => x.into_py(py),
220//             Self::Uchar(x) => x.into_py(py),
221//             Self::Ushort(x) => x.into_py(py),
222//             Self::Uint(x) => x.into_py(py),
223//             Self::Ulong(x) => x.into_py(py),
224//             Self::Float(x) => x.into_py(py),
225//             Self::Double(x) => x.into_py(py),
226//             Self::String(x) => x.into_py(py),
227//         }
228//     }
229// }
230
231macro_rules! vec_to_bytes {
232    ($bytes:ident, $x:ident) => {{
233        $bytes.extend(($x.ndim() as i32).to_le_bytes());
234        for &dim in $x.shape().iter().rev() {
235            $bytes.extend((dim as i32).to_le_bytes());
236        }
237        for y in $x.iter() {
238            $bytes.append(&mut DmapType::as_bytes(y).to_vec());
239        }
240    }};
241}
242
243/// A vector field in a DMAP record.
244#[derive(Clone, Debug, PartialEq)]
245pub enum DmapVec {
246    Char(ArrayD<i8>),
247    Short(ArrayD<i16>),
248    Int(ArrayD<i32>),
249    Long(ArrayD<i64>),
250    Uchar(ArrayD<u8>),
251    Ushort(ArrayD<u16>),
252    Uint(ArrayD<u32>),
253    Ulong(ArrayD<u64>),
254    Float(ArrayD<f32>),
255    Double(ArrayD<f64>),
256}
257impl DmapVec {
258    /// Gets the corresponding [`Type`] of the vector.
259    #[inline]
260    pub(crate) fn get_type(&self) -> Type {
261        match self {
262            DmapVec::Char(_) => Type::Char,
263            DmapVec::Short(_) => Type::Short,
264            DmapVec::Int(_) => Type::Int,
265            DmapVec::Long(_) => Type::Long,
266            DmapVec::Uchar(_) => Type::Uchar,
267            DmapVec::Ushort(_) => Type::Ushort,
268            DmapVec::Uint(_) => Type::Uint,
269            DmapVec::Ulong(_) => Type::Ulong,
270            DmapVec::Float(_) => Type::Float,
271            DmapVec::Double(_) => Type::Double,
272        }
273    }
274    /// Copies the data and metadata (dimensions, [`Type`] key) to raw bytes
275    #[inline]
276    pub(crate) fn as_bytes(&self) -> Vec<u8> {
277        let mut bytes: Vec<u8> = DmapType::as_bytes(&self.get_type().key()).to_vec();
278        match self {
279            DmapVec::Char(x) => vec_to_bytes!(bytes, x),
280            DmapVec::Short(x) => vec_to_bytes!(bytes, x),
281            DmapVec::Int(x) => vec_to_bytes!(bytes, x),
282            DmapVec::Long(x) => vec_to_bytes!(bytes, x),
283            DmapVec::Uchar(x) => vec_to_bytes!(bytes, x),
284            DmapVec::Ushort(x) => vec_to_bytes!(bytes, x),
285            DmapVec::Uint(x) => vec_to_bytes!(bytes, x),
286            DmapVec::Ulong(x) => vec_to_bytes!(bytes, x),
287            DmapVec::Float(x) => vec_to_bytes!(bytes, x),
288            DmapVec::Double(x) => vec_to_bytes!(bytes, x),
289        };
290        bytes
291    }
292
293    /// Gets the dimensions of the vector, in row-major order.
294    /// ## Example
295    /// ```
296    /// use numpy::ndarray::array;
297    /// use dmap::types::DmapVec;
298    ///
299    /// let arr = DmapVec::Char(array![0, 1, 2, 3, 4].into_dyn());
300    /// assert_eq!(arr.shape(), &[5]);
301    ///
302    /// let arr = DmapVec::Uint(array![[0, 1, 2], [3, 4, 5]].into_dyn());
303    /// assert_eq!(arr.shape(), &[2, 3]);
304    /// ```
305    #[must_use]
306    pub fn shape(&self) -> &[usize] {
307        match self {
308            DmapVec::Char(x) => x.shape(),
309            DmapVec::Short(x) => x.shape(),
310            DmapVec::Int(x) => x.shape(),
311            DmapVec::Long(x) => x.shape(),
312            DmapVec::Uchar(x) => x.shape(),
313            DmapVec::Ushort(x) => x.shape(),
314            DmapVec::Uint(x) => x.shape(),
315            DmapVec::Ulong(x) => x.shape(),
316            DmapVec::Float(x) => x.shape(),
317            DmapVec::Double(x) => x.shape(),
318        }
319    }
320}
321impl<'py> IntoPyObject<'py> for DmapVec {
322    type Target = PyAny;
323    type Output = Bound<'py, Self::Target>;
324    type Error = std::convert::Infallible;
325
326    fn into_pyobject(self, py: Python<'py>) -> std::result::Result<Self::Output, Self::Error> {
327        Ok(match self {
328            DmapVec::Char(x) => PyArray::from_owned_array(py, x).into_any(),
329            DmapVec::Short(x) => PyArray::from_owned_array(py, x).into_any(),
330            DmapVec::Int(x) => PyArray::from_owned_array(py, x).into_any(),
331            DmapVec::Long(x) => PyArray::from_owned_array(py, x).into_any(),
332            DmapVec::Uchar(x) => PyArray::from_owned_array(py, x).into_any(),
333            DmapVec::Ushort(x) => PyArray::from_owned_array(py, x).into_any(),
334            DmapVec::Uint(x) => PyArray::from_owned_array(py, x).into_any(),
335            DmapVec::Ulong(x) => PyArray::from_owned_array(py, x).into_any(),
336            DmapVec::Float(x) => PyArray::from_owned_array(py, x).into_any(),
337            DmapVec::Double(x) => PyArray::from_owned_array(py, x).into_any(),
338        })
339    }
340}
341impl<'py> FromPyObject<'py> for DmapVec {
342    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
343        if let Ok(x) = ob.downcast::<PyArray<u8, _>>() {
344            Ok(DmapVec::Uchar(x.to_owned_array()))
345        } else if let Ok(x) = ob.downcast::<PyArray<u16, _>>() {
346            Ok(DmapVec::Ushort(x.to_owned_array()))
347        } else if let Ok(x) = ob.downcast::<PyArray<u32, _>>() {
348            Ok(DmapVec::Uint(x.to_owned_array()))
349        } else if let Ok(x) = ob.downcast::<PyArray<u64, _>>() {
350            Ok(DmapVec::Ulong(x.to_owned_array()))
351        } else if let Ok(x) = ob.downcast::<PyArray<i8, _>>() {
352            Ok(DmapVec::Char(x.to_owned_array()))
353        } else if let Ok(x) = ob.downcast::<PyArray<i16, _>>() {
354            Ok(DmapVec::Short(x.to_owned_array()))
355        } else if let Ok(x) = ob.downcast::<PyArray<i32, _>>() {
356            Ok(DmapVec::Int(x.to_owned_array()))
357        } else if let Ok(x) = ob.downcast::<PyArray<i64, _>>() {
358            Ok(DmapVec::Long(x.to_owned_array()))
359        } else if let Ok(x) = ob.downcast::<PyArray<f32, _>>() {
360            Ok(DmapVec::Float(x.to_owned_array()))
361        } else if let Ok(x) = ob.downcast::<PyArray<f64, _>>() {
362            Ok(DmapVec::Double(x.to_owned_array()))
363        } else {
364            Err(PyValueError::new_err("Could not extract vector"))
365        }
366    }
367}
368
369/// Generates trait implementations for infallible conversion into [`DmapVec`] and fallible conversion
370/// back.
371///
372/// Example: `vec_impls!(ArrayD<i8>, DmapVec::Char)` will generate `impl From<ArrayD<i8>> for
373/// DmapVec` and `impl TryFrom<DmapVec> for ArrayD<i8>` code blocks.
374macro_rules! vec_impls {
375    ($type:ty, $enum_var:path) => {
376        impl From<$type> for DmapVec {
377            #[inline]
378            fn from(value: $type) -> Self {
379                $enum_var(value)
380            }
381        }
382
383        impl TryFrom<DmapVec> for $type {
384            type Error = DmapError;
385
386            fn try_from(value: DmapVec) -> std::result::Result<Self, Self::Error> {
387                if let $enum_var(x) = value {
388                    Ok(x)
389                } else {
390                    Err(DmapError::InvalidVector(format!(
391                        "Cannot convert to {}",
392                        stringify!($type)
393                    )))
394                }
395            }
396        }
397
398        impl From<$type> for DmapField {
399            #[inline]
400            fn from(value: $type) -> Self {
401                DmapField::Vector($enum_var(value))
402            }
403        }
404
405        impl TryFrom<DmapField> for $type {
406            type Error = DmapError;
407
408            fn try_from(value: DmapField) -> std::result::Result<Self, Self::Error> {
409                match value {
410                    DmapField::Vector(x) => x.try_into(),
411                    _ => Err(Self::Error::InvalidVector(format!(
412                        "Cannot interpret as {}",
413                        stringify!($type)
414                    ))),
415                }
416            }
417        }
418    };
419}
420
421vec_impls!(ArrayD<i8>, DmapVec::Char);
422vec_impls!(ArrayD<i16>, DmapVec::Short);
423vec_impls!(ArrayD<i32>, DmapVec::Int);
424vec_impls!(ArrayD<i64>, DmapVec::Long);
425vec_impls!(ArrayD<u8>, DmapVec::Uchar);
426vec_impls!(ArrayD<u16>, DmapVec::Ushort);
427vec_impls!(ArrayD<u32>, DmapVec::Uint);
428vec_impls!(ArrayD<u64>, DmapVec::Ulong);
429vec_impls!(ArrayD<f32>, DmapVec::Float);
430vec_impls!(ArrayD<f64>, DmapVec::Double);
431
432/// A generic field of a DMAP record.
433///
434/// This is the type that is stored in a DMAP record, representing either a scalar or
435/// vector field.
436#[derive(Debug, Clone, PartialEq, FromPyObject, IntoPyObject)]
437#[repr(C)]
438pub enum DmapField {
439    Vector(DmapVec),
440    Scalar(DmapScalar),
441}
442impl DmapField {
443    /// Converts the field and metadata (`Type` key and dimensions if applicable) to raw bytes.
444    #[inline]
445    #[must_use]
446    pub fn as_bytes(&self) -> Vec<u8> {
447        match self {
448            Self::Scalar(x) => x.as_bytes(),
449            Self::Vector(x) => x.as_bytes(),
450        }
451    }
452}
453// impl IntoPyObject for DmapField {
454//     fn into_py(self, py: Python<'_>) -> PyObject {
455//         match self {
456//             DmapField::Scalar(x) => x.into_py(py),
457//             DmapField::Vector(x) => x.into_py(py),
458//         }
459//     }
460// }
461
462/// Macro for implementing conversion traits between primitives and [`DmapField`], [`DmapScalar`]
463/// types.
464///
465/// Example: `scalar_impls(i8, DmapScalar::Char)` will implement:
466///   `From<i8> for DmapField`
467///   `TryFrom<DmapField> for i8`
468macro_rules! scalar_impls {
469    ($type:ty, $enum_var:path, $type_var:path) => {
470        impl From<$type> for DmapField {
471            fn from(value: $type) -> Self {
472                DmapField::Scalar($enum_var(value))
473            }
474        }
475        impl TryFrom<DmapField> for $type {
476            type Error = DmapError;
477
478            fn try_from(value: DmapField) -> std::result::Result<Self, Self::Error> {
479                match value {
480                    DmapField::Scalar(x) => x.try_into(),
481                    _ => Err(Self::Error::InvalidScalar(format!(
482                        "Cannot interpret {value:?} as {}",
483                        stringify!($type)
484                    ))),
485                }
486            }
487        }
488    };
489}
490
491scalar_impls!(i8, DmapScalar::Char, Type::Char);
492scalar_impls!(i16, DmapScalar::Short, Type::Short);
493scalar_impls!(i32, DmapScalar::Int, Type::Int);
494scalar_impls!(i64, DmapScalar::Long, Type::Long);
495scalar_impls!(u8, DmapScalar::Uchar, Type::Uchar);
496scalar_impls!(u16, DmapScalar::Ushort, Type::Ushort);
497scalar_impls!(u32, DmapScalar::Uint, Type::Uint);
498scalar_impls!(u64, DmapScalar::Ulong, Type::Ulong);
499scalar_impls!(f32, DmapScalar::Float, Type::Float);
500scalar_impls!(f64, DmapScalar::Double, Type::Double);
501scalar_impls!(String, DmapScalar::String, Type::String);
502
503/// Trait for raw types that can be stored in DMAP files.
504pub trait DmapType: std::fmt::Debug {
505    /// Size in bytes of the type.
506    fn size() -> usize
507    where
508        Self: Sized;
509    /// Create a copy of the data as raw bytes.
510    fn as_bytes(&self) -> Vec<u8>;
511    /// Convert raw bytes to `Self`
512    ///
513    /// # Errors
514    /// If the bytes are not a valid DMAP record of type `Self`.
515    fn from_bytes(bytes: &[u8]) -> Result<Self>
516    where
517        Self: Sized;
518    /// Get the `Type` variant that represents `self`
519    fn dmap_type() -> Type;
520}
521
522/// Macro for implementing [`DmapType`] trait for primitive types.
523/// Example: `type_impls!(i8, Type::Char, 1)`
524macro_rules! type_impls {
525    // This variant captures single-byte types
526    ($type:ty, $enum_var:path, 1) => {
527        impl DmapType for $type {
528            #[inline]
529            fn size() -> usize { 1 }
530
531            #[inline]
532            fn as_bytes(&self) -> Vec<u8> {
533                AsBytes::as_bytes(self).to_vec()
534            }
535
536            #[inline]
537            fn from_bytes(bytes: &[u8]) -> Result<Self>
538            where
539                Self: Sized,
540            {
541                Self::read_from(bytes).ok_or(DmapError::CorruptStream("Unable to interpret bytes"))
542            }
543
544            #[inline]
545            fn dmap_type() -> Type { $enum_var }
546        }
547    };
548    // This variant captures multi-byte primitive types
549    ($type:ty, $enum_var:path, $num_bytes:expr) => {
550        paste! {
551            impl DmapType for $type {
552                #[inline]
553                fn size() -> usize { $num_bytes }
554
555                #[inline]
556                fn as_bytes(&self) -> Vec<u8> {
557                    let mut bytes = [0; $num_bytes];
558                    LittleEndian::[< write_ $type >](&mut bytes, *self);
559                    bytes.to_vec()
560                }
561
562                #[inline]
563                fn from_bytes(bytes: &[u8]) -> Result<Self>
564                where
565                    Self: Sized,
566                {
567                    Self::read_from(bytes).ok_or(DmapError::CorruptStream("Unable to interpret bytes"))
568                }
569
570                #[inline]
571                fn dmap_type() -> Type { $enum_var }
572            }
573        }
574    }
575}
576
577type_impls!(i8, Type::Char, 1);
578type_impls!(i16, Type::Short, 2);
579type_impls!(i32, Type::Int, 4);
580type_impls!(i64, Type::Long, 8);
581type_impls!(u8, Type::Uchar, 1);
582type_impls!(u16, Type::Ushort, 2);
583type_impls!(u32, Type::Uint, 4);
584type_impls!(u64, Type::Ulong, 8);
585type_impls!(f32, Type::Float, 4);
586type_impls!(f64, Type::Double, 8);
587
588// This implementation differs significantly from the others, so it doesn't use the macro
589impl DmapType for String {
590    #[inline]
591    fn size() -> usize {
592        0
593    }
594
595    #[inline]
596    fn as_bytes(&self) -> Vec<u8> {
597        let mut bytes = self.as_bytes().to_vec();
598        bytes.push(0); // null-terminate
599        bytes
600    }
601
602    #[inline]
603    fn from_bytes(bytes: &[u8]) -> Result<Self> {
604        let data = String::from_utf8(bytes.to_owned())
605            .map_err(|_| DmapError::InvalidScalar("Cannot convert bytes to String".to_string()))?;
606        Ok(data.trim_end_matches(char::from(0)).to_string())
607    }
608
609    #[inline]
610    fn dmap_type() -> Type {
611        Type::String
612    }
613}
614
615impl TryFrom<DmapScalar> for u8 {
616    type Error = DmapError;
617    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
618        match value {
619            DmapScalar::Char(x) => Ok(u8::try_from(x)?),
620            DmapScalar::Short(x) => Ok(u8::try_from(x)?),
621            DmapScalar::Int(x) => Ok(u8::try_from(x)?),
622            DmapScalar::Long(x) => Ok(u8::try_from(x)?),
623            DmapScalar::Uchar(x) => Ok(x),
624            DmapScalar::Ushort(x) => Ok(u8::try_from(x)?),
625            DmapScalar::Uint(x) => Ok(u8::try_from(x)?),
626            DmapScalar::Ulong(x) => Ok(u8::try_from(x)?),
627            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
628                "Unable to convert {x}_f32 to u8"
629            ))),
630            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
631                "Unable to convert {x}_f64 to u8"
632            ))),
633            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
634                "Unable to convert {x} to u8"
635            ))),
636        }
637    }
638}
639impl TryFrom<DmapScalar> for u16 {
640    type Error = DmapError;
641    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
642        match value {
643            DmapScalar::Char(x) => Ok(u16::try_from(x)?),
644            DmapScalar::Short(x) => Ok(u16::try_from(x)?),
645            DmapScalar::Int(x) => Ok(u16::try_from(x)?),
646            DmapScalar::Long(x) => Ok(u16::try_from(x)?),
647            DmapScalar::Uchar(x) => Ok(x as u16),
648            DmapScalar::Ushort(x) => Ok(x),
649            DmapScalar::Uint(x) => Ok(u16::try_from(x)?),
650            DmapScalar::Ulong(x) => Ok(u16::try_from(x)?),
651            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
652                "Unable to convert {x}_f32 to u16"
653            ))),
654            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
655                "Unable to convert {x}_f64 to u16"
656            ))),
657            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
658                "Unable to convert {x} to u16"
659            ))),
660        }
661    }
662}
663impl TryFrom<DmapScalar> for u32 {
664    type Error = DmapError;
665    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
666        match value {
667            DmapScalar::Char(x) => Ok(u32::try_from(x)?),
668            DmapScalar::Short(x) => Ok(u32::try_from(x)?),
669            DmapScalar::Int(x) => Ok(u32::try_from(x)?),
670            DmapScalar::Long(x) => Ok(u32::try_from(x)?),
671            DmapScalar::Uchar(x) => Ok(x as u32),
672            DmapScalar::Ushort(x) => Ok(x as u32),
673            DmapScalar::Uint(x) => Ok(x),
674            DmapScalar::Ulong(x) => Ok(u32::try_from(x)?),
675            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
676                "Unable to convert {x}_f32 to u32"
677            ))),
678            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
679                "Unable to convert {x}_f64 to u32"
680            ))),
681            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
682                "Unable to convert {x} to u32"
683            ))),
684        }
685    }
686}
687impl TryFrom<DmapScalar> for u64 {
688    type Error = DmapError;
689    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
690        match value {
691            DmapScalar::Char(x) => Ok(u64::try_from(x)?),
692            DmapScalar::Short(x) => Ok(u64::try_from(x)?),
693            DmapScalar::Int(x) => Ok(u64::try_from(x)?),
694            DmapScalar::Long(x) => Ok(u64::try_from(x)?),
695            DmapScalar::Uchar(x) => Ok(x as u64),
696            DmapScalar::Ushort(x) => Ok(x as u64),
697            DmapScalar::Uint(x) => Ok(x as u64),
698            DmapScalar::Ulong(x) => Ok(x),
699            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
700                "Unable to convert {x}_f32 to u64"
701            ))),
702            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
703                "Unable to convert {x}_f64 to u64"
704            ))),
705            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
706                "Unable to convert {x} to u64"
707            ))),
708        }
709    }
710}
711impl TryFrom<DmapScalar> for i8 {
712    type Error = DmapError;
713    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
714        match value {
715            DmapScalar::Char(x) => Ok(x),
716            DmapScalar::Short(x) => Ok(i8::try_from(x)?),
717            DmapScalar::Int(x) => Ok(i8::try_from(x)?),
718            DmapScalar::Long(x) => Ok(i8::try_from(x)?),
719            DmapScalar::Uchar(x) => Ok(i8::try_from(x)?),
720            DmapScalar::Ushort(x) => Ok(i8::try_from(x)?),
721            DmapScalar::Uint(x) => Ok(i8::try_from(x)?),
722            DmapScalar::Ulong(x) => Ok(i8::try_from(x)?),
723            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
724                "Unable to convert {x}_f32 to i8"
725            ))),
726            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
727                "Unable to convert {x}_f64 to i8"
728            ))),
729            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
730                "Unable to convert {x} to i8"
731            ))),
732        }
733    }
734}
735impl TryFrom<DmapScalar> for i16 {
736    type Error = DmapError;
737    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
738        match value {
739            DmapScalar::Char(x) => Ok(x as i16),
740            DmapScalar::Short(x) => Ok(x),
741            DmapScalar::Int(x) => Ok(i16::try_from(x)?),
742            DmapScalar::Long(x) => Ok(i16::try_from(x)?),
743            DmapScalar::Uchar(x) => Ok(x as i16),
744            DmapScalar::Ushort(x) => Ok(i16::try_from(x)?),
745            DmapScalar::Uint(x) => Ok(i16::try_from(x)?),
746            DmapScalar::Ulong(x) => Ok(i16::try_from(x)?),
747            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
748                "Unable to convert {x}_f32 to i16"
749            ))),
750            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
751                "Unable to convert {x}_f64 to i16"
752            ))),
753            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
754                "Unable to convert {x} to i16"
755            ))),
756        }
757    }
758}
759impl TryFrom<DmapScalar> for i32 {
760    type Error = DmapError;
761    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
762        match value {
763            DmapScalar::Char(x) => Ok(x as i32),
764            DmapScalar::Short(x) => Ok(x as i32),
765            DmapScalar::Int(x) => Ok(x),
766            DmapScalar::Long(x) => Ok(i32::try_from(x)?),
767            DmapScalar::Uchar(x) => Ok(x as i32),
768            DmapScalar::Ushort(x) => Ok(x as i32),
769            DmapScalar::Uint(x) => Ok(i32::try_from(x)?),
770            DmapScalar::Ulong(x) => Ok(i32::try_from(x)?),
771            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
772                "Unable to convert {x}_f32 to i32"
773            ))),
774            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
775                "Unable to convert {x}_f64 to i32"
776            ))),
777            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
778                "Unable to convert {x} to i32"
779            ))),
780        }
781    }
782}
783impl TryFrom<DmapScalar> for i64 {
784    type Error = DmapError;
785    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
786        match value {
787            DmapScalar::Char(x) => Ok(x as i64),
788            DmapScalar::Short(x) => Ok(x as i64),
789            DmapScalar::Int(x) => Ok(x as i64),
790            DmapScalar::Long(x) => Ok(x),
791            DmapScalar::Uchar(x) => Ok(x as i64),
792            DmapScalar::Ushort(x) => Ok(x as i64),
793            DmapScalar::Uint(x) => Ok(x as i64),
794            DmapScalar::Ulong(x) => Ok(i64::try_from(x)?),
795            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
796                "Unable to convert {x}_f32 to i64"
797            ))),
798            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
799                "Unable to convert {x}_f64 to i64"
800            ))),
801            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
802                "Unable to convert {x} to i64"
803            ))),
804        }
805    }
806}
807impl TryFrom<DmapScalar> for f32 {
808    type Error = DmapError;
809    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
810        match value {
811            DmapScalar::Char(x) => Ok(x as f32),
812            DmapScalar::Short(x) => Ok(x as f32),
813            DmapScalar::Int(x) => Ok(x as f32),
814            DmapScalar::Long(x) => Ok(x as f32),
815            DmapScalar::Uchar(x) => Ok(x as f32),
816            DmapScalar::Ushort(x) => Ok(x as f32),
817            DmapScalar::Uint(x) => Ok(x as f32),
818            DmapScalar::Ulong(x) => Ok(x as f32),
819            DmapScalar::Float(x) => Ok(x),
820            DmapScalar::Double(x) => Ok(x as f32),
821            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
822                "Unable to convert {x} to f32"
823            ))),
824        }
825    }
826}
827impl TryFrom<DmapScalar> for f64 {
828    type Error = DmapError;
829    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
830        match value {
831            DmapScalar::Char(x) => Ok(x as f64),
832            DmapScalar::Short(x) => Ok(x as f64),
833            DmapScalar::Int(x) => Ok(x as f64),
834            DmapScalar::Long(x) => Ok(x as f64),
835            DmapScalar::Uchar(x) => Ok(x as f64),
836            DmapScalar::Ushort(x) => Ok(x as f64),
837            DmapScalar::Uint(x) => Ok(x as f64),
838            DmapScalar::Ulong(x) => Ok(x as f64),
839            DmapScalar::Float(x) => Ok(f64::from(x)),
840            DmapScalar::Double(x) => Ok(x),
841            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
842                "Unable to convert {x} to f64"
843            ))),
844        }
845    }
846}
847impl TryFrom<DmapScalar> for String {
848    type Error = DmapError;
849    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
850        match value {
851            DmapScalar::String(x) => Ok(x),
852            x => Err(DmapError::InvalidScalar(format!(
853                "Unable to convert {x} to String"
854            ))),
855        }
856    }
857}
858
859/// Verify that `name` exists in `fields` and is of the correct [`Type`].
860///
861/// # Errors
862/// If `name` is not in `fields`.
863///
864/// If `name` is in `fields`, but is not a [`DmapField::Scalar`] of `expected_type`.
865pub fn check_scalar(
866    fields: &IndexMap<String, DmapField>,
867    name: &str,
868    expected_type: &Type,
869) -> Result<()> {
870    match fields.get(name) {
871        Some(DmapField::Scalar(data)) if data.get_type() == *expected_type => Ok(()),
872        Some(DmapField::Scalar(data)) => Err(DmapError::InvalidScalar(format!(
873            "{name} is of type {}, expected {}",
874            data.get_type(),
875            expected_type
876        ))),
877        Some(_) => Err(DmapError::InvalidScalar(format!(
878            "{name} is a vector field"
879        ))),
880        None => Err(DmapError::InvalidScalar(format!("{name} is not in record"))),
881    }
882}
883
884/// If `name` is in `fields`, verify that it is of the correct [`Type`].
885///
886/// # Errors
887/// If `name` is in `fields`, but is not a [`DmapField::Scalar`] of `expected_type`.
888pub fn check_scalar_opt(
889    fields: &IndexMap<String, DmapField>,
890    name: &str,
891    expected_type: &Type,
892) -> Result<()> {
893    match fields.get(name) {
894        Some(DmapField::Scalar(data)) if data.get_type() == *expected_type => Ok(()),
895        Some(DmapField::Scalar(data)) => Err(DmapError::InvalidScalar(format!(
896            "{name} is of type {}, expected {}",
897            data.get_type(),
898            expected_type
899        ))),
900        Some(_) => Err(DmapError::InvalidScalar(format!(
901            "{name} is a vector field"
902        ))),
903        None => Ok(()),
904    }
905}
906
907/// Verify that `name` exists in `fields` and is of the correct [`Type`].
908///
909/// # Errors
910/// If `name` is not in `fields`.
911///
912/// If `name` is in `fields`, but is not a [`DmapField::Vector`] of `expected_type`.
913pub fn check_vector(
914    fields: &IndexMap<String, DmapField>,
915    name: &str,
916    expected_type: &Type,
917) -> Result<()> {
918    match fields.get(name) {
919        Some(DmapField::Vector(data)) if data.get_type() != *expected_type => {
920            Err(DmapError::InvalidVector(format!(
921                "{name} is of type {}, expected {}",
922                data.get_type(),
923                expected_type
924            )))
925        }
926        Some(DmapField::Scalar(_)) => Err(DmapError::InvalidVector(format!(
927            "{name} is a scalar field"
928        ))),
929        None => Err(DmapError::InvalidVector(format!("{name} not in record"))),
930        _ => Ok(()),
931    }
932}
933
934/// If `name` is in `fields`, verify that it is of the correct [`Type`].
935///
936/// # Errors
937/// If `name` is in `fields`, but is not a [`DmapField::Vector`] of `expected_type`.
938pub fn check_vector_opt(
939    fields: &IndexMap<String, DmapField>,
940    name: &str,
941    expected_type: &Type,
942) -> Result<()> {
943    match fields.get(name) {
944        Some(DmapField::Vector(data)) if data.get_type() != *expected_type => {
945            Err(DmapError::InvalidVector(format!(
946                "{name} is of type {}, expected {}",
947                data.get_type(),
948                expected_type
949            )))
950        }
951        Some(DmapField::Scalar(_)) => Err(DmapError::InvalidVector(format!(
952            "{name} is a scalar field"
953        ))),
954        _ => Ok(()),
955    }
956}
957
958/// Parses a scalar starting from the `cursor` position.
959///
960/// Interprets the bytes starting from the `cursor` position in the following order:
961/// 1. `name`: a null-terminated string
962/// 2. `type`: an i32 key, which maps to a data type (see [`Type`])
963/// 3. `data`: the actual data as raw bytes.
964#[inline]
965pub(crate) fn parse_scalar(cursor: &mut Cursor<Vec<u8>>) -> Result<(String, DmapField)> {
966    let (name, data_type) = parse_header(cursor)?;
967    let data: DmapScalar = match data_type {
968        Type::Char => DmapScalar::Char(read_data::<i8>(cursor)?),
969        Type::Short => DmapScalar::Short(read_data::<i16>(cursor)?),
970        Type::Int => DmapScalar::Int(read_data::<i32>(cursor)?),
971        Type::Long => DmapScalar::Long(read_data::<i64>(cursor)?),
972        Type::Uchar => DmapScalar::Uchar(read_data::<u8>(cursor)?),
973        Type::Ushort => DmapScalar::Ushort(read_data::<u16>(cursor)?),
974        Type::Uint => DmapScalar::Uint(read_data::<u32>(cursor)?),
975        Type::Ulong => DmapScalar::Ulong(read_data::<u64>(cursor)?),
976        Type::Float => DmapScalar::Float(read_data::<f32>(cursor)?),
977        Type::Double => DmapScalar::Double(read_data::<f64>(cursor)?),
978        Type::String => DmapScalar::String(read_data::<String>(cursor)?),
979    };
980
981    Ok((name, DmapField::Scalar(data)))
982}
983
984/// Grabs the name and data type key from `cursor`.
985#[inline]
986pub(crate) fn parse_header(cursor: &mut Cursor<Vec<u8>>) -> Result<(String, Type)> {
987    let name = read_data::<String>(cursor).map_err(|e| {
988        DmapError::InvalidField(format!("Invalid name, byte {}: {e}", cursor.position()))
989    })?;
990    let data_type_key = read_data::<i8>(cursor).map_err(|e| {
991        DmapError::InvalidField(format!(
992            "Invalid data type for field '{name}', byte {}: {e}",
993            cursor.position() - i8::size() as u64
994        ))
995    })?;
996    let data_type = Type::from_key(data_type_key)?;
997
998    Ok((name, data_type))
999}
1000
1001/// Parses a header for a vector starting from the `cursor` position.
1002///
1003/// Interprets the bytes in `cursor` as follows:
1004/// 1. `name`: a null-terminated string
1005/// 2. `type`: a key indicating the data type ([`Type`])
1006/// 3. `num_dims`: the number of dimensions in the array, as an `i32`.
1007/// 4. `dims`: the dimensions themselves, as a list of `num_dims` `i32`s, in column-major order.
1008pub(crate) fn parse_vector_header(
1009    cursor: &mut Cursor<Vec<u8>>,
1010    record_size: i32,
1011) -> Result<(String, Type, Vec<usize>, i32)> {
1012    let (name, data_type) = parse_header(cursor)?;
1013
1014    let vector_dimension = read_data::<i32>(cursor)?;
1015    if vector_dimension > record_size {
1016        return Err(DmapError::InvalidVector(format!(
1017            "Parsed number of vector dimensions {vector_dimension} for field `{name}` at byte {} are larger \
1018            than record size {record_size}",
1019            cursor.position() - i32::size() as u64,
1020        )));
1021    } else if vector_dimension <= 0 {
1022        return Err(DmapError::InvalidVector(format!(
1023            "Parsed number of vector dimensions {vector_dimension} for field `{name}` at byte {} are zero or \
1024            negative",
1025            cursor.position() - i32::size() as u64,
1026        )));
1027    }
1028
1029    let mut dimensions: Vec<usize> = vec![];
1030    let mut total_elements = 1;
1031    for _ in 0..vector_dimension {
1032        let dim = read_data::<i32>(cursor)?;
1033        if dim <= 0 && name != "slist" {
1034            return Err(DmapError::InvalidVector(format!(
1035                "Vector `{name}` dimension {dim} at byte {} is zero or negative",
1036                cursor.position() - i32::size() as u64,
1037            )));
1038        } else if dim > record_size {
1039            return Err(DmapError::InvalidVector(format!(
1040                "Vector `{name}` dimension {dim} at byte {} exceeds record size {record_size}",
1041                cursor.position() - i32::size() as u64,
1042            )));
1043        }
1044        dimensions.push(usize::try_from(dim)?);
1045        total_elements *= dim;
1046    }
1047    dimensions = dimensions.into_iter().rev().collect(); // reverse the dimensions, stored in column-major order
1048    if total_elements * i32::try_from(data_type.size())? > record_size {
1049        return Err(DmapError::InvalidVector(format!(
1050            "Vector `{name}` size starting at byte {} exceeds record size ({} > {record_size})",
1051            cursor.position() - u64::try_from(vector_dimension)? * u64::try_from(i32::size())?,
1052            total_elements * i32::try_from(data_type.size())?,
1053        )));
1054    }
1055
1056    Ok((name, data_type, dimensions, total_elements))
1057}
1058
1059/// Parses a vector starting from the `cursor` position.
1060///
1061/// Interprets the bytes in `cursor` as follows:
1062/// 1. `name`: a null-terminated string
1063/// 2. `type`: a key indicating the data type ([`Type`])
1064/// 3. `num_dims`: the number of dimensions in the array, as an `i32`.
1065/// 4. `dims`: the dimensions themselves, as a list of `num_dims` `i32`s, in column-major order.
1066/// 5. `data`: the data itself, of type `type` with shape `dims`, stored in column-major order.
1067pub(crate) fn parse_vector(
1068    cursor: &mut Cursor<Vec<u8>>,
1069    record_size: i32,
1070) -> Result<(String, DmapField)> {
1071    let start_position = cursor.position();
1072    let (name, data_type, dimensions, total_elements) = parse_vector_header(cursor, record_size)?;
1073
1074    macro_rules! dmapvec_from_cursor {
1075        ($type:ty, $enum_var:path, $dims:ident, $cursor:ident, $num_elements:ident, $name:ident) => {
1076            $enum_var(
1077                ArrayD::from_shape_vec($dims, read_vector::<$type>($cursor, $num_elements)?)
1078                    .map_err(|e| {
1079                        DmapError::InvalidVector(format!(
1080                            "Could not read in vector field {}: {e}",
1081                            $name
1082                        ))
1083                    })?,
1084            )
1085        };
1086    }
1087    let vector: DmapVec = match data_type {
1088        Type::Char => {
1089            dmapvec_from_cursor!(i8, DmapVec::Char, dimensions, cursor, total_elements, name)
1090        }
1091        Type::Short => dmapvec_from_cursor!(
1092            i16,
1093            DmapVec::Short,
1094            dimensions,
1095            cursor,
1096            total_elements,
1097            name
1098        ),
1099        Type::Int => {
1100            dmapvec_from_cursor!(i32, DmapVec::Int, dimensions, cursor, total_elements, name)
1101        }
1102        Type::Long => {
1103            dmapvec_from_cursor!(i64, DmapVec::Long, dimensions, cursor, total_elements, name)
1104        }
1105        Type::Uchar => {
1106            dmapvec_from_cursor!(u8, DmapVec::Uchar, dimensions, cursor, total_elements, name)
1107        }
1108        Type::Ushort => dmapvec_from_cursor!(
1109            u16,
1110            DmapVec::Ushort,
1111            dimensions,
1112            cursor,
1113            total_elements,
1114            name
1115        ),
1116        Type::Uint => {
1117            dmapvec_from_cursor!(u32, DmapVec::Uint, dimensions, cursor, total_elements, name)
1118        }
1119        Type::Ulong => dmapvec_from_cursor!(
1120            u64,
1121            DmapVec::Ulong,
1122            dimensions,
1123            cursor,
1124            total_elements,
1125            name
1126        ),
1127        Type::Float => dmapvec_from_cursor!(
1128            f32,
1129            DmapVec::Float,
1130            dimensions,
1131            cursor,
1132            total_elements,
1133            name
1134        ),
1135        Type::Double => dmapvec_from_cursor!(
1136            f64,
1137            DmapVec::Double,
1138            dimensions,
1139            cursor,
1140            total_elements,
1141            name
1142        ),
1143        Type::String => {
1144            return Err(DmapError::InvalidVector(format!(
1145                "Invalid type {data_type} for DMAP vector {name}"
1146            )))
1147        }
1148    };
1149
1150    let num_bytes = cursor.position() - start_position;
1151    if num_bytes > u64::try_from(record_size)? {
1152        return Err(DmapError::InvalidVector(format!(
1153            "Vector `{name}` occupies more bytes than record ({num_bytes} > {record_size})"
1154        )));
1155    }
1156
1157    Ok((name, DmapField::Vector(vector)))
1158}
1159
1160/// Read the raw data (excluding metadata) for a DMAP vector of type `T` from `cursor`.
1161fn read_vector<T: DmapType>(cursor: &mut Cursor<Vec<u8>>, num_elements: i32) -> Result<Vec<T>> {
1162    let mut data: Vec<T> = vec![];
1163    for _ in 0..num_elements {
1164        data.push(read_data::<T>(cursor)?);
1165    }
1166    Ok(data)
1167}
1168
1169/// Reads a singular value of type `T` starting from the `cursor` position.
1170#[inline]
1171pub(crate) fn read_data<T: DmapType>(cursor: &mut Cursor<Vec<u8>>) -> Result<T> {
1172    let position = usize::try_from(cursor.position())?;
1173    let stream = cursor.get_mut();
1174
1175    if position > stream.len() {
1176        return Err(DmapError::CorruptStream("Cursor extends out of buffer"));
1177    }
1178    if stream.len() - position < T::size() {
1179        return Err(DmapError::CorruptStream(
1180            "Byte offsets into buffer are not properly aligned",
1181        ));
1182    }
1183
1184    let data_size = match T::size() {
1185        0 => {
1186            // String type
1187            let mut byte_counter = 0;
1188            while stream[position + byte_counter] != 0 {
1189                byte_counter += 1;
1190                if position + byte_counter >= stream.len() {
1191                    return Err(DmapError::CorruptStream("String is improperly terminated"));
1192                }
1193            }
1194            byte_counter + 1
1195        }
1196        x => x,
1197    };
1198    let data: &[u8] = &stream[position..position + data_size];
1199    let parsed_data = T::from_bytes(data)?;
1200
1201    cursor.set_position({ position + data_size } as u64);
1202
1203    Ok(parsed_data)
1204}
1205
1206#[cfg(test)]
1207mod tests {
1208    use super::*;
1209    use numpy::ndarray::array;
1210
1211    #[test]
1212    fn test_read_vec() {
1213        let bytes: Vec<u8> = vec![1, 0, 1, 0];
1214        let mut cursor = Cursor::new(bytes.clone());
1215        let data = read_vector::<u8>(&mut cursor, 4);
1216        assert!(data.is_ok());
1217        assert_eq!(data.unwrap(), vec![1, 0, 1, 0]);
1218
1219        cursor.set_position(0);
1220        let data = read_vector::<u16>(&mut cursor, 2);
1221        assert!(data.is_ok());
1222        assert_eq!(data.unwrap(), vec![1, 1]);
1223
1224        cursor.set_position(0);
1225        let data = read_vector::<i8>(&mut cursor, 4);
1226        assert!(data.is_ok());
1227        assert_eq!(data.unwrap(), vec![1, 0, 1, 0]);
1228
1229        cursor.set_position(0);
1230        let data = read_vector::<i16>(&mut cursor, 2);
1231        assert!(data.is_ok());
1232        assert_eq!(data.unwrap(), vec![1, 1]);
1233    }
1234
1235    #[test]
1236    fn test_read_data() {
1237        // bytes are little-endian, so this will come out to 1 no matter if you interpret the first
1238        // number of bytes as u8, u16, u32, u64, i8, i16, i32, or i64.
1239        let bytes: Vec<u8> = vec![1, 0, 0, 0, 0, 0, 0, 0];
1240        let mut cursor = Cursor::new(bytes);
1241        let data = read_data::<u8>(&mut cursor);
1242        assert!(data.is_ok());
1243        assert_eq!(data.unwrap(), 1);
1244
1245        cursor.set_position(0);
1246        let data = read_data::<u16>(&mut cursor);
1247        assert!(data.is_ok());
1248        assert_eq!(data.unwrap(), 1);
1249
1250        cursor.set_position(0);
1251        let data = read_data::<u32>(&mut cursor);
1252        assert!(data.is_ok());
1253        assert_eq!(data.unwrap(), 1);
1254
1255        cursor.set_position(0);
1256        let data = read_data::<u64>(&mut cursor);
1257        assert!(data.is_ok());
1258        assert_eq!(data.unwrap(), 1);
1259
1260        cursor.set_position(0);
1261        let data = read_data::<i8>(&mut cursor);
1262        assert!(data.is_ok());
1263        assert_eq!(data.unwrap(), 1);
1264
1265        cursor.set_position(0);
1266        let data = read_data::<i16>(&mut cursor);
1267        assert!(data.is_ok());
1268        assert_eq!(data.unwrap(), 1);
1269
1270        cursor.set_position(0);
1271        let data = read_data::<i32>(&mut cursor);
1272        assert!(data.is_ok());
1273        assert_eq!(data.unwrap(), 1);
1274
1275        cursor.set_position(0);
1276        let data = read_data::<i64>(&mut cursor);
1277        assert!(data.is_ok());
1278        assert_eq!(data.unwrap(), 1);
1279
1280        // This read_data call should return an error, since i64 is bigger than the remaining buffer
1281        cursor.set_position(1);
1282        let data = read_data::<i64>(&mut cursor);
1283        assert!(data.is_err());
1284
1285        // This read_data call should return an error, since the cursor is past the end of the buffer
1286        cursor.set_position(4);
1287        let data = read_data::<i64>(&mut cursor);
1288        assert!(data.is_err());
1289
1290        let bytes: Vec<u8> = vec![116, 101, 115, 116, 0]; // b"test\0"
1291        let mut cursor = Cursor::new(bytes);
1292        let data = read_data::<String>(&mut cursor);
1293        assert!(data.is_ok());
1294        assert_eq!(data.unwrap(), "test".to_string());
1295
1296        let bytes: Vec<u8> = vec![116, 101, 115, 116]; // b"test", not null-terminated
1297        let mut cursor = Cursor::new(bytes);
1298        let data = read_data::<String>(&mut cursor);
1299        assert!(data.is_err());
1300    }
1301
1302    #[test]
1303    fn dmaptype() -> Result<()> {
1304        assert_eq!(i8::size(), 1);
1305        assert_eq!(u8::size(), 1);
1306        assert_eq!(i16::size(), 2);
1307        assert_eq!(u16::size(), 2);
1308        assert_eq!(i32::size(), 4);
1309        assert_eq!(u32::size(), 4);
1310        assert_eq!(f32::size(), 4);
1311        assert_eq!(i64::size(), 8);
1312        assert_eq!(u64::size(), 8);
1313        assert_eq!(f64::size(), 8);
1314
1315        assert_eq!(i8::dmap_type(), Type::Char);
1316        assert_eq!(u8::dmap_type(), Type::Uchar);
1317        assert_eq!(i16::dmap_type(), Type::Short);
1318        assert_eq!(u16::dmap_type(), Type::Ushort);
1319        assert_eq!(i32::dmap_type(), Type::Int);
1320        assert_eq!(u32::dmap_type(), Type::Uint);
1321        assert_eq!(f32::dmap_type(), Type::Float);
1322        assert_eq!(i64::dmap_type(), Type::Long);
1323        assert_eq!(u64::dmap_type(), Type::Ulong);
1324        assert_eq!(f64::dmap_type(), Type::Double);
1325
1326        assert_eq!(vec![1], DmapType::as_bytes(&i8::from_bytes(&[1])?));
1327        assert_eq!(vec![1], DmapType::as_bytes(&u8::from_bytes(&[1])?));
1328        assert_eq!(vec![1, 0], DmapType::as_bytes(&i16::from_bytes(&[1, 0])?));
1329        assert_eq!(vec![1, 0], DmapType::as_bytes(&u16::from_bytes(&[1, 0])?));
1330        assert_eq!(
1331            vec![1, 0, 0, 0],
1332            DmapType::as_bytes(&i32::from_bytes(&[1, 0, 0, 0])?)
1333        );
1334        assert_eq!(
1335            vec![1, 2, 3, 4],
1336            DmapType::as_bytes(&u32::from_bytes(&[1, 2, 3, 4])?)
1337        );
1338        assert_eq!(
1339            vec![1, 0, 0, 0],
1340            DmapType::as_bytes(&f32::from_bytes(&[1, 0, 0, 0])?)
1341        );
1342        assert_eq!(
1343            vec![1, 2, 3, 4, 5, 6, 7, 8],
1344            DmapType::as_bytes(&u64::from_bytes(&[1, 2, 3, 4, 5, 6, 7, 8])?)
1345        );
1346        assert_eq!(
1347            vec![1, 0, 0, 0, 1, 2, 3, 4],
1348            DmapType::as_bytes(&i64::from_bytes(&[1, 0, 0, 0, 1, 2, 3, 4])?)
1349        );
1350        assert_eq!(
1351            vec![1, 2, 3, 4, 4, 32, 2, 1],
1352            DmapType::as_bytes(&f64::from_bytes(&[1, 2, 3, 4, 4, 32, 2, 1])?)
1353        );
1354        Ok(())
1355    }
1356
1357    #[test]
1358    fn types() -> Result<()> {
1359        assert_eq!(Type::from_key(1)?, Type::Char);
1360        assert_eq!(Type::from_key(2)?, Type::Short);
1361        assert_eq!(Type::from_key(3)?, Type::Int);
1362        assert_eq!(Type::from_key(10)?, Type::Long);
1363        assert_eq!(Type::from_key(16)?, Type::Uchar);
1364        assert_eq!(Type::from_key(17)?, Type::Ushort);
1365        assert_eq!(Type::from_key(18)?, Type::Uint);
1366        assert_eq!(Type::from_key(19)?, Type::Ulong);
1367        assert_eq!(Type::from_key(4)?, Type::Float);
1368        assert_eq!(Type::from_key(8)?, Type::Double);
1369        assert_eq!(Type::from_key(9)?, Type::String);
1370        assert!(Type::from_key(-1).is_err());
1371        assert!(Type::from_key(15).is_err());
1372        assert!(Type::from_key(0).is_err());
1373
1374        assert_eq!(Type::Char.key(), 1);
1375        assert_eq!(Type::Short.key(), 2);
1376        assert_eq!(Type::Int.key(), 3);
1377        assert_eq!(Type::Long.key(), 10);
1378        assert_eq!(Type::Uchar.key(), 16);
1379        assert_eq!(Type::Ushort.key(), 17);
1380        assert_eq!(Type::Uint.key(), 18);
1381        assert_eq!(Type::Ulong.key(), 19);
1382        assert_eq!(Type::Float.key(), 4);
1383        assert_eq!(Type::Double.key(), 8);
1384        assert_eq!(Type::String.key(), 9);
1385
1386        assert_eq!(Type::Char.size(), 1);
1387        assert_eq!(Type::Short.size(), 2);
1388        assert_eq!(Type::Int.size(), 4);
1389        assert_eq!(Type::Long.size(), 8);
1390        assert_eq!(Type::Uchar.size(), 1);
1391        assert_eq!(Type::Ushort.size(), 2);
1392        assert_eq!(Type::Uint.size(), 4);
1393        assert_eq!(Type::Ulong.size(), 8);
1394        assert_eq!(Type::Float.size(), 4);
1395        assert_eq!(Type::Double.size(), 8);
1396        assert_eq!(Type::String.size(), 0);
1397
1398        Ok(())
1399    }
1400
1401    #[test]
1402    fn dmapscalar() -> Result<()> {
1403        assert_eq!(DmapScalar::Char(0).get_type(), Type::Char);
1404        assert_eq!(DmapScalar::Short(0).get_type(), Type::Short);
1405        assert_eq!(DmapScalar::Int(0).get_type(), Type::Int);
1406        assert_eq!(DmapScalar::Long(0).get_type(), Type::Long);
1407        assert_eq!(DmapScalar::Uchar(0).get_type(), Type::Uchar);
1408        assert_eq!(DmapScalar::Ushort(0).get_type(), Type::Ushort);
1409        assert_eq!(DmapScalar::Uint(0).get_type(), Type::Uint);
1410        assert_eq!(DmapScalar::Ulong(0).get_type(), Type::Ulong);
1411        assert_eq!(DmapScalar::Float(0.0).get_type(), Type::Float);
1412        assert_eq!(DmapScalar::Double(0.0).get_type(), Type::Double);
1413        assert_eq!(
1414            DmapScalar::String("test".to_string()).get_type(),
1415            Type::String
1416        );
1417
1418        let x = DmapScalar::Char(-1);
1419        assert_eq!(x.cast_as(&Type::Short)?, DmapScalar::Short(-1));
1420        assert!(x.cast_as(&Type::Float).is_ok());
1421        assert!(x.cast_as(&Type::Uchar).is_err());
1422        assert!(x.cast_as(&Type::String).is_err());
1423
1424        let x = DmapScalar::Uchar(255);
1425        assert_eq!(x.cast_as(&Type::Short)?, DmapScalar::Short(255));
1426        assert!(x.cast_as(&Type::Char).is_err());
1427        assert!(x.cast_as(&Type::Float).is_ok());
1428        assert!(x.cast_as(&Type::Uchar).is_ok());
1429        assert!(x.cast_as(&Type::String).is_err());
1430
1431        let x = DmapScalar::Short(256);
1432        assert_eq!(x.cast_as(&Type::Short)?, DmapScalar::Short(256));
1433        assert!(x.cast_as(&Type::Char).is_err());
1434        assert_eq!(x.cast_as(&Type::Ushort)?, DmapScalar::Ushort(256));
1435        assert!(x.cast_as(&Type::Uchar).is_err());
1436        assert!(x.cast_as(&Type::Float).is_ok());
1437        assert!(x.cast_as(&Type::String).is_err());
1438
1439        let x = DmapScalar::Float(1.0);
1440        assert!(x.cast_as(&Type::Double).is_ok());
1441        assert!(x.cast_as(&Type::Char).is_err());
1442        assert!(x.cast_as(&Type::Uchar).is_err());
1443        assert!(x.cast_as(&Type::Float).is_ok());
1444        assert!(x.cast_as(&Type::String).is_err());
1445
1446        let x = DmapScalar::String("test".to_string());
1447        assert!(x.cast_as(&Type::Char).is_err());
1448        assert!(x.cast_as(&Type::Short).is_err());
1449        assert!(x.cast_as(&Type::Int).is_err());
1450        assert!(x.cast_as(&Type::Long).is_err());
1451        assert!(x.cast_as(&Type::Uchar).is_err());
1452        assert!(x.cast_as(&Type::Ushort).is_err());
1453        assert!(x.cast_as(&Type::Uint).is_err());
1454        assert!(x.cast_as(&Type::Ulong).is_err());
1455        assert!(x.cast_as(&Type::Float).is_err());
1456        assert!(x.cast_as(&Type::Double).is_err());
1457
1458        assert_eq!(
1459            DmapScalar::Char(8).as_bytes(),
1460            vec![Type::Char.key() as u8, 8]
1461        );
1462        assert_eq!(
1463            DmapScalar::Short(256).as_bytes(),
1464            vec![Type::Short.key() as u8, 0, 1]
1465        );
1466        assert_eq!(
1467            DmapScalar::Int(256).as_bytes(),
1468            vec![Type::Int.key() as u8, 0, 1, 0, 0]
1469        );
1470        assert_eq!(
1471            DmapScalar::Long(512).as_bytes(),
1472            vec![Type::Long.key() as u8, 0, 2, 0, 0, 0, 0, 0, 0]
1473        );
1474        assert_eq!(
1475            DmapScalar::Uchar(8).as_bytes(),
1476            vec![Type::Uchar.key() as u8, 8]
1477        );
1478        assert_eq!(
1479            DmapScalar::Ushort(256).as_bytes(),
1480            vec![Type::Ushort.key() as u8, 0, 1]
1481        );
1482        assert_eq!(
1483            DmapScalar::Uint(256).as_bytes(),
1484            vec![Type::Uint.key() as u8, 0, 1, 0, 0]
1485        );
1486        assert_eq!(
1487            DmapScalar::Ulong(512).as_bytes(),
1488            vec![Type::Ulong.key() as u8, 0, 2, 0, 0, 0, 0, 0, 0]
1489        );
1490        assert_eq!(
1491            DmapScalar::Float(0.0).as_bytes(),
1492            vec![Type::Float.key() as u8, 0, 0, 0, 0]
1493        );
1494        assert_eq!(
1495            DmapScalar::Double(0.0).as_bytes(),
1496            vec![Type::Double.key() as u8, 0, 0, 0, 0, 0, 0, 0, 0]
1497        );
1498        assert_eq!(
1499            DmapScalar::String("test".to_string()).as_bytes(),
1500            vec![Type::String.key() as u8, 116, 101, 115, 116, 0]
1501        );
1502
1503        Ok(())
1504    }
1505
1506    #[test]
1507    fn dmapvec() -> Result<()> {
1508        let arr = DmapVec::Char(array![0, 1, 2, 3, 4].into_dyn());
1509        assert_eq!(arr.get_type(), Type::Char);
1510        let arr = DmapVec::Uchar(array![0, 1, 2, 3, 4].into_dyn());
1511        assert_eq!(arr.get_type(), Type::Uchar);
1512        let arr = DmapVec::Short(array![0, 1, 2, 3, 4].into_dyn());
1513        assert_eq!(arr.get_type(), Type::Short);
1514        let arr = DmapVec::Ushort(array![0, 1, 2, 3, 4].into_dyn());
1515        assert_eq!(arr.get_type(), Type::Ushort);
1516        let arr = DmapVec::Int(array![0, 1, 2, 3, 4].into_dyn());
1517        assert_eq!(arr.get_type(), Type::Int);
1518        let arr = DmapVec::Uint(array![[0, 1, 2], [3, 4, 5]].into_dyn());
1519        assert_eq!(arr.get_type(), Type::Uint);
1520        let arr = DmapVec::Long(array![0, 1, 2, 3, 4].into_dyn());
1521        assert_eq!(arr.get_type(), Type::Long);
1522        let arr = DmapVec::Ulong(array![0, 1, 2, 3, 4].into_dyn());
1523        assert_eq!(arr.get_type(), Type::Ulong);
1524        let arr = DmapVec::Float(array![0.0, 1.0, 2.0, 3.0, 4.0].into_dyn());
1525        assert_eq!(arr.get_type(), Type::Float);
1526        let arr = DmapVec::Double(array![0.0, 1.0, 2.0, 3.0, 4.0].into_dyn());
1527        assert_eq!(arr.get_type(), Type::Double);
1528
1529        Ok(())
1530    }
1531
1532    #[test]
1533    fn check_fields_in_indexmap() -> Result<()> {
1534        use numpy::ndarray::array;
1535
1536        let mut rec = IndexMap::<String, DmapField>::new();
1537        let res = check_scalar(&rec, "test", &Type::Char);
1538        assert!(res.is_err());
1539        let res = check_scalar_opt(&rec, "test", &Type::Char);
1540        assert!(res.is_ok());
1541        let res = check_vector(&rec, "test", &Type::Char);
1542        assert!(res.is_err());
1543        let res = check_vector_opt(&rec, "test", &Type::Char);
1544        assert!(res.is_ok());
1545
1546        let res = rec.insert("test".to_string(), DmapField::from(1i32));
1547        assert!(res.is_none());
1548        let res = check_scalar(&rec, "test", &Type::Int);
1549        assert!(res.is_ok());
1550        let res = check_scalar_opt(&rec, "test", &Type::Char);
1551        assert!(res.is_err());
1552        let res = check_scalar_opt(&rec, "test", &Type::Int);
1553        assert!(res.is_ok());
1554        let res = check_vector(&rec, "test", &Type::Char);
1555        assert!(res.is_err());
1556        let res = check_vector_opt(&rec, "test", &Type::Char);
1557        assert!(res.is_err());
1558
1559        let test_vec = array![1.0f32, 2.0f32].into_dyn();
1560        let res = rec.insert("test_vec".to_string(), test_vec.into());
1561        assert!(res.is_none());
1562        let res = check_scalar(&rec, "test_vec", &Type::Float);
1563        assert!(res.is_err());
1564        let res = check_scalar_opt(&rec, "test_vec", &Type::Float);
1565        assert!(res.is_err());
1566        let res = check_vector(&rec, "test_vec", &Type::Float);
1567        assert!(res.is_ok());
1568        let res = check_vector(&rec, "test_vec", &Type::Double);
1569        assert!(res.is_err());
1570        let res = check_vector_opt(&rec, "test_vec", &Type::Float);
1571        assert!(res.is_ok());
1572        let res = check_vector_opt(&rec, "test_vec", &Type::Int);
1573        assert!(res.is_err());
1574
1575        Ok(())
1576    }
1577
1578    #[test]
1579    fn test_parse_header() -> Result<()> {
1580        let name: Vec<u8> = vec![116, 101, 115, 116, 0, Type::Char.key() as u8];
1581        let num_bytes = name.len();
1582        let mut cursor = Cursor::new(name);
1583        let res = parse_header(&mut cursor);
1584        assert_eq!(res?, ("test".to_string(), Type::Char));
1585        assert_eq!(cursor.position(), num_bytes as u64);
1586
1587        cursor.set_position(2);
1588        let res = parse_header(&mut cursor);
1589        assert_eq!(res?, ("st".to_string(), Type::Char));
1590
1591        cursor.set_position(5);
1592        let res = parse_scalar(&mut cursor);
1593        assert!(res.is_err());
1594
1595        let name: Vec<u8> = vec![116, 101, 115, 116, Type::Char.key() as u8]; // name not null-terminated
1596        let mut cursor = Cursor::new(name);
1597        let res = parse_header(&mut cursor);
1598        assert!(res.is_err());
1599
1600        Ok(())
1601    }
1602
1603    #[test]
1604    fn test_parse_scalar() -> Result<()> {
1605        let mut name: Vec<u8> = vec![116, 101, 115, 116, 0]; // "test" in bytes
1606        let mut data: Vec<u8> = vec![Type::Char.key() as u8, 25, 56];
1607        name.append(&mut data);
1608        let num_bytes = name.len();
1609        let mut cursor = Cursor::new(name);
1610        let res = parse_scalar(&mut cursor);
1611        assert_eq!(res?, ("test".to_string(), 25i8.into()));
1612        assert_eq!(cursor.position(), (num_bytes - 1) as u64);
1613
1614        cursor.set_position(1);
1615        let res = parse_scalar(&mut cursor);
1616        assert_eq!(res?, ("est".to_string(), 25i8.into()));
1617
1618        cursor.set_position(4);
1619        let res = parse_scalar(&mut cursor);
1620        assert_eq!(res?, ("".to_string(), 25i8.into()));
1621
1622        cursor.set_position(5);
1623        let res = parse_scalar(&mut cursor);
1624        assert!(res.is_err());
1625
1626        // This test should highlight the problem when the name is not null-terminated. The bytes of the `type` are
1627        // consumed as part of the scalar name, until a 0 is encountered.
1628        let mut name: Vec<u8> = vec![116, 101, 115, 116]; // b"test" , not null-terminated
1629        let mut data: Vec<u8> = vec![Type::Char.key() as u8, 25];
1630        name.append(&mut data);
1631        let mut cursor = Cursor::new(name);
1632        let res = parse_scalar(&mut cursor);
1633        assert!(res.is_err());
1634
1635        // This test should highlight the problem when a string field is not null-terminated.
1636        let mut name: Vec<u8> = vec![116, 101, 115, 116, 0]; // "test"
1637        let mut data: Vec<u8> = vec![Type::String.key() as u8, 116, 101, 115, 116]; // b"test" , not null-terminated
1638        name.append(&mut data);
1639        let mut cursor = Cursor::new(name);
1640        let res = parse_scalar(&mut cursor);
1641        assert!(res.is_err());
1642
1643        let mut name: Vec<u8> = vec![116, 101, 115, 116, 0]; // "test"
1644        let mut data: Vec<u8> = vec![Type::String.key() as u8, 116, 101, 115, 116, 0]; // b"test\0"
1645        name.append(&mut data);
1646        let mut cursor = Cursor::new(name);
1647        let res = parse_scalar(&mut cursor);
1648        assert_eq!(res?, ("test".to_string(), "test".to_string().into()));
1649
1650        Ok(())
1651    }
1652
1653    #[test]
1654    fn test_parse_vector() -> Result<()> {
1655        let mut name: Vec<u8> = vec![116, 101, 115, 116, 0]; // "test" in bytes
1656        let mut data: Vec<u8> = vec![Type::Char.key() as u8, 1, 0, 0, 0, 1, 0, 0, 0, 25];
1657        name.append(&mut data);
1658        let num_bytes = name.len();
1659        let mut cursor = Cursor::new(name);
1660        let res = parse_vector(&mut cursor, 15);
1661        assert_eq!(res?, ("test".to_string(), array![25i8].into_dyn().into()));
1662        assert_eq!(cursor.position(), num_bytes as u64);
1663
1664        let mut name: Vec<u8> = vec![116, 101, 115, 116, 0]; // "test" in bytes
1665        let mut data: Vec<u8> = vec![
1666            Type::Char.key() as u8,
1667            2,
1668            0,
1669            0,
1670            0,
1671            3,
1672            0,
1673            0,
1674            0,
1675            2,
1676            0,
1677            0,
1678            0,
1679            1,
1680            2,
1681            3,
1682            4,
1683            5,
1684            6,
1685        ];
1686        name.append(&mut data);
1687        let num_bytes = name.len();
1688        let mut cursor = Cursor::new(name);
1689        let res = parse_vector(&mut cursor, 24);
1690        assert_eq!(
1691            res?,
1692            (
1693                "test".to_string(),
1694                array![[1i8, 2, 3], [4, 5, 6]].into_dyn().into()
1695            )
1696        );
1697        assert_eq!(cursor.position(), num_bytes as u64);
1698
1699        cursor.set_position(0);
1700        let res = parse_vector(&mut cursor, 3);
1701        assert!(res.is_err()); // size (all dimensions multiplied together) greater than record size (6 > 3)
1702
1703        let mut name: Vec<u8> = vec![116, 101, 115, 116, 0]; // "test" in bytes
1704        let mut data: Vec<u8> = vec![
1705            Type::Char.key() as u8,
1706            100,
1707            0,
1708            0,
1709            0,
1710            1,
1711            0,
1712            0,
1713            0,
1714            1,
1715            2,
1716            3,
1717            4,
1718            5,
1719            6,
1720        ];
1721        name.append(&mut data);
1722        let mut cursor = Cursor::new(name);
1723        let res = parse_vector(&mut cursor, 24);
1724        assert!(res.is_err()); // number of dimensions greater than record size (100 > 24)
1725
1726        Ok(())
1727    }
1728}