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}