dmap/formats/
dmap.rs

1//! The generic [DMAP file format](https://radar-software-toolkit-rst.readthedocs.io/en/latest/references/general/dmap_data/).
2//!
3//! Defines [`DmapRecord`] which implements [`Record`], which can be used
4//! for reading/writing DMAP files without checking that certain fields are or
5//! are not present, or have a given type.
6
7use crate::error::DmapError;
8use crate::record::Record;
9use crate::types::{DmapField, DmapType};
10use indexmap::IndexMap;
11
12#[derive(Debug, PartialEq, Clone)]
13pub struct DmapRecord {
14    pub data: IndexMap<String, DmapField>,
15}
16
17impl Record<'_> for DmapRecord {
18    fn inner(self) -> IndexMap<String, DmapField> {
19        self.data
20    }
21    fn get(&self, key: &str) -> Option<&DmapField> {
22        self.data.get(key)
23    }
24    fn keys(&self) -> Vec<&String> {
25        self.data.keys().collect()
26    }
27    fn new(fields: &mut IndexMap<String, DmapField>) -> Result<DmapRecord, DmapError> {
28        Ok(DmapRecord {
29            data: fields.to_owned(),
30        })
31    }
32    fn is_metadata_field(_name: &str) -> bool {
33        true
34    }
35    fn to_bytes(&self) -> Result<Vec<u8>, DmapError> {
36        let mut data_bytes: Vec<u8> = vec![];
37        let mut num_scalars: i32 = 0;
38        let mut num_vectors: i32 = 0;
39
40        // Do a first pass, to get all the scalar fields
41        for (name, val) in self.data.iter() {
42            if let x @ DmapField::Scalar(_) = val {
43                data_bytes.extend(name.as_bytes());
44                data_bytes.extend([0]); // null-terminate string
45                data_bytes.append(&mut x.as_bytes());
46                num_scalars += 1;
47            }
48        }
49        // Do a second pass to convert all the vector fields
50        for (name, val) in self.data.iter() {
51            if let x @ DmapField::Vector(_) = val {
52                data_bytes.extend(name.as_bytes());
53                data_bytes.extend([0]); // null-terminate string
54                data_bytes.append(&mut x.as_bytes());
55                num_vectors += 1;
56            }
57        }
58        let mut bytes: Vec<u8> = vec![];
59        bytes.extend((65537_i32).as_bytes()); // No idea why this is what it is, copied from backscatter
60        bytes.extend((data_bytes.len() as i32 + 16).as_bytes()); // +16 for code, length, num_scalars, num_vectors
61        bytes.extend(num_scalars.as_bytes());
62        bytes.extend(num_vectors.as_bytes());
63        bytes.append(&mut data_bytes); // consumes data_bytes
64        Ok(bytes)
65    }
66}
67
68impl TryFrom<&mut IndexMap<String, DmapField>> for DmapRecord {
69    type Error = DmapError;
70
71    fn try_from(value: &mut IndexMap<String, DmapField>) -> Result<Self, Self::Error> {
72        DmapRecord::new(value)
73    }
74}
75
76impl TryFrom<IndexMap<String, DmapField>> for DmapRecord {
77    type Error = DmapError;
78
79    fn try_from(mut value: IndexMap<String, DmapField>) -> Result<Self, Self::Error> {
80        DmapRecord::new(&mut value)
81    }
82}