Skip to main content

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 zerocopy::{AsBytes, ByteOrder, FromBytes, LittleEndian};
14
15type Result<T> = std::result::Result<T, DmapError>;
16
17/// Defines the fields of a record and their [`Type`].
18pub struct Fields<'a> {
19    /// The names of all fields of the record type
20    pub all_fields: Vec<&'a str>,
21    /// The name and Type of each required scalar field
22    pub scalars_required: Vec<(&'a str, Type)>,
23    /// The name and Type of each optional scalar field
24    pub scalars_optional: Vec<(&'a str, Type)>,
25    /// The name and Type of each required vector field
26    pub vectors_required: Vec<(&'a str, Type)>,
27    /// The name and Type of each optional vector field
28    pub vectors_optional: Vec<(&'a str, Type)>,
29    /// Groups of vector fields which must have identical dimensions
30    pub vector_dim_groups: Vec<Vec<&'a str>>,
31    /// The name of each field which is a data (as opposed to metadata) field
32    pub data_fields: Vec<&'a str>,
33}
34
35/// The possible data types that a scalar or vector field may have.
36///
37/// **Note**: `String` type is not supported for vector fields.
38#[derive(Debug, PartialEq, Clone)]
39pub enum Type {
40    Char,
41    Short,
42    Int,
43    Long,
44    Uchar,
45    Ushort,
46    Uint,
47    Ulong,
48    Float,
49    Double,
50    String,
51}
52impl Display for Type {
53    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
54        match self {
55            Self::Char => write!(f, "CHAR"),
56            Self::Short => write!(f, "SHORT"),
57            Self::Int => write!(f, "INT"),
58            Self::Float => write!(f, "FLOAT"),
59            Self::Double => write!(f, "DOUBLE"),
60            Self::String => write!(f, "STRING"),
61            Self::Long => write!(f, "LONG"),
62            Self::Uchar => write!(f, "UCHAR"),
63            Self::Ushort => write!(f, "USHORT"),
64            Self::Uint => write!(f, "UINT"),
65            Self::Ulong => write!(f, "ULONG"),
66        }
67    }
68}
69impl Type {
70    /// 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)).
71    /// Returns the `Type` if the key is supported, otherwise raises `DmapError`
72    pub(crate) fn from_key(key: i8) -> Result<Self> {
73        let data = match key {
74            1 => Self::Char,
75            2 => Self::Short,
76            3 => Self::Int,
77            10 => Self::Long,
78            16 => Self::Uchar,
79            17 => Self::Ushort,
80            18 => Self::Uint,
81            19 => Self::Ulong,
82            4 => Self::Float,
83            8 => Self::Double,
84            9 => Self::String,
85            x => Err(DmapError::InvalidKey(x))?,
86        };
87        Ok(data)
88    }
89    /// Returns the corresponding key for the `Type` variant.
90    pub(crate) fn key(&self) -> i8 {
91        match self {
92            Self::Char => 1,
93            Self::Short => 2,
94            Self::Int => 3,
95            Self::Long => 10,
96            Self::Uchar => 16,
97            Self::Ushort => 17,
98            Self::Uint => 18,
99            Self::Ulong => 19,
100            Self::Float => 4,
101            Self::Double => 8,
102            Self::String => 9,
103        }
104    }
105    /// The size in bytes of the data for `Type`
106    pub fn size(&self) -> usize {
107        match self {
108            Self::Char => 1,
109            Self::Short => 2,
110            Self::Int => 4,
111            Self::Long => 8,
112            Self::Uchar => 1,
113            Self::Ushort => 2,
114            Self::Uint => 4,
115            Self::Ulong => 8,
116            Self::Float => 4,
117            Self::Double => 8,
118            Self::String => 0,
119        }
120    }
121}
122
123/// A scalar field in a DMAP record.
124#[derive(Debug, Clone, PartialEq, FromPyObject, IntoPyObject)]
125#[repr(C)]
126pub enum DmapScalar {
127    Char(i8),
128    Short(i16),
129    Int(i32),
130    Long(i64),
131    Uchar(u8),
132    Ushort(u16),
133    Uint(u32),
134    Ulong(u64),
135    Float(f32),
136    Double(f64),
137    String(String),
138}
139impl DmapScalar {
140    /// Gets the corresponding `Type`
141    pub(crate) fn get_type(&self) -> Type {
142        match self {
143            Self::Char(_) => Type::Char,
144            Self::Short(_) => Type::Short,
145            Self::Int(_) => Type::Int,
146            Self::Long(_) => Type::Long,
147            Self::Uchar(_) => Type::Uchar,
148            Self::Ushort(_) => Type::Ushort,
149            Self::Uint(_) => Type::Uint,
150            Self::Ulong(_) => Type::Ulong,
151            Self::Float(_) => Type::Float,
152            Self::Double(_) => Type::Double,
153            Self::String(_) => Type::String,
154        }
155    }
156
157    /// Converts `self` into a new `Type`, if possible.
158    pub(crate) fn cast_as(&self, new_type: &Type) -> Result<Self> {
159        match new_type {
160            Type::Char => Ok(Self::Char(i8::try_from(self.clone())?)),
161            Type::Short => Ok(Self::Short(i16::try_from(self.clone())?)),
162            Type::Int => Ok(Self::Int(i32::try_from(self.clone())?)),
163            Type::Long => Ok(Self::Long(i64::try_from(self.clone())?)),
164            Type::Uchar => Ok(Self::Uchar(u8::try_from(self.clone())?)),
165            Type::Ushort => Ok(Self::Ushort(u16::try_from(self.clone())?)),
166            Type::Uint => Ok(Self::Uint(u32::try_from(self.clone())?)),
167            Type::Ulong => Ok(Self::Ulong(u64::try_from(self.clone())?)),
168            Type::Float => Ok(Self::Float(f32::try_from(self.clone())?)),
169            Type::Double => Ok(Self::Double(f64::try_from(self.clone())?)),
170            Type::String => Err(DmapError::InvalidScalar(
171                "Unable to cast value to String".to_string(),
172            )),
173        }
174    }
175    /// Copies the data and metadata (`Type` key) to raw bytes
176    pub(crate) fn as_bytes(&self) -> Vec<u8> {
177        let mut bytes: Vec<u8> = DmapType::as_bytes(&self.get_type().key()).to_vec();
178        let mut data_bytes: Vec<u8> = match self {
179            Self::Char(x) => DmapType::as_bytes(x),
180            Self::Short(x) => DmapType::as_bytes(x),
181            Self::Int(x) => DmapType::as_bytes(x),
182            Self::Long(x) => DmapType::as_bytes(x),
183            Self::Uchar(x) => DmapType::as_bytes(x),
184            Self::Ushort(x) => DmapType::as_bytes(x),
185            Self::Uint(x) => DmapType::as_bytes(x),
186            Self::Ulong(x) => DmapType::as_bytes(x),
187            Self::Float(x) => DmapType::as_bytes(x),
188            Self::Double(x) => DmapType::as_bytes(x),
189            Self::String(x) => DmapType::as_bytes(x),
190        };
191        bytes.append(&mut data_bytes);
192        bytes
193    }
194}
195impl Display for DmapScalar {
196    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
197        match self {
198            Self::Char(x) => write!(f, "CHAR {x}"),
199            Self::Short(x) => write!(f, "SHORT {x}"),
200            Self::Int(x) => write!(f, "INT {x}"),
201            Self::Float(x) => write!(f, "FLOAT {x}"),
202            Self::Double(x) => write!(f, "DOUBLE {x}"),
203            Self::String(x) => write!(f, "STRING {x}"),
204            Self::Long(x) => write!(f, "LONG {x}"),
205            Self::Uchar(x) => write!(f, "UCHAR {x}"),
206            Self::Ushort(x) => write!(f, "USHORT {x}"),
207            Self::Uint(x) => write!(f, "UINT {x}"),
208            Self::Ulong(x) => write!(f, "ULONG {x}"),
209        }
210    }
211}
212// impl IntoPy<PyObject> for DmapScalar {
213//     fn into_py(self, py: Python<'_>) -> PyObject {
214//         match self {
215//             Self::Char(x) => x.into_py(py),
216//             Self::Short(x) => x.into_py(py),
217//             Self::Int(x) => x.into_py(py),
218//             Self::Long(x) => x.into_py(py),
219//             Self::Uchar(x) => x.into_py(py),
220//             Self::Ushort(x) => x.into_py(py),
221//             Self::Uint(x) => x.into_py(py),
222//             Self::Ulong(x) => x.into_py(py),
223//             Self::Float(x) => x.into_py(py),
224//             Self::Double(x) => x.into_py(py),
225//             Self::String(x) => x.into_py(py),
226//         }
227//     }
228// }
229
230macro_rules! vec_to_bytes {
231    ($bytes:ident, $x:ident) => {{
232        $bytes.extend(($x.ndim() as i32).to_le_bytes());
233        for &dim in $x.shape().iter().rev() {
234            $bytes.extend((dim as i32).to_le_bytes());
235        }
236        for y in $x.iter() {
237            $bytes.append(&mut DmapType::as_bytes(y).to_vec());
238        }
239    }};
240}
241
242/// A vector field in a DMAP record.
243#[derive(Clone, Debug, PartialEq)]
244pub enum DmapVec {
245    Char(ArrayD<i8>),
246    Short(ArrayD<i16>),
247    Int(ArrayD<i32>),
248    Long(ArrayD<i64>),
249    Uchar(ArrayD<u8>),
250    Ushort(ArrayD<u16>),
251    Uint(ArrayD<u32>),
252    Ulong(ArrayD<u64>),
253    Float(ArrayD<f32>),
254    Double(ArrayD<f64>),
255}
256impl DmapVec {
257    /// Gets the corresponding [`Type`] of the vector.
258    #[inline]
259    pub(crate) fn get_type(&self) -> Type {
260        match self {
261            DmapVec::Char(_) => Type::Char,
262            DmapVec::Short(_) => Type::Short,
263            DmapVec::Int(_) => Type::Int,
264            DmapVec::Long(_) => Type::Long,
265            DmapVec::Uchar(_) => Type::Uchar,
266            DmapVec::Ushort(_) => Type::Ushort,
267            DmapVec::Uint(_) => Type::Uint,
268            DmapVec::Ulong(_) => Type::Ulong,
269            DmapVec::Float(_) => Type::Float,
270            DmapVec::Double(_) => Type::Double,
271        }
272    }
273    /// Copies the data and metadata (dimensions, [`Type`] key) to raw bytes
274    #[inline]
275    pub(crate) fn as_bytes(&self) -> Vec<u8> {
276        let mut bytes: Vec<u8> = DmapType::as_bytes(&self.get_type().key()).to_vec();
277        match self {
278            DmapVec::Char(x) => vec_to_bytes!(bytes, x),
279            DmapVec::Short(x) => vec_to_bytes!(bytes, x),
280            DmapVec::Int(x) => vec_to_bytes!(bytes, x),
281            DmapVec::Long(x) => vec_to_bytes!(bytes, x),
282            DmapVec::Uchar(x) => vec_to_bytes!(bytes, x),
283            DmapVec::Ushort(x) => vec_to_bytes!(bytes, x),
284            DmapVec::Uint(x) => vec_to_bytes!(bytes, x),
285            DmapVec::Ulong(x) => vec_to_bytes!(bytes, x),
286            DmapVec::Float(x) => vec_to_bytes!(bytes, x),
287            DmapVec::Double(x) => vec_to_bytes!(bytes, x),
288        };
289        bytes
290    }
291
292    /// Gets the dimensions of the vector, in row-major order.
293    /// ## Example
294    /// ```
295    /// use numpy::ndarray::array;
296    /// use dmap::types::DmapVec;
297    ///
298    /// let arr = DmapVec::Char(array![0, 1, 2, 3, 4].into_dyn());
299    /// assert_eq!(arr.shape(), &[5]);
300    ///
301    /// let arr = DmapVec::Uint(array![[0, 1, 2], [3, 4, 5]].into_dyn());
302    /// assert_eq!(arr.shape(), &[2, 3]);
303    /// ```
304    #[must_use]
305    pub fn shape(&self) -> &[usize] {
306        match self {
307            DmapVec::Char(x) => x.shape(),
308            DmapVec::Short(x) => x.shape(),
309            DmapVec::Int(x) => x.shape(),
310            DmapVec::Long(x) => x.shape(),
311            DmapVec::Uchar(x) => x.shape(),
312            DmapVec::Ushort(x) => x.shape(),
313            DmapVec::Uint(x) => x.shape(),
314            DmapVec::Ulong(x) => x.shape(),
315            DmapVec::Float(x) => x.shape(),
316            DmapVec::Double(x) => x.shape(),
317        }
318    }
319}
320impl<'py> IntoPyObject<'py> for DmapVec {
321    type Target = PyAny;
322    type Output = Bound<'py, Self::Target>;
323    type Error = std::convert::Infallible;
324
325    fn into_pyobject(self, py: Python<'py>) -> std::result::Result<Self::Output, Self::Error> {
326        Ok(match self {
327            DmapVec::Char(x) => PyArray::from_owned_array(py, x).into_any(),
328            DmapVec::Short(x) => PyArray::from_owned_array(py, x).into_any(),
329            DmapVec::Int(x) => PyArray::from_owned_array(py, x).into_any(),
330            DmapVec::Long(x) => PyArray::from_owned_array(py, x).into_any(),
331            DmapVec::Uchar(x) => PyArray::from_owned_array(py, x).into_any(),
332            DmapVec::Ushort(x) => PyArray::from_owned_array(py, x).into_any(),
333            DmapVec::Uint(x) => PyArray::from_owned_array(py, x).into_any(),
334            DmapVec::Ulong(x) => PyArray::from_owned_array(py, x).into_any(),
335            DmapVec::Float(x) => PyArray::from_owned_array(py, x).into_any(),
336            DmapVec::Double(x) => PyArray::from_owned_array(py, x).into_any(),
337        })
338    }
339}
340impl<'py> FromPyObject<'py> for DmapVec {
341    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
342        if let Ok(x) = ob.downcast::<PyArray<u8, _>>() {
343            Ok(DmapVec::Uchar(x.to_owned_array()))
344        } else if let Ok(x) = ob.downcast::<PyArray<u16, _>>() {
345            Ok(DmapVec::Ushort(x.to_owned_array()))
346        } else if let Ok(x) = ob.downcast::<PyArray<u32, _>>() {
347            Ok(DmapVec::Uint(x.to_owned_array()))
348        } else if let Ok(x) = ob.downcast::<PyArray<u64, _>>() {
349            Ok(DmapVec::Ulong(x.to_owned_array()))
350        } else if let Ok(x) = ob.downcast::<PyArray<i8, _>>() {
351            Ok(DmapVec::Char(x.to_owned_array()))
352        } else if let Ok(x) = ob.downcast::<PyArray<i16, _>>() {
353            Ok(DmapVec::Short(x.to_owned_array()))
354        } else if let Ok(x) = ob.downcast::<PyArray<i32, _>>() {
355            Ok(DmapVec::Int(x.to_owned_array()))
356        } else if let Ok(x) = ob.downcast::<PyArray<i64, _>>() {
357            Ok(DmapVec::Long(x.to_owned_array()))
358        } else if let Ok(x) = ob.downcast::<PyArray<f32, _>>() {
359            Ok(DmapVec::Float(x.to_owned_array()))
360        } else if let Ok(x) = ob.downcast::<PyArray<f64, _>>() {
361            Ok(DmapVec::Double(x.to_owned_array()))
362        } else {
363            Err(PyValueError::new_err("Could not extract vector"))
364        }
365    }
366}
367
368/// Generates trait implementations for infallible conversion into [`DmapVec`] and fallible conversion
369/// back.
370///
371/// Example: `vec_impls!(ArrayD<i8>, DmapVec::Char)` will generate `impl From<ArrayD<i8>> for
372/// DmapVec` and `impl TryFrom<DmapVec> for ArrayD<i8>` code blocks.
373macro_rules! vec_impls {
374    ($type:ty, $enum_var:path) => {
375        impl From<$type> for DmapVec {
376            #[inline]
377            fn from(value: $type) -> Self {
378                $enum_var(value)
379            }
380        }
381
382        impl TryFrom<DmapVec> for $type {
383            type Error = DmapError;
384
385            fn try_from(value: DmapVec) -> std::result::Result<Self, Self::Error> {
386                if let $enum_var(x) = value {
387                    Ok(x)
388                } else {
389                    Err(DmapError::InvalidVector(format!(
390                        "Cannot convert to {}",
391                        stringify!($type)
392                    )))
393                }
394            }
395        }
396
397        impl From<$type> for DmapField {
398            #[inline]
399            fn from(value: $type) -> Self {
400                DmapField::Vector($enum_var(value))
401            }
402        }
403
404        impl TryFrom<DmapField> for $type {
405            type Error = DmapError;
406
407            fn try_from(value: DmapField) -> std::result::Result<Self, Self::Error> {
408                match value {
409                    DmapField::Vector(x) => x.try_into(),
410                    _ => Err(Self::Error::InvalidVector(format!(
411                        "Cannot interpret as {}",
412                        stringify!($type)
413                    ))),
414                }
415            }
416        }
417    };
418}
419
420vec_impls!(ArrayD<i8>, DmapVec::Char);
421vec_impls!(ArrayD<i16>, DmapVec::Short);
422vec_impls!(ArrayD<i32>, DmapVec::Int);
423vec_impls!(ArrayD<i64>, DmapVec::Long);
424vec_impls!(ArrayD<u8>, DmapVec::Uchar);
425vec_impls!(ArrayD<u16>, DmapVec::Ushort);
426vec_impls!(ArrayD<u32>, DmapVec::Uint);
427vec_impls!(ArrayD<u64>, DmapVec::Ulong);
428vec_impls!(ArrayD<f32>, DmapVec::Float);
429vec_impls!(ArrayD<f64>, DmapVec::Double);
430
431/// A generic field of a DMAP record.
432///
433/// This is the type that is stored in a DMAP record, representing either a scalar or
434/// vector field.
435#[derive(Debug, Clone, PartialEq, FromPyObject, IntoPyObject)]
436#[repr(C)]
437pub enum DmapField {
438    Vector(DmapVec),
439    Scalar(DmapScalar),
440}
441impl DmapField {
442    /// Converts the field and metadata (`Type` key and dimensions if applicable) to raw bytes.
443    #[inline]
444    #[must_use]
445    pub fn as_bytes(&self) -> Vec<u8> {
446        match self {
447            Self::Scalar(x) => x.as_bytes(),
448            Self::Vector(x) => x.as_bytes(),
449        }
450    }
451}
452// impl IntoPyObject for DmapField {
453//     fn into_py(self, py: Python<'_>) -> PyObject {
454//         match self {
455//             DmapField::Scalar(x) => x.into_py(py),
456//             DmapField::Vector(x) => x.into_py(py),
457//         }
458//     }
459// }
460
461/// Macro for implementing conversion traits between primitives and [`DmapField`], [`DmapScalar`]
462/// types.
463///
464/// Example: `scalar_impls(i8, DmapScalar::Char)` will implement:
465///   `From<i8> for DmapField`
466///   `TryFrom<DmapField> for i8`
467macro_rules! scalar_impls {
468    ($type:ty, $enum_var:path, $type_var:path) => {
469        impl From<$type> for DmapField {
470            fn from(value: $type) -> Self {
471                DmapField::Scalar($enum_var(value))
472            }
473        }
474        impl TryFrom<DmapField> for $type {
475            type Error = DmapError;
476
477            fn try_from(value: DmapField) -> std::result::Result<Self, Self::Error> {
478                match value {
479                    DmapField::Scalar(x) => x.try_into(),
480                    _ => Err(Self::Error::InvalidScalar(format!(
481                        "Cannot interpret {value:?} as {}",
482                        stringify!($type)
483                    ))),
484                }
485            }
486        }
487    };
488}
489
490scalar_impls!(i8, DmapScalar::Char, Type::Char);
491scalar_impls!(i16, DmapScalar::Short, Type::Short);
492scalar_impls!(i32, DmapScalar::Int, Type::Int);
493scalar_impls!(i64, DmapScalar::Long, Type::Long);
494scalar_impls!(u8, DmapScalar::Uchar, Type::Uchar);
495scalar_impls!(u16, DmapScalar::Ushort, Type::Ushort);
496scalar_impls!(u32, DmapScalar::Uint, Type::Uint);
497scalar_impls!(u64, DmapScalar::Ulong, Type::Ulong);
498scalar_impls!(f32, DmapScalar::Float, Type::Float);
499scalar_impls!(f64, DmapScalar::Double, Type::Double);
500scalar_impls!(String, DmapScalar::String, Type::String);
501
502/// Trait for raw types that can be stored in DMAP files.
503pub trait DmapType: std::fmt::Debug {
504    /// Size in bytes of the type.
505    fn size() -> usize
506    where
507        Self: Sized;
508    /// Create a copy of the data as raw bytes.
509    fn as_bytes(&self) -> Vec<u8>;
510    /// Convert raw bytes to `Self`
511    ///
512    /// # Errors
513    /// If the bytes are not a valid DMAP record of type `Self`.
514    fn from_bytes(bytes: &[u8]) -> Result<Self>
515    where
516        Self: Sized;
517    /// Get the `Type` variant that represents `self`
518    fn dmap_type() -> Type;
519}
520
521/// Macro for implementing [`DmapType`] trait for primitive types.
522/// Example: `type_impls!(i8, Type::Char, 1)`
523macro_rules! type_impls {
524    // This variant captures single-byte types
525    ($type:ty, $enum_var:path, 1) => {
526        impl DmapType for $type {
527            #[inline]
528            fn size() -> usize { 1 }
529
530            #[inline]
531            fn as_bytes(&self) -> Vec<u8> {
532                AsBytes::as_bytes(self).to_vec()
533            }
534
535            #[inline]
536            fn from_bytes(bytes: &[u8]) -> Result<Self>
537            where
538                Self: Sized,
539            {
540                Self::read_from(bytes).ok_or(DmapError::CorruptStream("Unable to interpret bytes"))
541            }
542
543            #[inline]
544            fn dmap_type() -> Type { $enum_var }
545        }
546    };
547    // This variant captures multi-byte primitive types
548    ($type:ty, $enum_var:path, $num_bytes:expr) => {
549        paste! {
550            impl DmapType for $type {
551                #[inline]
552                fn size() -> usize { $num_bytes }
553
554                #[inline]
555                fn as_bytes(&self) -> Vec<u8> {
556                    let mut bytes = [0; $num_bytes];
557                    LittleEndian::[< write_ $type >](&mut bytes, *self);
558                    bytes.to_vec()
559                }
560
561                #[inline]
562                fn from_bytes(bytes: &[u8]) -> Result<Self>
563                where
564                    Self: Sized,
565                {
566                    Self::read_from(bytes).ok_or(DmapError::CorruptStream("Unable to interpret bytes"))
567                }
568
569                #[inline]
570                fn dmap_type() -> Type { $enum_var }
571            }
572        }
573    }
574}
575
576type_impls!(i8, Type::Char, 1);
577type_impls!(i16, Type::Short, 2);
578type_impls!(i32, Type::Int, 4);
579type_impls!(i64, Type::Long, 8);
580type_impls!(u8, Type::Uchar, 1);
581type_impls!(u16, Type::Ushort, 2);
582type_impls!(u32, Type::Uint, 4);
583type_impls!(u64, Type::Ulong, 8);
584type_impls!(f32, Type::Float, 4);
585type_impls!(f64, Type::Double, 8);
586
587// This implementation differs significantly from the others, so it doesn't use the macro
588impl DmapType for String {
589    #[inline]
590    fn size() -> usize {
591        0
592    }
593
594    #[inline]
595    fn as_bytes(&self) -> Vec<u8> {
596        let mut bytes = self.as_bytes().to_vec();
597        bytes.push(0); // null-terminate
598        bytes
599    }
600
601    #[inline]
602    fn from_bytes(bytes: &[u8]) -> Result<Self> {
603        let data = String::from_utf8(bytes.to_owned())
604            .map_err(|_| DmapError::InvalidScalar("Cannot convert bytes to String".to_string()))?;
605        Ok(data.trim_end_matches(char::from(0)).to_string())
606    }
607
608    #[inline]
609    fn dmap_type() -> Type {
610        Type::String
611    }
612}
613
614impl TryFrom<DmapScalar> for u8 {
615    type Error = DmapError;
616    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
617        match value {
618            DmapScalar::Char(x) => Ok(u8::try_from(x)?),
619            DmapScalar::Short(x) => Ok(u8::try_from(x)?),
620            DmapScalar::Int(x) => Ok(u8::try_from(x)?),
621            DmapScalar::Long(x) => Ok(u8::try_from(x)?),
622            DmapScalar::Uchar(x) => Ok(x),
623            DmapScalar::Ushort(x) => Ok(u8::try_from(x)?),
624            DmapScalar::Uint(x) => Ok(u8::try_from(x)?),
625            DmapScalar::Ulong(x) => Ok(u8::try_from(x)?),
626            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
627                "Unable to convert {x}_f32 to u8"
628            ))),
629            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
630                "Unable to convert {x}_f64 to u8"
631            ))),
632            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
633                "Unable to convert {x} to u8"
634            ))),
635        }
636    }
637}
638impl TryFrom<DmapScalar> for u16 {
639    type Error = DmapError;
640    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
641        match value {
642            DmapScalar::Char(x) => Ok(u16::try_from(x)?),
643            DmapScalar::Short(x) => Ok(u16::try_from(x)?),
644            DmapScalar::Int(x) => Ok(u16::try_from(x)?),
645            DmapScalar::Long(x) => Ok(u16::try_from(x)?),
646            DmapScalar::Uchar(x) => Ok(x as u16),
647            DmapScalar::Ushort(x) => Ok(x),
648            DmapScalar::Uint(x) => Ok(u16::try_from(x)?),
649            DmapScalar::Ulong(x) => Ok(u16::try_from(x)?),
650            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
651                "Unable to convert {x}_f32 to u16"
652            ))),
653            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
654                "Unable to convert {x}_f64 to u16"
655            ))),
656            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
657                "Unable to convert {x} to u16"
658            ))),
659        }
660    }
661}
662impl TryFrom<DmapScalar> for u32 {
663    type Error = DmapError;
664    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
665        match value {
666            DmapScalar::Char(x) => Ok(u32::try_from(x)?),
667            DmapScalar::Short(x) => Ok(u32::try_from(x)?),
668            DmapScalar::Int(x) => Ok(u32::try_from(x)?),
669            DmapScalar::Long(x) => Ok(u32::try_from(x)?),
670            DmapScalar::Uchar(x) => Ok(x as u32),
671            DmapScalar::Ushort(x) => Ok(x as u32),
672            DmapScalar::Uint(x) => Ok(x),
673            DmapScalar::Ulong(x) => Ok(u32::try_from(x)?),
674            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
675                "Unable to convert {x}_f32 to u32"
676            ))),
677            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
678                "Unable to convert {x}_f64 to u32"
679            ))),
680            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
681                "Unable to convert {x} to u32"
682            ))),
683        }
684    }
685}
686impl TryFrom<DmapScalar> for u64 {
687    type Error = DmapError;
688    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
689        match value {
690            DmapScalar::Char(x) => Ok(u64::try_from(x)?),
691            DmapScalar::Short(x) => Ok(u64::try_from(x)?),
692            DmapScalar::Int(x) => Ok(u64::try_from(x)?),
693            DmapScalar::Long(x) => Ok(u64::try_from(x)?),
694            DmapScalar::Uchar(x) => Ok(x as u64),
695            DmapScalar::Ushort(x) => Ok(x as u64),
696            DmapScalar::Uint(x) => Ok(x as u64),
697            DmapScalar::Ulong(x) => Ok(x),
698            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
699                "Unable to convert {x}_f32 to u64"
700            ))),
701            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
702                "Unable to convert {x}_f64 to u64"
703            ))),
704            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
705                "Unable to convert {x} to u64"
706            ))),
707        }
708    }
709}
710impl TryFrom<DmapScalar> for i8 {
711    type Error = DmapError;
712    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
713        match value {
714            DmapScalar::Char(x) => Ok(x),
715            DmapScalar::Short(x) => Ok(i8::try_from(x)?),
716            DmapScalar::Int(x) => Ok(i8::try_from(x)?),
717            DmapScalar::Long(x) => Ok(i8::try_from(x)?),
718            DmapScalar::Uchar(x) => Ok(i8::try_from(x)?),
719            DmapScalar::Ushort(x) => Ok(i8::try_from(x)?),
720            DmapScalar::Uint(x) => Ok(i8::try_from(x)?),
721            DmapScalar::Ulong(x) => Ok(i8::try_from(x)?),
722            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
723                "Unable to convert {x}_f32 to i8"
724            ))),
725            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
726                "Unable to convert {x}_f64 to i8"
727            ))),
728            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
729                "Unable to convert {x} to i8"
730            ))),
731        }
732    }
733}
734impl TryFrom<DmapScalar> for i16 {
735    type Error = DmapError;
736    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
737        match value {
738            DmapScalar::Char(x) => Ok(x as i16),
739            DmapScalar::Short(x) => Ok(x),
740            DmapScalar::Int(x) => Ok(i16::try_from(x)?),
741            DmapScalar::Long(x) => Ok(i16::try_from(x)?),
742            DmapScalar::Uchar(x) => Ok(x as i16),
743            DmapScalar::Ushort(x) => Ok(i16::try_from(x)?),
744            DmapScalar::Uint(x) => Ok(i16::try_from(x)?),
745            DmapScalar::Ulong(x) => Ok(i16::try_from(x)?),
746            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
747                "Unable to convert {x}_f32 to i16"
748            ))),
749            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
750                "Unable to convert {x}_f64 to i16"
751            ))),
752            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
753                "Unable to convert {x} to i16"
754            ))),
755        }
756    }
757}
758impl TryFrom<DmapScalar> for i32 {
759    type Error = DmapError;
760    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
761        match value {
762            DmapScalar::Char(x) => Ok(x as i32),
763            DmapScalar::Short(x) => Ok(x as i32),
764            DmapScalar::Int(x) => Ok(x),
765            DmapScalar::Long(x) => Ok(i32::try_from(x)?),
766            DmapScalar::Uchar(x) => Ok(x as i32),
767            DmapScalar::Ushort(x) => Ok(x as i32),
768            DmapScalar::Uint(x) => Ok(i32::try_from(x)?),
769            DmapScalar::Ulong(x) => Ok(i32::try_from(x)?),
770            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
771                "Unable to convert {x}_f32 to i32"
772            ))),
773            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
774                "Unable to convert {x}_f64 to i32"
775            ))),
776            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
777                "Unable to convert {x} to i32"
778            ))),
779        }
780    }
781}
782impl TryFrom<DmapScalar> for i64 {
783    type Error = DmapError;
784    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
785        match value {
786            DmapScalar::Char(x) => Ok(x as i64),
787            DmapScalar::Short(x) => Ok(x as i64),
788            DmapScalar::Int(x) => Ok(x as i64),
789            DmapScalar::Long(x) => Ok(x),
790            DmapScalar::Uchar(x) => Ok(x as i64),
791            DmapScalar::Ushort(x) => Ok(x as i64),
792            DmapScalar::Uint(x) => Ok(x as i64),
793            DmapScalar::Ulong(x) => Ok(i64::try_from(x)?),
794            DmapScalar::Float(x) => Err(DmapError::InvalidScalar(format!(
795                "Unable to convert {x}_f32 to i64"
796            ))),
797            DmapScalar::Double(x) => Err(DmapError::InvalidScalar(format!(
798                "Unable to convert {x}_f64 to i64"
799            ))),
800            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
801                "Unable to convert {x} to i64"
802            ))),
803        }
804    }
805}
806impl TryFrom<DmapScalar> for f32 {
807    type Error = DmapError;
808    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
809        match value {
810            DmapScalar::Char(x) => Ok(x as f32),
811            DmapScalar::Short(x) => Ok(x as f32),
812            DmapScalar::Int(x) => Ok(x as f32),
813            DmapScalar::Long(x) => Ok(x as f32),
814            DmapScalar::Uchar(x) => Ok(x as f32),
815            DmapScalar::Ushort(x) => Ok(x as f32),
816            DmapScalar::Uint(x) => Ok(x as f32),
817            DmapScalar::Ulong(x) => Ok(x as f32),
818            DmapScalar::Float(x) => Ok(x),
819            DmapScalar::Double(x) => Ok(x as f32),
820            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
821                "Unable to convert {x} to f32"
822            ))),
823        }
824    }
825}
826impl TryFrom<DmapScalar> for f64 {
827    type Error = DmapError;
828    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
829        match value {
830            DmapScalar::Char(x) => Ok(x as f64),
831            DmapScalar::Short(x) => Ok(x as f64),
832            DmapScalar::Int(x) => Ok(x as f64),
833            DmapScalar::Long(x) => Ok(x as f64),
834            DmapScalar::Uchar(x) => Ok(x as f64),
835            DmapScalar::Ushort(x) => Ok(x as f64),
836            DmapScalar::Uint(x) => Ok(x as f64),
837            DmapScalar::Ulong(x) => Ok(x as f64),
838            DmapScalar::Float(x) => Ok(f64::from(x)),
839            DmapScalar::Double(x) => Ok(x),
840            DmapScalar::String(x) => Err(DmapError::InvalidScalar(format!(
841                "Unable to convert {x} to f64"
842            ))),
843        }
844    }
845}
846impl TryFrom<DmapScalar> for String {
847    type Error = DmapError;
848    fn try_from(value: DmapScalar) -> std::result::Result<Self, Self::Error> {
849        match value {
850            DmapScalar::String(x) => Ok(x),
851            x => Err(DmapError::InvalidScalar(format!(
852                "Unable to convert {x} to String"
853            ))),
854        }
855    }
856}
857
858/// Verify that `name` exists in `fields` and is of the correct [`Type`].
859///
860/// # Errors
861/// If `name` is not in `fields`.
862///
863/// If `name` is in `fields`, but is not a [`DmapField::Scalar`] of `expected_type`.
864pub fn check_scalar(
865    fields: &IndexMap<String, DmapField>,
866    name: &str,
867    expected_type: &Type,
868) -> Result<()> {
869    match fields.get(name) {
870        Some(DmapField::Scalar(data)) if data.get_type() == *expected_type => Ok(()),
871        Some(DmapField::Scalar(data)) => Err(DmapError::InvalidScalar(format!(
872            "{name} is of type {}, expected {}",
873            data.get_type(),
874            expected_type
875        ))),
876        Some(_) => Err(DmapError::InvalidScalar(format!(
877            "{name} is a vector field"
878        ))),
879        None => Err(DmapError::InvalidScalar(format!("{name} is not in record"))),
880    }
881}
882
883/// If `name` is in `fields`, verify that it is of the correct [`Type`].
884///
885/// # Errors
886/// If `name` is in `fields`, but is not a [`DmapField::Scalar`] of `expected_type`.
887pub fn check_scalar_opt(
888    fields: &IndexMap<String, DmapField>,
889    name: &str,
890    expected_type: &Type,
891) -> Result<()> {
892    match fields.get(name) {
893        Some(DmapField::Scalar(data)) if data.get_type() == *expected_type => Ok(()),
894        Some(DmapField::Scalar(data)) => Err(DmapError::InvalidScalar(format!(
895            "{name} is of type {}, expected {}",
896            data.get_type(),
897            expected_type
898        ))),
899        Some(_) => Err(DmapError::InvalidScalar(format!(
900            "{name} is a vector field"
901        ))),
902        None => Ok(()),
903    }
904}
905
906/// Verify that `name` exists in `fields` and is of the correct [`Type`].
907///
908/// # Errors
909/// If `name` is not in `fields`.
910///
911/// If `name` is in `fields`, but is not a [`DmapField::Vector`] of `expected_type`.
912pub fn check_vector(
913    fields: &IndexMap<String, DmapField>,
914    name: &str,
915    expected_type: &Type,
916) -> Result<()> {
917    match fields.get(name) {
918        Some(DmapField::Vector(data)) if data.get_type() != *expected_type => {
919            Err(DmapError::InvalidVector(format!(
920                "{name} is of type {}, expected {}",
921                data.get_type(),
922                expected_type
923            )))
924        }
925        Some(DmapField::Scalar(_)) => Err(DmapError::InvalidVector(format!(
926            "{name} is a scalar field"
927        ))),
928        None => Err(DmapError::InvalidVector(format!("{name} not in record"))),
929        _ => Ok(()),
930    }
931}
932
933/// If `name` is in `fields`, verify that it is of the correct [`Type`].
934///
935/// # Errors
936/// If `name` is in `fields`, but is not a [`DmapField::Vector`] of `expected_type`.
937pub fn check_vector_opt(
938    fields: &IndexMap<String, DmapField>,
939    name: &str,
940    expected_type: &Type,
941) -> Result<()> {
942    match fields.get(name) {
943        Some(DmapField::Vector(data)) if data.get_type() != *expected_type => {
944            Err(DmapError::InvalidVector(format!(
945                "{name} is of type {}, expected {}",
946                data.get_type(),
947                expected_type
948            )))
949        }
950        Some(DmapField::Scalar(_)) => Err(DmapError::InvalidVector(format!(
951            "{name} is a scalar field"
952        ))),
953        _ => Ok(()),
954    }
955}
956
957#[cfg(test)]
958mod tests {
959    use super::*;
960    use numpy::ndarray::array;
961
962    #[test]
963    fn dmaptype() -> Result<()> {
964        assert_eq!(i8::size(), 1);
965        assert_eq!(u8::size(), 1);
966        assert_eq!(i16::size(), 2);
967        assert_eq!(u16::size(), 2);
968        assert_eq!(i32::size(), 4);
969        assert_eq!(u32::size(), 4);
970        assert_eq!(f32::size(), 4);
971        assert_eq!(i64::size(), 8);
972        assert_eq!(u64::size(), 8);
973        assert_eq!(f64::size(), 8);
974
975        assert_eq!(i8::dmap_type(), Type::Char);
976        assert_eq!(u8::dmap_type(), Type::Uchar);
977        assert_eq!(i16::dmap_type(), Type::Short);
978        assert_eq!(u16::dmap_type(), Type::Ushort);
979        assert_eq!(i32::dmap_type(), Type::Int);
980        assert_eq!(u32::dmap_type(), Type::Uint);
981        assert_eq!(f32::dmap_type(), Type::Float);
982        assert_eq!(i64::dmap_type(), Type::Long);
983        assert_eq!(u64::dmap_type(), Type::Ulong);
984        assert_eq!(f64::dmap_type(), Type::Double);
985
986        assert_eq!(vec![1], DmapType::as_bytes(&i8::from_bytes(&[1])?));
987        assert_eq!(vec![1], DmapType::as_bytes(&u8::from_bytes(&[1])?));
988        assert_eq!(vec![1, 0], DmapType::as_bytes(&i16::from_bytes(&[1, 0])?));
989        assert_eq!(vec![1, 0], DmapType::as_bytes(&u16::from_bytes(&[1, 0])?));
990        assert_eq!(
991            vec![1, 0, 0, 0],
992            DmapType::as_bytes(&i32::from_bytes(&[1, 0, 0, 0])?)
993        );
994        assert_eq!(
995            vec![1, 2, 3, 4],
996            DmapType::as_bytes(&u32::from_bytes(&[1, 2, 3, 4])?)
997        );
998        assert_eq!(
999            vec![1, 0, 0, 0],
1000            DmapType::as_bytes(&f32::from_bytes(&[1, 0, 0, 0])?)
1001        );
1002        assert_eq!(
1003            vec![1, 2, 3, 4, 5, 6, 7, 8],
1004            DmapType::as_bytes(&u64::from_bytes(&[1, 2, 3, 4, 5, 6, 7, 8])?)
1005        );
1006        assert_eq!(
1007            vec![1, 0, 0, 0, 1, 2, 3, 4],
1008            DmapType::as_bytes(&i64::from_bytes(&[1, 0, 0, 0, 1, 2, 3, 4])?)
1009        );
1010        assert_eq!(
1011            vec![1, 2, 3, 4, 4, 32, 2, 1],
1012            DmapType::as_bytes(&f64::from_bytes(&[1, 2, 3, 4, 4, 32, 2, 1])?)
1013        );
1014        Ok(())
1015    }
1016
1017    #[test]
1018    fn types() -> Result<()> {
1019        assert_eq!(Type::from_key(1)?, Type::Char);
1020        assert_eq!(Type::from_key(2)?, Type::Short);
1021        assert_eq!(Type::from_key(3)?, Type::Int);
1022        assert_eq!(Type::from_key(10)?, Type::Long);
1023        assert_eq!(Type::from_key(16)?, Type::Uchar);
1024        assert_eq!(Type::from_key(17)?, Type::Ushort);
1025        assert_eq!(Type::from_key(18)?, Type::Uint);
1026        assert_eq!(Type::from_key(19)?, Type::Ulong);
1027        assert_eq!(Type::from_key(4)?, Type::Float);
1028        assert_eq!(Type::from_key(8)?, Type::Double);
1029        assert_eq!(Type::from_key(9)?, Type::String);
1030        assert!(Type::from_key(-1).is_err());
1031        assert!(Type::from_key(15).is_err());
1032        assert!(Type::from_key(0).is_err());
1033
1034        assert_eq!(Type::Char.key(), 1);
1035        assert_eq!(Type::Short.key(), 2);
1036        assert_eq!(Type::Int.key(), 3);
1037        assert_eq!(Type::Long.key(), 10);
1038        assert_eq!(Type::Uchar.key(), 16);
1039        assert_eq!(Type::Ushort.key(), 17);
1040        assert_eq!(Type::Uint.key(), 18);
1041        assert_eq!(Type::Ulong.key(), 19);
1042        assert_eq!(Type::Float.key(), 4);
1043        assert_eq!(Type::Double.key(), 8);
1044        assert_eq!(Type::String.key(), 9);
1045
1046        assert_eq!(Type::Char.size(), 1);
1047        assert_eq!(Type::Short.size(), 2);
1048        assert_eq!(Type::Int.size(), 4);
1049        assert_eq!(Type::Long.size(), 8);
1050        assert_eq!(Type::Uchar.size(), 1);
1051        assert_eq!(Type::Ushort.size(), 2);
1052        assert_eq!(Type::Uint.size(), 4);
1053        assert_eq!(Type::Ulong.size(), 8);
1054        assert_eq!(Type::Float.size(), 4);
1055        assert_eq!(Type::Double.size(), 8);
1056        assert_eq!(Type::String.size(), 0);
1057
1058        Ok(())
1059    }
1060
1061    #[test]
1062    fn dmapscalar() -> Result<()> {
1063        assert_eq!(DmapScalar::Char(0).get_type(), Type::Char);
1064        assert_eq!(DmapScalar::Short(0).get_type(), Type::Short);
1065        assert_eq!(DmapScalar::Int(0).get_type(), Type::Int);
1066        assert_eq!(DmapScalar::Long(0).get_type(), Type::Long);
1067        assert_eq!(DmapScalar::Uchar(0).get_type(), Type::Uchar);
1068        assert_eq!(DmapScalar::Ushort(0).get_type(), Type::Ushort);
1069        assert_eq!(DmapScalar::Uint(0).get_type(), Type::Uint);
1070        assert_eq!(DmapScalar::Ulong(0).get_type(), Type::Ulong);
1071        assert_eq!(DmapScalar::Float(0.0).get_type(), Type::Float);
1072        assert_eq!(DmapScalar::Double(0.0).get_type(), Type::Double);
1073        assert_eq!(
1074            DmapScalar::String("test".to_string()).get_type(),
1075            Type::String
1076        );
1077
1078        let x = DmapScalar::Char(-1);
1079        assert_eq!(x.cast_as(&Type::Short)?, DmapScalar::Short(-1));
1080        assert!(x.cast_as(&Type::Float).is_ok());
1081        assert!(x.cast_as(&Type::Uchar).is_err());
1082        assert!(x.cast_as(&Type::String).is_err());
1083
1084        let x = DmapScalar::Uchar(255);
1085        assert_eq!(x.cast_as(&Type::Short)?, DmapScalar::Short(255));
1086        assert!(x.cast_as(&Type::Char).is_err());
1087        assert!(x.cast_as(&Type::Float).is_ok());
1088        assert!(x.cast_as(&Type::Uchar).is_ok());
1089        assert!(x.cast_as(&Type::String).is_err());
1090
1091        let x = DmapScalar::Short(256);
1092        assert_eq!(x.cast_as(&Type::Short)?, DmapScalar::Short(256));
1093        assert!(x.cast_as(&Type::Char).is_err());
1094        assert_eq!(x.cast_as(&Type::Ushort)?, DmapScalar::Ushort(256));
1095        assert!(x.cast_as(&Type::Uchar).is_err());
1096        assert!(x.cast_as(&Type::Float).is_ok());
1097        assert!(x.cast_as(&Type::String).is_err());
1098
1099        let x = DmapScalar::Float(1.0);
1100        assert!(x.cast_as(&Type::Double).is_ok());
1101        assert!(x.cast_as(&Type::Char).is_err());
1102        assert!(x.cast_as(&Type::Uchar).is_err());
1103        assert!(x.cast_as(&Type::Float).is_ok());
1104        assert!(x.cast_as(&Type::String).is_err());
1105
1106        let x = DmapScalar::String("test".to_string());
1107        assert!(x.cast_as(&Type::Char).is_err());
1108        assert!(x.cast_as(&Type::Short).is_err());
1109        assert!(x.cast_as(&Type::Int).is_err());
1110        assert!(x.cast_as(&Type::Long).is_err());
1111        assert!(x.cast_as(&Type::Uchar).is_err());
1112        assert!(x.cast_as(&Type::Ushort).is_err());
1113        assert!(x.cast_as(&Type::Uint).is_err());
1114        assert!(x.cast_as(&Type::Ulong).is_err());
1115        assert!(x.cast_as(&Type::Float).is_err());
1116        assert!(x.cast_as(&Type::Double).is_err());
1117
1118        assert_eq!(
1119            DmapScalar::Char(8).as_bytes(),
1120            vec![Type::Char.key() as u8, 8]
1121        );
1122        assert_eq!(
1123            DmapScalar::Short(256).as_bytes(),
1124            vec![Type::Short.key() as u8, 0, 1]
1125        );
1126        assert_eq!(
1127            DmapScalar::Int(256).as_bytes(),
1128            vec![Type::Int.key() as u8, 0, 1, 0, 0]
1129        );
1130        assert_eq!(
1131            DmapScalar::Long(512).as_bytes(),
1132            vec![Type::Long.key() as u8, 0, 2, 0, 0, 0, 0, 0, 0]
1133        );
1134        assert_eq!(
1135            DmapScalar::Uchar(8).as_bytes(),
1136            vec![Type::Uchar.key() as u8, 8]
1137        );
1138        assert_eq!(
1139            DmapScalar::Ushort(256).as_bytes(),
1140            vec![Type::Ushort.key() as u8, 0, 1]
1141        );
1142        assert_eq!(
1143            DmapScalar::Uint(256).as_bytes(),
1144            vec![Type::Uint.key() as u8, 0, 1, 0, 0]
1145        );
1146        assert_eq!(
1147            DmapScalar::Ulong(512).as_bytes(),
1148            vec![Type::Ulong.key() as u8, 0, 2, 0, 0, 0, 0, 0, 0]
1149        );
1150        assert_eq!(
1151            DmapScalar::Float(0.0).as_bytes(),
1152            vec![Type::Float.key() as u8, 0, 0, 0, 0]
1153        );
1154        assert_eq!(
1155            DmapScalar::Double(0.0).as_bytes(),
1156            vec![Type::Double.key() as u8, 0, 0, 0, 0, 0, 0, 0, 0]
1157        );
1158        assert_eq!(
1159            DmapScalar::String("test".to_string()).as_bytes(),
1160            vec![Type::String.key() as u8, 116, 101, 115, 116, 0]
1161        );
1162
1163        Ok(())
1164    }
1165
1166    #[test]
1167    fn dmapvec() -> Result<()> {
1168        let arr = DmapVec::Char(array![0, 1, 2, 3, 4].into_dyn());
1169        assert_eq!(arr.get_type(), Type::Char);
1170        let arr = DmapVec::Uchar(array![0, 1, 2, 3, 4].into_dyn());
1171        assert_eq!(arr.get_type(), Type::Uchar);
1172        let arr = DmapVec::Short(array![0, 1, 2, 3, 4].into_dyn());
1173        assert_eq!(arr.get_type(), Type::Short);
1174        let arr = DmapVec::Ushort(array![0, 1, 2, 3, 4].into_dyn());
1175        assert_eq!(arr.get_type(), Type::Ushort);
1176        let arr = DmapVec::Int(array![0, 1, 2, 3, 4].into_dyn());
1177        assert_eq!(arr.get_type(), Type::Int);
1178        let arr = DmapVec::Uint(array![[0, 1, 2], [3, 4, 5]].into_dyn());
1179        assert_eq!(arr.get_type(), Type::Uint);
1180        let arr = DmapVec::Long(array![0, 1, 2, 3, 4].into_dyn());
1181        assert_eq!(arr.get_type(), Type::Long);
1182        let arr = DmapVec::Ulong(array![0, 1, 2, 3, 4].into_dyn());
1183        assert_eq!(arr.get_type(), Type::Ulong);
1184        let arr = DmapVec::Float(array![0.0, 1.0, 2.0, 3.0, 4.0].into_dyn());
1185        assert_eq!(arr.get_type(), Type::Float);
1186        let arr = DmapVec::Double(array![0.0, 1.0, 2.0, 3.0, 4.0].into_dyn());
1187        assert_eq!(arr.get_type(), Type::Double);
1188
1189        Ok(())
1190    }
1191
1192    #[test]
1193    fn check_fields_in_indexmap() -> Result<()> {
1194        use numpy::ndarray::array;
1195
1196        let mut rec = IndexMap::<String, DmapField>::new();
1197        let res = check_scalar(&rec, "test", &Type::Char);
1198        assert!(res.is_err());
1199        let res = check_scalar_opt(&rec, "test", &Type::Char);
1200        assert!(res.is_ok());
1201        let res = check_vector(&rec, "test", &Type::Char);
1202        assert!(res.is_err());
1203        let res = check_vector_opt(&rec, "test", &Type::Char);
1204        assert!(res.is_ok());
1205
1206        let res = rec.insert("test".to_string(), DmapField::from(1i32));
1207        assert!(res.is_none());
1208        let res = check_scalar(&rec, "test", &Type::Int);
1209        assert!(res.is_ok());
1210        let res = check_scalar_opt(&rec, "test", &Type::Char);
1211        assert!(res.is_err());
1212        let res = check_scalar_opt(&rec, "test", &Type::Int);
1213        assert!(res.is_ok());
1214        let res = check_vector(&rec, "test", &Type::Char);
1215        assert!(res.is_err());
1216        let res = check_vector_opt(&rec, "test", &Type::Char);
1217        assert!(res.is_err());
1218
1219        let test_vec = array![1.0f32, 2.0f32].into_dyn();
1220        let res = rec.insert("test_vec".to_string(), test_vec.into());
1221        assert!(res.is_none());
1222        let res = check_scalar(&rec, "test_vec", &Type::Float);
1223        assert!(res.is_err());
1224        let res = check_scalar_opt(&rec, "test_vec", &Type::Float);
1225        assert!(res.is_err());
1226        let res = check_vector(&rec, "test_vec", &Type::Float);
1227        assert!(res.is_ok());
1228        let res = check_vector(&rec, "test_vec", &Type::Double);
1229        assert!(res.is_err());
1230        let res = check_vector_opt(&rec, "test_vec", &Type::Float);
1231        assert!(res.is_ok());
1232        let res = check_vector_opt(&rec, "test_vec", &Type::Int);
1233        assert!(res.is_err());
1234
1235        Ok(())
1236    }
1237}