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