oa_gateway_uci/
instance.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Schema-annotated instance tree. Adapters convert; the engine never
//! sees this.
//!
//! [`Message::name`] is the global element. [`Complex::type_name`] is
//! set when `$type` / `xsi:type` overrides the declared type.
//! [`Field::Many`] is a repeating element, not a JSON array invented
//! by the codec.

use serde_json::Number;

/// One UCI / OMS message: a global element and its body.
#[derive(Debug, Clone, PartialEq)]
pub struct Message {
    pub name: String,
    pub body: Node,
}

/// A leaf or a complex element.
#[derive(Debug, Clone, PartialEq)]
pub enum Node {
    Simple(Simple),
    Complex(Complex),
}

/// A scalar as JSON would carry it. XML text that does not fit the
/// declared primitive stays a [`Self::String`] rather than being
/// coerced.
#[derive(Debug, Clone, PartialEq)]
pub enum Simple {
    String(String),
    Bool(bool),
    Number(Number),
}

/// Child fields of a complex type, in document order.
#[derive(Debug, Clone, PartialEq)]
pub struct Complex {
    /// Set when `$type` / `xsi:type` overrides the declared type.
    pub type_name: Option<String>,
    pub fields: Vec<(String, Field)>,
}

/// One child name: a single occurrence or a repeating group.
#[derive(Debug, Clone, PartialEq)]
pub enum Field {
    One(Node),
    Many(Vec<Node>),
}

impl Complex {
    /// First field whose name equals `name`. Case-sensitive.
    #[must_use]
    pub fn get(&self, name: &str) -> Option<&Field> {
        self.fields.iter().find(|(n, _)| n == name).map(|(_, f)| f)
    }
}

impl Simple {
    /// Lexical form for XML text and for validation.
    #[must_use]
    pub fn as_text(&self) -> String {
        match self {
            Self::String(s) => s.clone(),
            Self::Bool(true) => "true".into(),
            Self::Bool(false) => "false".into(),
            Self::Number(n) => n.to_string(),
        }
    }
}