orchestra_toolkit/
value.rs

1/* Copyright 2024-2025 LEDR Technologies Inc.
2* This file is part of the Orchestra library, which helps developer use our Orchestra technology which is based on AvesTerra, owned and developped by Georgetown University, under license agreement with LEDR Technologies Inc.
3*
4* The Orchestra library is a free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
5*
6* The Orchestra library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
7*
8* You should have received a copy of the GNU Lesser General Public License along with the Orchestra library. If not, see <https://www.gnu.org/licenses/>.
9*
10* If you have any questions, feedback or issues about the Orchestra library, you can contact us at support@ledr.io.
11*/
12
13use crate::time_serde::*;
14use crate::AvialError;
15use crate::Locutor;
16use crate::Operator;
17use crate::{Entity, Tag, Token};
18use ascii::AsciiChar;
19use ascii::AsciiString;
20use ascii::IntoAsciiString;
21use std::collections::HashMap;
22use std::num::IntErrorKind;
23use std::{cmp::PartialEq, fmt, str::FromStr};
24use thiserror::Error;
25use time::OffsetDateTime;
26
27// Used for value variant that isn't implemented
28#[derive(Clone, Debug, PartialEq)]
29pub struct UnimplementedValue(pub String);
30
31#[derive(Clone, PartialEq, Debug)]
32pub enum Value {
33    Null(String),
34    Avesterra(String),
35    Boolean(bool),
36    Character(AsciiChar),
37    String(AsciiString),
38    Text(String),
39    Integer(i64),
40    Float(f64),
41    Entity(Entity),
42    Time(OffsetDateTime),
43    Web(String),
44    Interchange(String),
45    Data(Vec<u8>),
46    Exception(AvialError),
47    Operator(Operator),
48    Function(Entity),
49    Measurement(UnimplementedValue),
50    Locutor(Box<Locutor>),
51    Authorization(Token),
52    Date(UnimplementedValue),
53    Aggregate(HashMap<String, Value>),
54    Array(Vec<Value>),
55    Variable(String, Box<Value>),
56}
57
58impl Value {
59    pub const NULL: Value = Value::Null(String::new());
60
61    pub fn is_null(&self) -> bool {
62        matches!(self, Value::Null(_))
63    }
64}
65
66#[derive(Error, Debug)]
67#[error("Value of type {actual:?} cannot be read as {expected:?}")]
68pub struct ConvertValueError {
69    expected: Tag,
70    actual: Tag,
71}
72
73#[derive(Error, Debug)]
74#[error("Fail to create value of type {tag:?} from string {string:?}: {error}")]
75pub struct ValueCreationError {
76    tag: Tag,
77    string: String,
78    error: Box<dyn std::error::Error + std::marker::Sync + std::marker::Send>,
79}
80
81impl Default for Value {
82    fn default() -> Self {
83        Self::Null(String::new())
84    }
85}
86
87macro_rules! getter {
88    ($name:ident, $tag:ident, $type:ty) => {
89        pub fn $name(self) -> Result<$type, ConvertValueError> {
90            match self {
91                Value::$tag(val) => Ok(val),
92                _ => Err(ConvertValueError {
93                    expected: Tag::$tag,
94                    actual: self.get_tag(),
95                }),
96            }
97        }
98    };
99}
100
101impl Value {
102    pub fn get_tag(&self) -> Tag {
103        match *self {
104            Value::Null(_) => Tag::Null,
105            Value::Avesterra(_) => Tag::Avesterra,
106            Value::Boolean(_) => Tag::Boolean,
107            Value::Character(_) => Tag::Character,
108            Value::String(_) => Tag::String,
109            Value::Text(_) => Tag::Text,
110            Value::Integer(_) => Tag::Integer,
111            Value::Float(_) => Tag::Float,
112            Value::Entity(_) => Tag::Entity,
113            Value::Time(_) => Tag::Time,
114            Value::Web(_) => Tag::Web,
115            Value::Interchange(_) => Tag::Interchange,
116            Value::Data(_) => Tag::Data,
117            Value::Exception(_) => Tag::Exception,
118            Value::Operator(_) => Tag::Operator,
119            Value::Function(_) => Tag::Function,
120            Value::Measurement(_) => Tag::Measurement,
121            Value::Locutor(_) => Tag::Locutor,
122            Value::Authorization(_) => Tag::Authorization,
123            Value::Date(_) => Tag::Date,
124            Value::Aggregate(_) => Tag::Aggregate,
125            Value::Array(_) => Tag::Array,
126            Value::Variable(_, _) => Tag::Variable,
127        }
128    }
129
130    getter!(null, Null, String);
131    getter!(avesterra, Avesterra, String);
132    getter!(boolean, Boolean, bool);
133    getter!(character, Character, AsciiChar);
134    getter!(string, String, AsciiString);
135    getter!(text, Text, String);
136    getter!(integer, Integer, i64);
137    getter!(float, Float, f64);
138    getter!(entity, Entity, Entity);
139    getter!(time, Time, OffsetDateTime);
140    getter!(web, Web, String);
141    getter!(interchange, Interchange, String);
142    getter!(data, Data, Vec<u8>);
143    getter!(exception, Exception, AvialError);
144    getter!(operator, Operator, Operator);
145    getter!(function, Function, Entity);
146    // getter!(measurement, Measurement, Measurement);
147    getter!(locutor, Locutor, Box<Locutor>);
148    getter!(authorization, Authorization, Token);
149    // getter!(date, Date, UnimplementedValue);
150    getter!(aggregate, Aggregate, HashMap<String, Value>);
151    getter!(array, Array, Vec<Value>);
152
153    pub fn variable(self) -> Result<(String, Box<Value>), ConvertValueError> {
154        match self {
155            Value::Variable(name, val) => Ok((name, val)),
156            _ => Err(ConvertValueError {
157                expected: Tag::Variable,
158                actual: self.get_tag(),
159            }),
160        }
161    }
162
163    pub(crate) fn new(tag: Tag, s: String) -> Result<Value, ValueCreationError> {
164        let result = match tag {
165            Tag::Null => Value::Null(s),
166            Tag::Avesterra => Value::Avesterra(s),
167            Tag::Boolean => Value::Boolean(bool::from_str(&s.to_lowercase()).map_err(|_| {
168                ValueCreationError {
169                    tag,
170                    string: s.to_owned(),
171                    error: "provided string was not `true` or `false` (case insensitive)".into(),
172                }
173            })?),
174            Tag::Character => {
175                let mut b = s.bytes();
176                let char = match (b.next(), b.next()) {
177                    (Some(b), None) => AsciiChar::from_ascii(b).map_err(|e| ValueCreationError {
178                        tag,
179                        string: s.to_owned(),
180                        error: Box::new(e),
181                    }),
182                    _ => Err(ValueCreationError {
183                        tag,
184                        string: s.to_owned(),
185                        error: "ascii character is not 1 byte".into(),
186                    }),
187                };
188                Value::Character(char?)
189            }
190            Tag::String => {
191                Value::String(s.into_ascii_string().map_err(|e| ValueCreationError {
192                    tag,
193                    string: e.clone().into_source(),
194                    error: Box::new(e),
195                })?)
196            }
197            Tag::Text => Value::Text(s),
198            Tag::Integer => Value::Integer(i64::from_str(&s).map_err(|e| ValueCreationError {
199                tag,
200                string: s.to_owned(),
201                error: match e.kind() {
202                    IntErrorKind::PosOverflow | IntErrorKind::NegOverflow => {
203                        "integer out of range, value does not fit in 64 bytes signed integer".into()
204                    }
205                    _ => Box::new(e),
206                },
207            })?),
208            Tag::Float => Value::Float(f64::from_str(&s).map_err(|e| ValueCreationError {
209                tag,
210                string: s.to_owned(),
211                error: Box::new(e),
212            })?),
213            Tag::Entity => {
214                Value::Entity(Entity::from_str_strict(&s).map_err(|e| ValueCreationError {
215                    tag,
216                    string: s.to_owned(),
217                    error: Box::new(e),
218                })?)
219            }
220            Tag::Time => {
221                Value::Time(
222                    unix_timestamp_string_to_time(&s).map_err(|e| ValueCreationError {
223                        tag,
224                        string: s.to_owned(),
225                        error: Box::new(e),
226                    })?,
227                )
228            }
229            Tag::Web => Value::Web(s),
230            Tag::Interchange => Value::Interchange(s),
231            Tag::Data => Value::Data(base16::decode(&s).map_err(|e| ValueCreationError {
232                tag,
233                string: s.to_owned(),
234                error: Box::new(e),
235            })?),
236            Tag::Exception => {
237                Value::Exception(serde_json::from_str(&s).map_err(|e| ValueCreationError {
238                    tag,
239                    string: s.to_owned(),
240                    error: Box::new(e),
241                })?)
242            }
243            Tag::Operator => Value::Operator(
244                serde_json::from_value(serde_json::Value::String(s.clone())).map_err(|e| {
245                    ValueCreationError {
246                        tag,
247                        string: s.to_owned(),
248                        error: Box::new(e),
249                    }
250                })?,
251            ),
252            Tag::Function => {
253                Value::Function(Entity::from_str_strict(&s).map_err(|e| ValueCreationError {
254                    tag,
255                    string: s.to_owned(),
256                    error: Box::new(e),
257                })?)
258            }
259            Tag::Measurement => Value::Measurement(UnimplementedValue(s)),
260            Tag::Locutor => Value::Locutor(Box::new(serde_json::from_str(&s).map_err(|e| {
261                ValueCreationError {
262                    tag,
263                    string: s.to_owned(),
264                    error: Box::new(e),
265                }
266            })?)),
267            Tag::Authorization => {
268                Value::Authorization(Token::from_str(&s).map_err(|e| ValueCreationError {
269                    tag,
270                    string: s.to_owned(),
271                    error: Box::new(e),
272                })?)
273            }
274            Tag::Date => Value::Date(UnimplementedValue(s)),
275            Tag::Aggregate => {
276                Value::Aggregate(serde_json::from_str(&s).map_err(|e| ValueCreationError {
277                    tag,
278                    string: s.to_owned(),
279                    error: Box::new(e),
280                })?)
281            }
282            Tag::Array => {
283                Value::Array(serde_json::from_str(&s).map_err(|e| ValueCreationError {
284                    tag,
285                    string: s.to_owned(),
286                    error: Box::new(e),
287                })?)
288            }
289
290            Tag::Variable => {
291                let map: HashMap<String, Value> =
292                    serde_json::from_str(&s).map_err(|e| ValueCreationError {
293                        tag,
294                        string: s.to_owned(),
295                        error: Box::new(e),
296                    })?;
297                if map.len() != 1 {
298                    return Err(ValueCreationError {
299                        tag,
300                        string: s.to_owned(),
301                        error: "variable must have exactly one key".into(),
302                    });
303                }
304                let kvp = map.into_iter().next().unwrap();
305                Value::Variable(kvp.0, Box::new(kvp.1))
306            }
307        };
308        Ok(result)
309    }
310
311    #[rustfmt::skip]
312    /// Gives the string representation of the value, as encoded in JSON
313    pub(crate) fn get_bytes(&self) -> String {
314
315        // UNWRAP SAFETY:
316        // serde_json::to_string documentation states:
317        //
318        // > Serialization can fail if `T`'s implementation of `Serialize` decides to
319        // > fail, or if `T` contains a map with non-string keys.
320        //
321        // We control both the implementation of `Serialize` for every item,
322        // and the keys of the maps, so we can be sure that this will never fail.
323        match self {
324            Value::Null(v)           => v.to_owned(),
325            Value::Avesterra(v)      => v.to_owned(),
326            Value::Boolean(v)        => v.to_string().to_ascii_uppercase(),
327            Value::Character(v)      => v.as_char().to_string(),
328            Value::String(v)         => v.to_string(),
329            Value::Text(v)           => v.to_owned(),
330            Value::Integer(v)        => v.to_string(),
331            Value::Float(v)          => v.to_string(),
332            Value::Entity(v)         => v.to_string(),
333            Value::Time(v)           => time_to_unix_timestamp_string(v),
334            Value::Web(v)            => v.to_string(),
335            Value::Interchange(v)    => v.to_owned(), // TODO: serialize avialModel
336            Value::Data(v)           => base16::encode_upper(v),
337            Value::Exception(v)      => serde_json::to_string(v).unwrap(),
338            Value::Operator(v)       => serde_json::to_value(v).unwrap().as_str().unwrap().to_owned(),
339            Value::Function(v)       => v.to_string(),
340            Value::Measurement(v)    => v.0.clone(),
341            Value::Locutor(v)        => serde_json::to_string(v).unwrap(),
342            Value::Authorization(v)  => v.to_string(),
343            Value::Date(v)           => v.0.clone(),
344            Value::Aggregate(v)      => serde_json::to_string(v).unwrap(),
345            Value::Array(v)          => serde_json::to_string(v).unwrap(),
346            Value::Variable(n, v)    => serde_json::json!{ { n: v } }.to_string()
347        }
348    }
349}
350
351mod serde_impl {
352    use super::*;
353
354    use serde::de;
355    use serde::ser;
356    use serde::ser::SerializeMap;
357
358    use crate::Tag;
359
360    impl ser::Serialize for Value {
361        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
362        where
363            S: ser::Serializer,
364        {
365            let tag = self.get_tag();
366            let value = self.get_bytes();
367
368            // For some reasons, a value json is the only place where tags are
369            // written without the _TAG suffix
370            let tagstr = serde_json::to_value(tag)
371                .unwrap()
372                .as_str()
373                .unwrap()
374                .strip_suffix("_TAG")
375                .unwrap()
376                .to_owned();
377
378            let mut state = serializer.serialize_map(Some(1))?;
379            state.serialize_entry(&tagstr, &value)?;
380            state.end()
381        }
382    }
383
384    struct ValueVisitor;
385    impl<'de> de::Visitor<'de> for ValueVisitor {
386        type Value = crate::Value;
387
388        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
389            formatter.write_str("a tag value pair")
390        }
391
392        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
393        where
394            A: de::MapAccess<'de>,
395        {
396            let (tag, value) = match (
397                map.next_entry::<Tag, String>()?,
398                map.next_entry::<String, String>()?,
399            ) {
400                (Some((tag, value)), None) => (tag, value),
401                (None, None) => return Err(serde::de::Error::custom("missing tag/value pair")),
402                (Some(_), Some(_)) => {
403                    return Err(serde::de::Error::custom("expected only one tag/value pair"))
404                }
405                (None, Some(_)) => unreachable!(),
406            };
407            Value::new(tag, value).map_err(serde::de::Error::custom)
408        }
409    }
410
411    impl<'de> de::Deserialize<'de> for crate::Value {
412        fn deserialize<D>(deserializer: D) -> Result<crate::Value, D::Error>
413        where
414            D: de::Deserializer<'de>,
415        {
416            deserializer.deserialize_map(ValueVisitor)
417        }
418    }
419}
420
421impl fmt::Display for Value {
422    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
423        let tag = self.get_tag();
424        let val = self.get_bytes();
425        write!(f, "Value({tag:?}, {val})")
426    }
427}
428
429#[cfg(test)]
430mod test {
431    use ascii::AsciiString;
432    use maplit::hashmap;
433    use serde_json::json;
434    use time::macros::datetime;
435
436    use super::*;
437    use crate::taxonomy::*;
438    use crate::AvialError;
439    use crate::String255;
440
441    macro_rules! test_ok {
442        ($value:expr, $json:expr $(,)?) => {
443            let jsonval = $json;
444            let v: Value = match serde_json::from_value(jsonval.clone()) {
445                Ok(v) => v,
446                Err(e) => panic!("unexpected error parsing json: {:?}", e),
447            };
448            assert_eq!(v, $value);
449
450            let endval = match serde_json::to_value(v) {
451                Ok(v) => v,
452                Err(e) => panic!("unexpected error serializing value: {:?}", e),
453            };
454            assert_eq!(endval, jsonval);
455        };
456    }
457
458    macro_rules! test_ok2 {
459        ($value:expr, $json_in:expr, $json_out:expr $(,)?) => {
460            let jsonval = $json_in;
461            let v: Value = match serde_json::from_value(jsonval.clone()) {
462                Ok(v) => v,
463                Err(e) => panic!("unexpected error parsing json: {:?}", e),
464            };
465            assert_eq!(v, $value);
466
467            let endval = match serde_json::to_value(v) {
468                Ok(v) => v,
469                Err(e) => panic!("unexpected error serializing value: {:?}", e),
470            };
471            let jsonval2 = $json_out;
472            assert_eq!(endval, jsonval2);
473        };
474    }
475
476    // Made for value where we can't check the exact json output
477    macro_rules! test_ok_nojsoncheck {
478        ($value:expr, $json:expr $(,)?) => {
479            let jsonval = $json;
480            let v: Value = match serde_json::from_value(jsonval.clone()) {
481                Ok(v) => v,
482                Err(e) => panic!("unexpected error parsing json: {:?}", e),
483            };
484            assert_eq!(v, $value);
485
486            let endjsonval = match serde_json::to_value(v.clone()) {
487                Ok(v) => v,
488                Err(e) => panic!("unexpected error serializing value: {:?}", e),
489            };
490
491            let v2: Value = match serde_json::from_value(endjsonval.clone()) {
492                Ok(v) => v,
493                Err(e) => panic!(
494                    "unexpected error parsing json after re-creating it: {:?}",
495                    e
496                ),
497            };
498            assert_eq!(v.clone(), v2, "value: {:?}, json: {:?}", v, endjsonval);
499        };
500    }
501
502    macro_rules! test_err {
503        ($json:expr) => {
504            match serde_json::from_value::<Value>($json) {
505                Ok(v) => panic!("expected error, got {:?}", v),
506                Err(e) => println!("OK: got expected error: {}", e),
507            };
508        };
509    }
510
511    #[test]
512    fn general_errors() {
513        // TOFIX: test_err!(json!({ "STRING": "first", "STRING": "second" }));
514        test_err!(json!({}));
515        test_err!(json!({ "INTEGER": 42 })); // it should be "42"
516        test_err!(json!({ "BLAH": "Hi" }));
517    }
518
519    #[test]
520    fn null() {
521        test_ok!(Value::Null("".into()), json!({ "NULL": "" }));
522        test_ok!(
523            Value::Null("content im not sure is used anyways".into()),
524            json!({ "NULL": "content im not sure is used anyways" })
525        );
526        test_ok!(
527            Value::Null("你好世界".into()),
528            json!({ "NULL": "你好世界" })
529        );
530    }
531
532    #[test]
533    fn avesterra() {
534        test_ok!(Value::Avesterra("".into()), json!({ "AVESTERRA": "" }));
535        test_ok!(
536            Value::Avesterra("Example".into()),
537            json!({ "AVESTERRA": "Example" })
538        );
539    }
540
541    #[test]
542    fn boolean() {
543        test_ok!(Value::Boolean(true), json!({ "BOOLEAN": "TRUE" }));
544        test_ok!(Value::Boolean(false), json!({ "BOOLEAN": "FALSE" }));
545        test_err!(json!({ "BOOLEAN": "blah" }));
546        test_err!(json!({ "BOOLEAN": "" }));
547    }
548
549    #[test]
550    fn character() {
551        test_ok!(Value::Character(AsciiChar::a), json!({ "CHARACTER": "a" }));
552        test_ok!(Value::Character(AsciiChar::A), json!({ "CHARACTER": "A" }));
553        test_ok!(Value::Character(AsciiChar::_1), json!({ "CHARACTER": "1" }));
554        test_ok!(
555            Value::Character(AsciiChar::Space),
556            json!({ "CHARACTER": " " })
557        );
558        test_err!(json!({ "CHARACTER": "" }));
559        test_err!(json!({ "CHARACTER": "ab" }));
560        test_err!(json!({ "CHARACTER": "ä" }));
561    }
562
563    #[test]
564    fn string() {
565        test_ok!(Value::String(AsciiString::new()), json!({ "STRING": "" }));
566        test_ok!(
567            Value::String(AsciiString::from_ascii(r"Hello World!\u0007").unwrap()),
568            json!({ "STRING": r"Hello World!\u0007" })
569        );
570        test_err!(json!({ "STRING": "Hello world is 你好世界" }));
571    }
572
573    #[test]
574    fn text() {
575        test_ok!(Value::Text("".into()), json!({ "TEXT": "" }));
576        test_ok!(
577            Value::Text("ÅvësTêrrã".into()),
578            json!({ "TEXT": "ÅvësTêrrã" })
579        );
580        test_ok!(
581            Value::Text("Hello world is 你好世界".into()),
582            json!({ "TEXT": "Hello world is 你好世界" })
583        );
584    }
585
586    #[test]
587    fn integer() {
588        test_ok!(Value::Integer(0), json!({ "INTEGER": "0" }));
589        test_ok!(Value::Integer(42), json!({ "INTEGER": "42" }));
590        test_ok!(Value::Integer(-42), json!({ "INTEGER": "-42" }));
591        test_err!(json!({ "INTEGER": "42.0" }));
592        test_err!(json!({ "INTEGER": "" }));
593        test_err!(json!({ "INTEGER": "three" }));
594        test_ok!(
595            Value::Integer(9_223_372_036_854_775_807),
596            json!({ "INTEGER": "9223372036854775807" })
597        );
598        test_ok!(
599            Value::Integer(-9_223_372_036_854_775_808),
600            json!({ "INTEGER": "-9223372036854775808" })
601        );
602        test_err!(json!({ "INTEGER": "9223372036854775808" }));
603        test_err!(json!({ "INTEGER": "-9223372036854775809" }));
604    }
605
606    #[test]
607    #[allow(clippy::approx_constant)]
608    fn float() {
609        // Note: It's unclear what the standard is, it seems that every
610        // implementation is different.
611        test_ok2!(
612            Value::Float(3.14159),
613            json!({ "FLOAT":"3.14159000000000000E+00" }),
614            json!({ "FLOAT":"3.14159" })
615        );
616        test_err!(json!({ "FLOAT": "" }));
617        test_err!(json!({ "FLOAT": "hello" }));
618    }
619
620    #[test]
621    fn entity() {
622        test_ok!(
623            Value::Entity(Entity {
624                pid: 0,
625                hid: 0,
626                uid: 24
627            }),
628            json!({ "ENTITY": "<0|0|24>" })
629        );
630        test_ok!(
631            Value::Entity(Entity {
632                pid: 0,
633                hid: 0,
634                uid: 24
635            }),
636            json!({ "ENTITY": "<0|0|24>" })
637        );
638
639        test_err!(json!({ "ENTITY": "" }));
640        test_err!(json!({ "ENTITY": "<0|0|>" }));
641        test_err!(json!({ "ENTITY": "<0|0|24" }));
642        test_err!(json!({ "ENTITY": "<0|0|24|>" }));
643        test_err!(json!({ "ENTITY": "<0|0|24|24>" }));
644        test_err!(json!({ "ENTITY": "0|0|24>" }));
645
646        // This is not standard and shouldn't be allowed
647        // except locally, where which server is referred to is obvious from context
648        test_err!(json!({ "ENTITY": "<24>" }));
649    }
650
651    #[test]
652    fn time() {
653        test_ok!(
654            Value::Time(datetime!(1970-01-01 00:00:00 UTC)),
655            json!({ "TIME": "0" })
656        );
657        test_ok!(
658            Value::Time(datetime!(2010-01-11 00:00:22 UTC)),
659            json!({ "TIME": "1263168022" })
660        );
661        test_ok!(
662            Value::Time(datetime!(1895-07-15 09:25:51 UTC)),
663            json!({ "TIME": "-2349873249" })
664        );
665        test_err!(json!({ "TIME": "" }));
666        test_err!(json!({ "TIME": "안녕" }));
667        test_err!(json!({ "TIME": "9223372036854775808" })); // i64 overflow
668        test_err!(json!({ "TIME": "9223372036854775807" })); // too far in the future
669    }
670
671    #[test]
672    fn web() {
673        test_ok!(
674            Value::Web("https://example.com".into()),
675            json!({ "WEB": "https://example.com" }),
676        );
677
678        test_ok!(
679            Value::Web("https://example.com/%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C".into()),
680            json!({ "WEB": "https://example.com/%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C" }),
681        );
682
683        test_ok!(
684            Value::Web("www.example.com".into()),
685            json!({ "WEB": "www.example.com" })
686        );
687
688        // Not sure if we should allow this :(
689        // There is no standard for this, better leave that to the application layer.
690        test_ok!(Value::Web("".into()), json!({ "WEB": "" }));
691    }
692
693    #[test]
694    fn interchange() {} // TODO: AvialModel
695
696    #[test]
697    fn data() {
698        test_ok!(
699            Value::Data(vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]),
700            json!({ "DATA": "000102030405" })
701        );
702        test_ok!(
703            Value::Data(vec![0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]),
704            json!({ "DATA": "0A0B0C0D0E0F" })
705        );
706        test_ok2!(
707            Value::Data(vec![0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]),
708            json!({ "DATA": "0a0b0c0d0e0f" }),
709            json!({ "DATA": "0A0B0C0D0E0F" }),
710        );
711        test_ok!(
712            Value::Data(String::from(r#"Example Data ~!@#$%^&*()_+"'"#).into_bytes()),
713            json!({ "DATA": "4578616D706C652044617461207E21402324255E262A28295F2B2227" })
714        );
715
716        test_ok!(Value::Data(vec![]), json!({ "DATA": "" }));
717        test_err!(json!({ "DATA": "0G" }));
718        test_err!(json!({ "DATA": ".f" }));
719        test_err!(json!({ "DATA": "3" }));
720    }
721
722    #[test]
723    fn exception() {
724        test_ok!(
725            Value::Exception(AvialError {
726                error: Error::Halt,
727                message: "The machine has halted".into()
728            }),
729            json!({ "EXCEPTION": r#"{"ERROR":"HALT_ERROR","MESSAGE":"The machine has halted"}"# })
730        );
731        test_ok!(
732            Value::Exception(AvialError {
733                error: Error::Adapter,
734                message: "There was an error".into()
735            }),
736            json!({ "EXCEPTION": r#"{"ERROR":"ADAPTER_ERROR","MESSAGE":"There was an error"}"# }),
737        );
738        test_ok2!(
739            Value::Exception(AvialError {
740                error: Error::Network,
741                message: "Connection lost".into()
742            }),
743            json!({ "EXCEPTION"   :  r#"  {   "ERROR"   :    "NETWORK_ERROR"   ,   "MESSAGE"   :   "Connection lost"  }  "#    }),
744            json!({ "EXCEPTION": r#"{"ERROR":"NETWORK_ERROR","MESSAGE":"Connection lost"}"# }),
745        );
746
747        test_err!(json!({ "EXCEPTION": r#"{"ERROR":"IDONTEXIST_ERROR","MESSAGE":"Oh no"}"# }));
748        test_err!(json!({ "EXCEPTION": r#"{"ERR":"ADAPTER_ERROR","MESSAGE":"Oh no no o"}"# }));
749        test_err!(json!({ "EXCEPTION": r#"{"ERROR":"ADAPTER_ERROR","MSG":"Oh no no no "}"# }));
750        test_err!(json!({ "EXCEPTION": r#"{"MESSAGE":"Oh no no no no no no no no no no"}"# }));
751        test_err!(json!({ "EXCEPTION": r#"{"ERROR":"ADAPTER_ERROR"}"# }));
752        test_err!(json!({ "EXCEPTION": r#"{}"# }));
753        test_err!(json!({ "EXCEPTION": r#"[]"# }));
754        test_err!(json!({ "EXCEPTION": r#""# }));
755    }
756
757    #[test]
758    fn operator() {
759        test_ok!(
760            Value::Operator(Operator::Halt),
761            json!( { "OPERATOR": "HALT_OPERATOR" })
762        );
763
764        // We accept both form, but the standard is the one with the _OPERATOR suffix
765        test_ok2!(
766            Value::Operator(Operator::Return),
767            json!( { "OPERATOR": "RETURN" }),
768            json!( { "OPERATOR": "RETURN_OPERATOR" }),
769        );
770
771        test_err!(json!({ "OPERATOR": "" }));
772        test_err!(json!({ "OPERATOR": "YOUSHALLNOTPASS" }));
773    }
774
775    #[test]
776    fn function() {
777        test_ok!(
778            Value::Function(Entity {
779                pid: 0,
780                hid: 0,
781                uid: 24
782            }),
783            json!({ "FUNCTION": "<0|0|24>" })
784        );
785        test_ok!(
786            Value::Function(Entity {
787                pid: 0,
788                hid: 0,
789                uid: 24
790            }),
791            json!({ "FUNCTION": "<0|0|24>" })
792        );
793
794        test_err!(json!({ "FUNCTION": "" }));
795        test_err!(json!({ "FUNCTION": "<0|0|>" }));
796        test_err!(json!({ "FUNCTION": "<0|0|24" }));
797        test_err!(json!({ "FUNCTION": "<0|0|24|>" }));
798        test_err!(json!({ "FUNCTION": "<0|0|24|24>" }));
799        test_err!(json!({ "FUNCTION": "0|0|24>" }));
800
801        // This is not standard and shouldn't be allowed
802        // except locally, where which server is referred to is obvious from context
803        test_err!(json!({ "FUNCTION": "<24>" }));
804    }
805
806    #[test]
807    fn authorization() {
808        test_ok!(
809            Value::Authorization(Token::from_str("2d754e46-6259-45f6-ac46-745f42f02558").unwrap()),
810            json!({ "AUTHORIZATION": "2d754e46-6259-45f6-ac46-745f42f02558" }),
811        );
812        test_ok!(
813            Value::Authorization(Token::from_str("d1159412-e368-4694-9289-5ce02979c523").unwrap()),
814            json!({ "AUTHORIZATION": "d1159412-e368-4694-9289-5ce02979c523" }),
815        );
816
817        test_ok2!(
818            Value::Authorization(Token::NOAUTH),
819            json!({ "AUTHORIZATION": "********-****-****-****-************" }),
820            json!({ "AUTHORIZATION": "ffffffff-ffff-ffff-ffff-ffffffffffff" }),
821        );
822        test_ok!(
823            Value::Authorization(Token::NOAUTH),
824            json!({ "AUTHORIZATION": "ffffffff-ffff-ffff-ffff-ffffffffffff" }),
825        );
826        test_ok!(
827            Value::Authorization(Token::NULL),
828            json!({ "AUTHORIZATION": "00000000-0000-0000-0000-000000000000" }),
829        );
830
831        test_err!(json!({ "AUTHORIZATION": "" }));
832        test_err!(json!({ "AUTHORIZATION": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }));
833        test_err!(json!({ "AUTHORIZATION": "hello world" }));
834        test_err!(json!({ "AUTHORIZATION": "你好" }));
835        test_err!(json!({ "AUTHORIZATION": 0}));
836        test_err!(json!({ "AUTHORIZATION": {}}));
837    }
838
839    #[test]
840    fn date() {
841        test_ok!(
842            Value::Authorization(Token::from_str("2d754e46-6259-45f6-ac46-745f42f02558").unwrap()),
843            json!({ "AUTHORIZATION": "2d754e46-6259-45f6-ac46-745f42f02558" }),
844        );
845
846        test_ok!(
847            Value::Measurement(UnimplementedValue(
848                "{\"YEAR\": 1960,\"MONTH\": 10,\"DAY\": 1}".to_string()
849            )),
850            json!(
851            {
852                "MEASUREMENT": "{\"YEAR\": 1960,\"MONTH\": 10,\"DAY\": 1}"
853            }),
854        );
855    }
856
857    #[test]
858    fn aggregate() {
859        test_ok_nojsoncheck!(
860            Value::Aggregate(hashmap! {
861                "Boolean Variable".to_owned() => Value::Boolean(true),
862                "Integer Variable".to_owned() => Value::Integer(42),
863            }),
864            json!({
865                "AGGREGATE": "{\"Boolean Variable\":{\"BOOLEAN\":\"TRUE\"},\"Integer Variable\":{\"INTEGER\":\"42\"}}"
866            }),
867        );
868
869        test_ok!(
870            Value::Aggregate(hashmap! {}),
871            json!({
872                "AGGREGATE": "{}"
873            }),
874        );
875
876        test_ok!(
877            Value::Aggregate(hashmap! {
878                "Nested".to_owned() => Value::Aggregate(hashmap! {}),
879            }),
880            json!({
881                "AGGREGATE": "{\"Nested\":{\"AGGREGATE\":\"{}\"}}"
882            }),
883        );
884
885        test_err!(json!({ "AGGREGATE": "" }));
886        test_err!(json!({ "AGGREGATE": "}" }));
887        test_err!(json!({ "AGGREGATE": "32" }));
888        test_err!(json!({ "AGGREGATE": "[]" }));
889        test_err!(json!({ "AGGREGATE": "hi" }));
890        test_err!(json!({ "AGGREGATE": "\"MyValue\": {\"INTEGER\": \"string!\"}" }));
891    }
892
893    #[test]
894    fn array() {
895        test_ok!(
896            Value::Array(vec![
897                Value::Entity(Entity {
898                    pid: 0,
899                    hid: 0,
900                    uid: 24,
901                }),
902                Value::Integer(42),
903            ]),
904            json!({
905                "ARRAY": "[{\"ENTITY\":\"<0|0|24>\"},{\"INTEGER\":\"42\"}]"
906            }),
907        );
908
909        test_ok!(
910            Value::Array(vec![
911                Value::String(AsciiString::from_ascii("Hello").unwrap()),
912                Value::Float(7.2939),
913                Value::Array(vec![Value::Character(AsciiChar::A), Value::Boolean(true),]),
914                Value::Entity(Entity {
915                    pid: 0,
916                    hid: 0,
917                    uid: 24
918                }),
919            ]),
920            json!({
921                "ARRAY": "[{\"STRING\":\"Hello\"},{\"FLOAT\":\"7.2939\"},{\"ARRAY\":\"[{\\\"CHARACTER\\\":\\\"A\\\"},{\\\"BOOLEAN\\\":\\\"TRUE\\\"}]\"},{\"ENTITY\":\"<0|0|24>\"}]"
922            }),
923        );
924
925        test_ok!(
926            Value::Array(vec![
927                Value::String(AsciiString::from_ascii("Hello").unwrap()),
928                Value::Float(7.2939),
929                Value::Aggregate(hashmap! {
930                    "Key".to_owned() => Value::Character(AsciiChar::A)
931                }),
932                Value::Entity(Entity {
933                    pid: 0,
934                    hid: 0,
935                    uid: 24
936                }),
937            ]),
938            json!({
939                "ARRAY": "[{\"STRING\":\"Hello\"},{\"FLOAT\":\"7.2939\"},{\"AGGREGATE\":\"{\\\"Key\\\":{\\\"CHARACTER\\\":\\\"A\\\"}}\"},{\"ENTITY\":\"<0|0|24>\"}]"
940            }),
941        );
942
943        test_ok!(
944            Value::Array(vec![
945                Value::String(AsciiString::from_ascii("Hello").unwrap()),
946                Value::Float(7.2939),
947                Value::Array(vec![Value::Character(AsciiChar::A), Value::Boolean(true),]),
948            ]),
949            json!({
950                "ARRAY": "[{\"STRING\":\"Hello\"},{\"FLOAT\":\"7.2939\"},{\"ARRAY\":\"[{\\\"CHARACTER\\\":\\\"A\\\"},{\\\"BOOLEAN\\\":\\\"TRUE\\\"}]\"}]"
951            }),
952        );
953
954        test_ok!(
955            Value::Array(vec![]),
956            json!({
957                "ARRAY": "[]"
958            }),
959        );
960
961        test_err!(json!({ "ARRAY": "" }));
962        test_err!(json!({ "ARRAY": "}" }));
963        test_err!(json!({ "ARRAY": "32" }));
964        test_err!(json!({ "ARRAY": "{}" }));
965        test_err!(json!({ "ARRAY": "hi" }));
966    }
967
968    #[test]
969    fn variable() {
970        test_ok!(
971            Value::Variable(
972                "City Variable".to_owned(),
973                Box::new(Value::String(
974                    AsciiString::from_ascii("Washington, D.C.").unwrap()
975                ))
976            ),
977            json!({
978                "VARIABLE": "{\"City Variable\":{\"STRING\":\"Washington, D.C.\"}}"
979            }),
980        );
981
982        test_ok!(
983            Value::Variable("MyVariable".to_owned(), Box::new(Value::Array(vec![]))),
984            json!({
985                "VARIABLE": "{\"MyVariable\":{\"ARRAY\":\"[]\"}}"
986            }),
987        );
988
989        test_ok_nojsoncheck!(
990            Value::Variable(
991                "MyVariable".to_owned(),
992                Box::new(Value::Aggregate(hashmap! {
993                    "Thing 1".to_owned() => Value::Integer(21),
994                    "Thing 2".to_owned() => Value::Boolean(true),
995                }))
996            ),
997            json!({
998                "VARIABLE": "{\"MyVariable\":{\"AGGREGATE\":\"{\\\"Thing 1\\\":{\\\"INTEGER\\\":\\\"21\\\"},\\\"Thing 2\\\":{\\\"BOOLEAN\\\":\\\"TRUE\\\"}}\"}}"
999            }),
1000        );
1001
1002        test_err!(json!({ "VARIABLE": "" }));
1003        test_err!(json!({ "VARIABLE": "}" }));
1004        test_err!(json!({ "VARIABLE": "32" }));
1005        test_err!(json!({ "VARIABLE": "{}" }));
1006        test_err!(json!({ "VARIABLE": "hi" }));
1007    }
1008
1009    #[test]
1010    fn locutor() {
1011        test_ok_nojsoncheck!(
1012            Value::Locutor(Box::new(Locutor {
1013                entity: Entity::new(0, 0, 24),
1014                outlet: Entity::new(0, 0, 11),
1015                auxiliary: Entity::new(0, 0, 1),
1016                ancillary: Entity::new(0, 0, 2),
1017                context: Context::Avesterra,
1018                category: Category::Avesterra,
1019                class: Class::Avesterra,
1020                method: Method::Avesterra,
1021                attribute: Attribute::Avesterra,
1022                instance: 1,
1023                offset: 0,
1024                parameter: -1,
1025                resultant: 0,
1026                count: 123,
1027                index: 1,
1028                event: Event::Avesterra,
1029                mode: Mode::Avesterra,
1030                state: State::Null,
1031                condition: Condition::Null,
1032                precedence: 8,
1033                time: OffsetDateTime::from_unix_timestamp(0).unwrap(),
1034                timeout: 60,
1035                aspect: Aspect::Avesterra,
1036                template: Template::Null,
1037                scheme: Scheme::Null,
1038                name: String255::unchecked("Example Name"),
1039                label: String::new(),
1040                key: String255::NULL,
1041                value: Value::String(AsciiString::from_str("Example String").unwrap()),
1042                format: Format::Null,
1043                authority: Token::from_str("********-****-****-****-************").unwrap(),
1044                authorization: Token::NULL,
1045            })),
1046            json!(
1047            {
1048              "LOCUTOR": "{\"ENTITY\": \"<0|0|24>\",\"OUTLET\": \"<0|0|11>\",\"AUXILIARY\": \"<0|0|1>\",\"ANCILLARY\": \"<0|0|2>\",\"CONTEXT\": \"AVESTERRA_CONTEXT\",\"CATEGORY\": \"AVESTERRA_CATEGORY\",\"CLASS\": \"AVESTERRA_CLASS\",\"METHOD\": \"AVESTERRA_METHOD\",\"ATTRIBUTE\": \"AVESTERRA_ATTRIBUTE\",\"INSTANCE\": 1,\"NAME\": \"Example Name\",\"VALUE\": \"Example String\",\"VALUE_TAG\": \"STRING_TAG\",\"INDEX\": 1,\"COUNT\": 123,\"PRECEDENCE\": \" 8\",\"PARAMETER\": -1,\"MODE\": \"AVESTERRA_MODE\",\"EVENT\": \"AVESTERRA_EVENT\",\"TIMEOUT\": 60,\"ASPECT\": \"AVESTERRA_ASPECT\",\"AUTHORITY\": \"********-****-****-****-************\"}"
1049            }),
1050        );
1051
1052        test_err!(json!({ "LOCUTOR": "" }));
1053        test_err!(json!({ "LOCUTOR": "}" }));
1054        test_err!(json!({ "LOCUTOR": "32" }));
1055        test_err!(json!({ "LOCUTOR": "hi" }));
1056    }
1057
1058    #[test]
1059    fn measurement() {
1060        test_ok!(
1061            Value::Measurement(UnimplementedValue("{\"FLOAT\": 4.20000000000000E+01,\"UNIT\": \"GRAM_UNIT\",\"PREFIX\": \"MICRO_PREFIX\",\"CONFIDENCE\": 9.99000015258789E+01,\"UNCERTAINTY\": 1.00000001490116E-01}".to_string())),
1062            json!(
1063            {
1064                "MEASUREMENT": "{\"FLOAT\": 4.20000000000000E+01,\"UNIT\": \"GRAM_UNIT\",\"PREFIX\": \"MICRO_PREFIX\",\"CONFIDENCE\": 9.99000015258789E+01,\"UNCERTAINTY\": 1.00000001490116E-01}"
1065            }),
1066        );
1067    }
1068}