1use serde::{Deserialize, Serialize};
14use time::OffsetDateTime;
15
16use crate::*;
17
18#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
19#[serde(try_from = "LocutorSerial", into = "LocutorSerial")]
20pub struct Locutor {
21 pub entity: Entity,
22 pub outlet: Entity,
23 pub auxiliary: Entity,
24 pub ancillary: Entity,
25 pub context: Context,
26 pub category: Category,
27 pub class: Class,
28 pub method: Method,
29 pub attribute: Attribute,
30 pub instance: i32,
31 pub offset: i32,
32 pub parameter: i64,
33 pub resultant: i64,
34 pub count: i64,
35 pub index: i64,
36 pub event: Event,
37 pub mode: Mode,
38 pub state: State,
39 pub condition: Condition,
40 pub precedence: u16,
41 pub time: OffsetDateTime,
42 pub timeout: i64,
43 pub aspect: Aspect,
44 pub template: Template,
45 pub scheme: Scheme,
46 pub name: String255,
47 pub label: String,
48 pub key: String255,
49 pub value: Value,
51 pub format: Format,
52 pub authority: Token,
53 pub authorization: Token,
54}
55
56impl Default for Locutor {
57 fn default() -> Self {
58 Locutor {
59 entity: Entity::NULL,
60 outlet: Entity::NULL,
61 auxiliary: Entity::NULL,
62 ancillary: Entity::NULL,
63 context: Context::Null,
64 category: Category::Null,
65 class: Class::Null,
66 method: Method::Null,
67 attribute: Attribute::Null,
68 instance: 0,
69 offset: 0,
70 parameter: 0,
71 resultant: 0,
72 count: 0,
73 index: 0,
74 event: Event::Null,
75 mode: Mode::Null,
76 state: State::Null,
77 condition: Condition::Null,
78 precedence: 0,
79 time: OffsetDateTime::UNIX_EPOCH,
80 timeout: 0,
81 aspect: Aspect::Null,
82 template: Template::Null,
83 scheme: Scheme::Null,
84 name: String255::NULL,
85 label: String::new(),
86 key: String255::NULL,
87 value: Value::NULL,
88 format: Format::Null,
89 authority: Token::NULL,
90 authorization: Token::NULL,
91 }
92 }
93}
94
95impl Locutor {
96 #[rustfmt::skip]
97 pub fn merge(&self, other: &Self) -> Self {
99 Locutor {
100 entity: if self.entity.is_null() { other.entity } else { self.entity },
101 outlet: if self.outlet.is_null() { other.outlet } else { self.outlet },
102 auxiliary: if self.auxiliary.is_null() { other.auxiliary } else { self.auxiliary },
103 ancillary: if self.ancillary.is_null() { other.ancillary } else { self.ancillary },
104 context: if self.context.is_null() { other.context } else { self.context },
105 category: if self.category.is_null() { other.category } else { self.category },
106 class: if self.class.is_null() { other.class } else { self.class },
107 method: if self.method.is_null() { other.method } else { self.method },
108 attribute: if self.attribute.is_null() { other.attribute } else { self.attribute },
109 instance: if self.instance == 0 { other.instance } else { self.instance },
110 offset: if self.offset == 0 { other.offset } else { self.offset },
111 parameter: if self.parameter == 0 { other.parameter } else { self.parameter },
112 resultant: if self.resultant == 0 { other.resultant } else { self.resultant },
113 count: if self.count == 0 { other.count } else { self.count },
114 index: if self.index == 0 { other.index } else { self.index },
115 event: if self.event.is_null() { other.event } else { self.event },
116 mode: if self.mode.is_null() { other.mode } else { self.mode },
117 state: if self.state.is_null() { other.state } else { self.state },
118 condition: if self.condition.is_null() { other.condition } else { self.condition },
119 precedence: if self.precedence == 0 { other.precedence } else { self.precedence },
120 time: if self.time == OffsetDateTime::UNIX_EPOCH { other.time } else { self.time },
121 timeout: if self.timeout == 0 { other.timeout } else { self.timeout },
122 aspect: if self.aspect.is_null() { other.aspect } else { self.aspect },
123 template: if self.template.is_null() { other.template } else { self.template },
124 scheme: if self.scheme.is_null() { other.scheme } else { self.scheme },
125 name: if self.name.is_null() { other.name.clone() } else { self.name.clone() },
126 label: if self.label.is_empty() { other.label.clone() } else { self.label.clone() },
127 key: if self.key.is_null() { other.key.clone() } else { self.key.clone() },
128 value: if self.value.is_null() { other.value.clone() } else { self.value.clone() },
129 format: if self.format.is_null() { other.format } else { self.format },
130 authority: if self.authority.is_null() { other.authority } else { self.authority },
131 authorization: if self.authorization.is_null() { other.authorization } else { self.authorization },
132 }
133 }
134}
135
136#[derive(Debug, Serialize, Deserialize, PartialEq)]
141#[serde(default, rename_all = "UPPERCASE")]
142struct LocutorSerial {
143 #[serde(skip_serializing_if = "Entity::is_null")]
144 entity: Entity,
145 #[serde(skip_serializing_if = "Entity::is_null")]
146 outlet: Entity,
147 #[serde(skip_serializing_if = "Entity::is_null")]
148 auxiliary: Entity,
149 #[serde(skip_serializing_if = "Entity::is_null")]
150 ancillary: Entity,
151 #[serde(skip_serializing_if = "Context::is_null")]
152 context: Context,
153 #[serde(skip_serializing_if = "Category::is_null")]
154 category: Category,
155 #[serde(skip_serializing_if = "Class::is_null")]
156 class: Class,
157 #[serde(skip_serializing_if = "Method::is_null")]
158 method: Method,
159 #[serde(skip_serializing_if = "Attribute::is_null")]
160 attribute: Attribute,
161 #[serde(skip_serializing_if = "i32_is_zero")]
162 instance: i32,
163 #[serde(skip_serializing_if = "i32_is_zero")]
164 offset: i32,
165 #[serde(skip_serializing_if = "i64_is_zero")]
166 parameter: i64,
167 #[serde(skip_serializing_if = "i64_is_zero")]
168 resultant: i64,
169 #[serde(skip_serializing_if = "i64_is_zero")]
170 count: i64,
171 #[serde(skip_serializing_if = "i64_is_zero")]
172 index: i64,
173 #[serde(skip_serializing_if = "Event::is_null")]
174 event: Event,
175 #[serde(skip_serializing_if = "Mode::is_null")]
176 mode: Mode,
177 #[serde(skip_serializing_if = "State::is_null")]
178 state: State,
179 #[serde(skip_serializing_if = "Condition::is_null")]
180 condition: Condition,
181 #[serde(skip_serializing_if = "u16_is_zero", with = "locutor_precedence_serde")]
182 precedence: u16,
183 #[serde(skip_serializing_if = "time_serde::is_zero", with = "time_serde")]
184 time: OffsetDateTime,
185 #[serde(skip_serializing_if = "i64_is_zero")]
186 timeout: i64,
187 #[serde(skip_serializing_if = "Aspect::is_null")]
188 aspect: Aspect,
189 #[serde(skip_serializing_if = "Template::is_null")]
190 template: Template,
191 #[serde(skip_serializing_if = "Scheme::is_null")]
192 scheme: Scheme,
193 #[serde(skip_serializing_if = "String::is_empty")]
194 name: String255,
195 #[serde(skip_serializing_if = "String::is_empty")]
196 label: String,
197 #[serde(skip_serializing_if = "String::is_empty")]
198 key: String255,
199 #[serde(skip_serializing_if = "String::is_empty")]
200 value: String,
201 #[serde(skip_serializing_if = "Tag::is_null")]
202 value_tag: Tag,
203 #[serde(skip_serializing_if = "Format::is_null")]
204 format: Format,
205 #[serde(skip_serializing_if = "Token::is_null")]
206 authority: Token,
207 #[serde(skip_serializing_if = "Token::is_null")]
208 authorization: Token,
209}
210
211fn i32_is_zero(n: &i32) -> bool {
212 *n == 0
213}
214
215fn i64_is_zero(n: &i64) -> bool {
216 *n == 0
217}
218
219fn u16_is_zero(n: &u16) -> bool {
220 *n == 0
221}
222
223impl From<Locutor> for LocutorSerial {
224 fn from(locutor: Locutor) -> Self {
225 LocutorSerial {
226 entity: locutor.entity,
227 outlet: locutor.outlet,
228 auxiliary: locutor.auxiliary,
229 ancillary: locutor.ancillary,
230 context: locutor.context,
231 category: locutor.category,
232 class: locutor.class,
233 method: locutor.method,
234 attribute: locutor.attribute,
235 instance: locutor.instance,
236 offset: locutor.offset,
237 parameter: locutor.parameter,
238 resultant: locutor.resultant,
239 count: locutor.count,
240 index: locutor.index,
241 event: locutor.event,
242 mode: locutor.mode,
243 state: locutor.state,
244 condition: locutor.condition,
245 precedence: locutor.precedence,
246 time: locutor.time,
247 timeout: locutor.timeout,
248 aspect: locutor.aspect,
249 template: locutor.template,
250 scheme: locutor.scheme,
251 name: locutor.name,
252 label: locutor.label,
253 key: locutor.key,
254 value: locutor.value.get_bytes(),
255 value_tag: locutor.value.get_tag(),
256 format: locutor.format,
257 authority: locutor.authority,
258 authorization: locutor.authorization,
259 }
260 }
261}
262
263impl TryFrom<LocutorSerial> for Locutor {
264 type Error = ValueCreationError;
265
266 fn try_from(locutor: LocutorSerial) -> Result<Self, Self::Error> {
267 Ok(Locutor {
268 entity: locutor.entity,
269 outlet: locutor.outlet,
270 auxiliary: locutor.auxiliary,
271 ancillary: locutor.ancillary,
272 context: locutor.context,
273 category: locutor.category,
274 class: locutor.class,
275 method: locutor.method,
276 attribute: locutor.attribute,
277 instance: locutor.instance,
278 offset: locutor.offset,
279 parameter: locutor.parameter,
280 resultant: locutor.resultant,
281 count: locutor.count,
282 index: locutor.index,
283 event: locutor.event,
284 mode: locutor.mode,
285 state: locutor.state,
286 condition: locutor.condition,
287 precedence: locutor.precedence,
288 time: locutor.time,
289 timeout: locutor.timeout,
290 aspect: locutor.aspect,
291 template: locutor.template,
292 scheme: locutor.scheme,
293 name: locutor.name,
294 label: locutor.label,
295 key: locutor.key,
296 value: Value::new(locutor.value_tag, locutor.value)?,
297 format: locutor.format,
298 authority: locutor.authority,
299 authorization: locutor.authorization,
300 })
301 }
302}
303
304impl Default for LocutorSerial {
305 fn default() -> Self {
306 Locutor::default().into()
307 }
308}
309
310mod locutor_precedence_serde {
313 use serde::de;
314 use serde::ser;
315
316 pub fn serialize<S>(precedence: &u16, serializer: S) -> Result<S::Ok, S::Error>
317 where
318 S: ser::Serializer,
319 {
320 serializer.serialize_str(&precedence.to_string())
321 }
322
323 pub fn deserialize<'de, D>(deserializer: D) -> Result<u16, D::Error>
324 where
325 D: de::Deserializer<'de>,
326 {
327 match serde::Deserialize::deserialize(deserializer)? {
328 serde_json::Value::Number(n) => n
329 .as_u64()
330 .ok_or_else(|| de::Error::custom("Invalid number"))
331 .map(|n| n as u16),
332 serde_json::Value::String(s) => s
333 .trim()
334 .parse()
335 .map_err(|_| de::Error::custom("Invalid string"))
336 .map(|n: u16| n),
337 _ => Err(de::Error::custom("Invalid value")),
338 }
339 }
340}
341
342#[cfg(test)]
343mod test {
344 use std::str::FromStr;
345
346 use super::*;
347 use ascii::AsciiString;
348 use serde_json::json;
349
350 #[test]
351 fn example_json() {
352 let json = json! (
353 {
354 "ENTITY": "<0|0|24>",
355 "OUTLET": "<0|0|11>",
356 "AUXILIARY": "<0|0|1>",
357 "ANCILLARY": "<0|0|2>",
358 "CONTEXT": "AVESTERRA_CONTEXT",
359 "CATEGORY": "AVESTERRA_CATEGORY",
360 "CLASS": "AVESTERRA_CLASS",
361 "METHOD": "AVESTERRA_METHOD",
362 "ATTRIBUTE": "AVESTERRA_ATTRIBUTE",
363 "INSTANCE": 1,
364 "NAME": "Example Name",
365 "VALUE": "Example String",
366 "VALUE_TAG": "STRING_TAG",
367 "INDEX": 1,
368 "COUNT": 123,
369 "PRECEDENCE": " 8",
370 "PARAMETER": -1,
371 "MODE": "AVESTERRA_MODE",
372 "EVENT": "AVESTERRA_EVENT",
373 "TIMEOUT": 60,
374 "ASPECT": "AVESTERRA_ASPECT",
375 "AUTHORITY": "********-****-****-****-************"
376 }
377 );
378
379 assert_eq!(
380 serde_json::from_value::<Locutor>(json).unwrap(),
381 Locutor {
382 entity: Entity::new(0, 0, 24),
383 outlet: Entity::new(0, 0, 11),
384 auxiliary: Entity::new(0, 0, 1),
385 ancillary: Entity::new(0, 0, 2),
386 context: Context::Avesterra,
387 category: Category::Avesterra,
388 class: Class::Avesterra,
389 method: Method::Avesterra,
390 attribute: Attribute::Avesterra,
391 instance: 1,
392 offset: 0,
393 parameter: -1,
394 resultant: 0,
395 count: 123,
396 index: 1,
397 event: Event::Avesterra,
398 mode: Mode::Avesterra,
399 state: State::Null,
400 condition: Condition::Null,
401 precedence: 8,
402 time: OffsetDateTime::from_unix_timestamp(0).unwrap(),
403 timeout: 60,
404 aspect: Aspect::Avesterra,
405 template: Template::Null,
406 scheme: Scheme::Null,
407 name: String255::unchecked("Example Name"),
408 label: String::new(),
409 key: String255::NULL,
410 value: Value::String(AsciiString::from_str("Example String").unwrap()),
411 format: Format::Null,
412 authority: Token::from_str("********-****-****-****-************").unwrap(),
413 authorization: Token::NULL,
414 }
415 )
416 }
417
418 #[test]
419 fn empty() {
420 let json = json!({});
421
422 assert_eq!(
423 serde_json::from_value::<Locutor>(json).unwrap(),
424 Locutor {
425 ..Default::default()
426 }
427 )
428 }
429
430 #[test]
431 fn precedence_as_string() {
432 let json = json! (
433 {
434 "PRECEDENCE": " 983 ",
435 }
436 );
437
438 assert_eq!(
439 serde_json::from_value::<Locutor>(json).unwrap(),
440 Locutor {
441 precedence: 983,
442 ..Default::default()
443 }
444 )
445 }
446
447 #[test]
448 fn precedence_as_number() {
449 let json = json! (
450 {
451 "PRECEDENCE": 123,
452 }
453 );
454
455 assert_eq!(
456 serde_json::from_value::<Locutor>(json).unwrap(),
457 Locutor {
458 precedence: 123,
459 ..Default::default()
460 }
461 )
462 }
463
464 #[test]
465 fn value_null() {
466 let json = json!({
467 "VALUE": "2398",
468 "VALUE_TAG": "INTEGER_TAG",
469 });
470
471 assert_eq!(
472 serde_json::from_value::<Locutor>(json).unwrap(),
473 Locutor {
474 value: Value::Integer(2398),
475 ..Default::default()
476 }
477 )
478 }
479
480 #[test]
481 fn serialize_empty() {
482 let v: serde_json::Value = serde_json::to_value(Locutor::default()).unwrap();
483
484 assert_eq!(v, json!({}))
485 }
486
487 #[test]
488 fn serialize_one_field() {
489 let loc = Locutor {
490 entity: Entity::new(0, 0, 24),
491 ..Default::default()
492 };
493 let v: serde_json::Value = serde_json::to_value(loc).unwrap();
494
495 assert_eq!(v, json!({"ENTITY": "<0|0|24>"}))
496 }
497
498 #[test]
499 fn negative_values() {
500 let json = json!({
501 "TIMEOUT": -1,
502 "INDEX": -2,
503 "COUNT": -3,
504 "RESULTANT": -4,
505 "PARAMETER": -5,
506 "OFFSET": -6,
507 "INSTANCE": -7,
508 });
509
510 let loc = serde_json::from_value::<Locutor>(json).unwrap();
511 assert_eq!(
512 loc,
513 Locutor {
514 timeout: -1,
515 index: -2,
516 count: -3,
517 resultant: -4,
518 parameter: -5,
519 offset: -6,
520 instance: -7,
521 ..Default::default()
522 }
523 );
524
525 assert_eq!(
526 serde_json::to_value(loc).unwrap(),
527 json!({
528 "TIMEOUT": -1,
529 "INDEX": -2,
530 "COUNT": -3,
531 "RESULTANT": -4,
532 "PARAMETER": -5,
533 "OFFSET": -6,
534 "INSTANCE": -7,
535 })
536 );
537 }
538}