eva_common/
dobj.rs

1use crate::{EResult, Error, OID, value::Value};
2use std::{
3    borrow::Borrow,
4    collections::{BTreeMap, BTreeSet},
5    fmt,
6    io::Cursor,
7    ops::Deref,
8};
9
10use binrw::prelude::*;
11
12use serde::{Deserialize, Deserializer, Serialize};
13
14impl Borrow<str> for Name {
15    fn borrow(&self) -> &str {
16        &self.0
17    }
18}
19
20#[derive(Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Debug)]
21#[serde(rename_all = "lowercase")]
22pub enum Endianess {
23    Big,
24    #[default]
25    Little,
26}
27
28impl From<Endianess> for binrw::Endian {
29    #[inline]
30    fn from(e: Endianess) -> binrw::Endian {
31        match e {
32            Endianess::Big => binrw::Endian::Big,
33            Endianess::Little => binrw::Endian::Little,
34        }
35    }
36}
37
38#[derive(Deserialize, Serialize, Debug, Default, Clone)]
39#[serde(deny_unknown_fields)]
40pub struct ObjectMap {
41    #[serde(rename = "data_objects")]
42    pub objects: BTreeMap<Name, DataObject>,
43}
44
45fn parse_value_by_kind(
46    buf: &mut Cursor<&[u8]>,
47    kind: &Kind,
48    map: &BTreeMap<Name, DataObject>,
49    endianess: Endianess,
50) -> EResult<Value> {
51    let value = match kind {
52        Kind::Bool => {
53            let v = u8::read(buf).map_err(Error::invalid_data)?;
54            Value::Bool(v > 0)
55        }
56        Kind::U8 => {
57            let v = u8::read(buf).map_err(Error::invalid_data)?;
58            Value::U8(v)
59        }
60        Kind::I8 => {
61            let v = i8::read(buf).map_err(Error::invalid_data)?;
62            Value::I8(v)
63        }
64        Kind::U16 => {
65            let v = u16::read_options(buf, endianess.into(), ()).map_err(Error::invalid_data)?;
66            Value::U16(v)
67        }
68        Kind::I16 => {
69            let v = i16::read_options(buf, endianess.into(), ()).map_err(Error::invalid_data)?;
70            Value::I16(v)
71        }
72        Kind::U32 => {
73            let v = u32::read_options(buf, endianess.into(), ()).map_err(Error::invalid_data)?;
74            Value::U32(v)
75        }
76        Kind::I32 => {
77            let v = i32::read_options(buf, endianess.into(), ()).map_err(Error::invalid_data)?;
78            Value::I32(v)
79        }
80        Kind::U64 => {
81            let v = u64::read_options(buf, endianess.into(), ()).map_err(Error::invalid_data)?;
82            Value::U64(v)
83        }
84        Kind::I64 => {
85            let v = i64::read_options(buf, endianess.into(), ()).map_err(Error::invalid_data)?;
86            Value::I64(v)
87        }
88        Kind::F32 => {
89            let v = f32::read_options(buf, endianess.into(), ()).map_err(Error::invalid_data)?;
90            Value::F32(v)
91        }
92        Kind::F64 => {
93            let v = f64::read_options(buf, endianess.into(), ()).map_err(Error::invalid_data)?;
94            Value::F64(v)
95        }
96        Kind::Array(k, n) => {
97            let mut values = Vec::with_capacity(*k);
98            for _ in 0..*k {
99                let value = parse_value_by_kind(buf, n, map, endianess)?;
100                values.push(value);
101            }
102            Value::Seq(values)
103        }
104        Kind::DataObject(s) => {
105            if let Some(object) = map.get(s) {
106                let mut values = BTreeMap::new();
107                for field in &object.fields {
108                    let kind = &field.kind;
109                    let value = parse_value_by_kind(buf, kind, map, endianess)?;
110                    values.insert(Value::String(field.name.to_string()), value);
111                }
112                Value::Map(values)
113            } else {
114                return Err(Error::not_found(s));
115            }
116        }
117    };
118    Ok(value)
119}
120
121impl ObjectMap {
122    pub fn new() -> Self {
123        Self::default()
124    }
125    pub fn merge(&mut self, other: Self) {
126        for (k, v) in other.objects {
127            self.objects.insert(k, v);
128        }
129    }
130    pub fn extend(&mut self, objects: Vec<DataObject>) {
131        for object in objects {
132            self.objects.insert(object.name.clone(), object);
133        }
134    }
135    pub fn mapped_oids(&self, name: &Name) -> BTreeSet<OID> {
136        let mut oids = BTreeSet::new();
137        self.mapped_oids_recursive(name, &mut oids);
138        oids
139    }
140    pub fn mapped_oids_recursive(&self, name: &Name, oids: &mut BTreeSet<OID>) {
141        let Some(object) = self.objects.get(name) else {
142            return;
143        };
144        for field in &object.fields {
145            if let Some(ref oid) = field.oid {
146                oids.insert(oid.clone());
147            }
148            match field.kind {
149                Kind::Array(_, ref k) => {
150                    if let Kind::DataObject(s) = k.as_ref() {
151                        self.mapped_oids_recursive(s, oids);
152                    }
153                }
154                Kind::DataObject(ref s) => {
155                    self.mapped_oids_recursive(s, oids);
156                }
157                _ => {}
158            }
159        }
160    }
161    pub fn remove_bulk<B: Borrow<str> + Ord>(&mut self, names: &[B]) {
162        for name in names {
163            self.objects.remove(name.borrow());
164        }
165    }
166    pub fn validate(&self) -> EResult<()> {
167        let mut invalid_objects: BTreeSet<&Name> = <_>::default();
168        for v in self.objects.values() {
169            for field in &v.fields {
170                self.validate_kind(&field.kind, &mut invalid_objects);
171            }
172        }
173        if !invalid_objects.is_empty() {
174            let mut err = String::new();
175            for (s, i) in invalid_objects.into_iter().enumerate() {
176                if s > 0 {
177                    err.push_str(", ");
178                }
179                err.push_str(i);
180            }
181            return Err(Error::invalid_data(format!("objects not found: {}", err)));
182        }
183        Ok(())
184    }
185    pub fn parse_values(
186        &self,
187        object: &Name,
188        buf: &[u8],
189        endianess: Endianess,
190    ) -> EResult<BTreeMap<OID, Value>> {
191        let mut cursor = Cursor::new(buf);
192        let mut values = BTreeMap::new();
193        self.parse_values_recursive(&mut cursor, object, &self.objects, &mut values, endianess)?;
194        Ok(values)
195    }
196    fn parse_values_recursive(
197        &self,
198        buf: &mut Cursor<&[u8]>,
199        object: &Name,
200        map: &BTreeMap<Name, DataObject>,
201        values: &mut BTreeMap<OID, Value>,
202        endianess: Endianess,
203    ) -> EResult<()> {
204        let Some(object) = map.get(object) else {
205            return Err(Error::not_found(object));
206        };
207        for field in &object.fields {
208            let kind = &field.kind;
209            if let Some(ref oid) = field.oid {
210                let pos = buf.position();
211                let value = parse_value_by_kind(buf, kind, map, endianess)?;
212                values.insert(oid.clone(), value);
213                buf.set_position(pos);
214            }
215            match kind {
216                Kind::Array(n, k) => {
217                    if let Kind::DataObject(s) = k.as_ref() {
218                        for _ in 0..*n {
219                            self.parse_values_recursive(buf, s, map, values, endianess)?;
220                        }
221                    } else {
222                        buf.set_position(buf.position() + u64::try_from(self.kind_size(kind)?)?);
223                    }
224                }
225                Kind::DataObject(s) => {
226                    self.parse_values_recursive(buf, s, map, values, endianess)?;
227                }
228                _ => {
229                    buf.set_position(buf.position() + u64::try_from(self.kind_size(kind)?)?);
230                }
231            }
232        }
233        Ok(())
234    }
235    pub fn size_of(&self, name: &Name) -> EResult<usize> {
236        let mut size = 0;
237        for field in &self
238            .objects
239            .get(name)
240            .ok_or_else(|| Error::invalid_data(format!("object not found: {}", name)))?
241            .fields
242        {
243            size += self.kind_size(&field.kind)?;
244        }
245        Ok(size)
246    }
247    fn kind_size(&self, kind: &Kind) -> EResult<usize> {
248        match kind {
249            Kind::Bool | Kind::I8 | Kind::U8 => Ok(1),
250            Kind::I16 | Kind::U16 => Ok(2),
251            Kind::I32 | Kind::U32 | Kind::F32 => Ok(4),
252            Kind::I64 | Kind::U64 | Kind::F64 => Ok(8),
253            Kind::Array(n, k) => {
254                let k_size = self.kind_size(k)?;
255                Ok(n * k_size)
256            }
257            Kind::DataObject(s) => self.size_of(s),
258        }
259    }
260    fn validate_kind<'a>(&self, kind: &'a Kind, invalid_objects: &mut BTreeSet<&'a Name>) {
261        match kind {
262            Kind::Array(_, k) => self.validate_kind(k, invalid_objects),
263            Kind::DataObject(s) => {
264                if !self.objects.contains_key(s) {
265                    invalid_objects.insert(s);
266                }
267            }
268            _ => {}
269        }
270    }
271}
272
273#[derive(Deserialize, Serialize, Debug, Clone)]
274#[serde(deny_unknown_fields)]
275pub struct DataObject {
276    #[serde(alias = "i")]
277    pub name: Name,
278    #[serde(default, alias = "f")]
279    pub fields: Vec<Field>,
280}
281
282#[derive(Deserialize, Serialize, Debug, Clone)]
283pub struct Field {
284    #[serde(alias = "i")]
285    pub name: Name,
286    #[serde(rename = "type", alias = "t")]
287    pub kind: Kind,
288    #[serde(skip_serializing_if = "Option::is_none")]
289    pub oid: Option<OID>,
290}
291
292#[derive(Debug, Ord, PartialEq, Eq, PartialOrd, Clone)]
293pub struct Name(String);
294
295impl Deref for Name {
296    type Target = str;
297
298    fn deref(&self) -> &Self::Target {
299        &self.0
300    }
301}
302
303fn is_valid_name(s: &str) -> bool {
304    s.chars()
305        .all(|c| c.is_alphanumeric() || c.is_numeric() || c == '_')
306}
307
308impl TryFrom<String> for Name {
309    type Error = Error;
310
311    fn try_from(s: String) -> Result<Self, Self::Error> {
312        if is_valid_name(&s) {
313            Ok(Name(s))
314        } else {
315            Err(Error::invalid_data(format!("invalid name: {}", s)))
316        }
317    }
318}
319
320impl TryFrom<&str> for Name {
321    type Error = Error;
322
323    fn try_from(s: &str) -> Result<Self, Self::Error> {
324        if is_valid_name(s) {
325            Ok(Name(s.to_owned()))
326        } else {
327            Err(Error::invalid_data(format!("invalid name: {}", s)))
328        }
329    }
330}
331
332impl From<Name> for String {
333    fn from(n: Name) -> String {
334        n.0
335    }
336}
337
338impl fmt::Display for Name {
339    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340        write!(f, "{}", self.0)
341    }
342}
343
344impl<'de> Deserialize<'de> for Name {
345    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
346    where
347        D: Deserializer<'de>,
348    {
349        let s = String::deserialize(deserializer)?;
350        Name::try_from(s).map_err(serde::de::Error::custom)
351    }
352}
353
354impl Serialize for Name {
355    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
356    where
357        S: serde::Serializer,
358    {
359        self.0.serialize(serializer)
360    }
361}
362
363#[derive(Clone, Eq, PartialEq, Debug)]
364pub enum Kind {
365    Bool,
366    I8,
367    I16,
368    I32,
369    I64,
370    U8,
371    U16,
372    U32,
373    U64,
374    F32,
375    F64,
376    Array(usize, Box<Kind>),
377    DataObject(Name),
378}
379
380impl<'de> Deserialize<'de> for Kind {
381    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
382    where
383        D: Deserializer<'de>,
384    {
385        let s = String::deserialize(deserializer)?;
386        let mut sp = s.split(',');
387        let kind = sp.next().unwrap();
388        let maybe_array: Option<usize> = if let Some(n) = sp.next() {
389            let n = n.parse().map_err(serde::de::Error::custom)?;
390            Some(n)
391        } else {
392            None
393        };
394        if sp.next().is_some() {
395            return Err(serde::de::Error::custom("too many commas in type"));
396        }
397        let data_kind = match kind {
398            "bool" | "BOOL" | "BOOLEAN" => {
399                maybe_array.map_or_else(|| Kind::Bool, |n| Kind::Array(n, Box::new(Kind::Bool)))
400            }
401            "i8" | "SINT" => {
402                maybe_array.map_or_else(|| Kind::I8, |n| Kind::Array(n, Box::new(Kind::I8)))
403            }
404            "i16" | "INT" => {
405                maybe_array.map_or_else(|| Kind::I16, |n| Kind::Array(n, Box::new(Kind::I16)))
406            }
407            "i32" | "DINT" => {
408                maybe_array.map_or_else(|| Kind::I32, |n| Kind::Array(n, Box::new(Kind::I32)))
409            }
410            "i64" | "LINT" => {
411                maybe_array.map_or_else(|| Kind::I64, |n| Kind::Array(n, Box::new(Kind::I64)))
412            }
413            "u8" | "USINT" => {
414                maybe_array.map_or_else(|| Kind::U8, |n| Kind::Array(n, Box::new(Kind::U8)))
415            }
416            "u16" | "UINT" => {
417                maybe_array.map_or_else(|| Kind::U16, |n| Kind::Array(n, Box::new(Kind::U16)))
418            }
419            "u32" | "UDINT" => {
420                maybe_array.map_or_else(|| Kind::U32, |n| Kind::Array(n, Box::new(Kind::U32)))
421            }
422            "u64" | "ULINT" => {
423                maybe_array.map_or_else(|| Kind::U64, |n| Kind::Array(n, Box::new(Kind::U64)))
424            }
425            "f32" | "REAL" => {
426                maybe_array.map_or_else(|| Kind::F32, |n| Kind::Array(n, Box::new(Kind::F32)))
427            }
428            "f64" | "LREAL" => {
429                maybe_array.map_or_else(|| Kind::F64, |n| Kind::Array(n, Box::new(Kind::F64)))
430            }
431            v => {
432                let name: Name = Name::try_from(v).map_err(serde::de::Error::custom)?;
433                if let Some(n) = maybe_array {
434                    Kind::Array(n, Box::new(Kind::DataObject(name)))
435                } else {
436                    Kind::DataObject(name)
437                }
438            }
439        };
440        Ok(data_kind)
441    }
442}
443
444impl fmt::Display for Kind {
445    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446        match self {
447            Kind::Bool => write!(f, "bool"),
448            Kind::I8 => write!(f, "i8"),
449            Kind::I16 => write!(f, "i16"),
450            Kind::I32 => write!(f, "i32"),
451            Kind::I64 => write!(f, "i64"),
452            Kind::U8 => write!(f, "u8"),
453            Kind::U16 => write!(f, "u16"),
454            Kind::U32 => write!(f, "u32"),
455            Kind::U64 => write!(f, "u64"),
456            Kind::F32 => write!(f, "f32"),
457            Kind::F64 => write!(f, "f64"),
458            Kind::Array(n, k) => write!(f, "{},{}", k, n),
459            Kind::DataObject(s) => write!(f, "{}", s),
460        }
461    }
462}
463
464impl Serialize for Kind {
465    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
466    where
467        S: serde::Serializer,
468    {
469        serializer.serialize_str(&self.to_string())
470    }
471}