Skip to main content

serde_er7/
component.rs

1//! [`Component`]: a sequence of [`Subcomponent`]s, serialized as an array.
2
3use std::fmt;
4use std::ops::{Deref, DerefMut};
5
6use serde::de::{SeqAccess, Visitor};
7use serde::ser::SerializeSeq;
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10use crate::Subcomponent;
11
12/// A Serde-enabled [`er7::Component`].
13///
14/// A component is nothing but its subcomponents in order
15/// ([`er7::Component::subcomponents`]), so it serializes as a plain array
16/// rather than as a one-field object: `ACME&1.2.3&ISO` becomes
17/// `["ACME", "1.2.3", "ISO"]`. The same shape [`Subcomponent`] chose for
18/// itself, one level up.
19///
20/// Example:
21///
22/// ```
23/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
24/// use serde_er7::Component;
25///
26/// let message = er7::parse(r"MSH|^~\&|LAB|ACME&1.2.3&ISO")?;
27/// let component = er7::Component {
28///     subcomponents: vec![
29///         er7::Subcomponent::new("ACME"),
30///         er7::Subcomponent::new("1.2.3"),
31///         er7::Subcomponent::new("ISO"),
32///     ],
33/// };
34/// let wrapped = Component(component);
35///
36/// assert_eq!(serde_json::to_string(&wrapped)?, r#"["ACME","1.2.3","ISO"]"#);
37/// let back: Component = serde_json::from_str(r#"["ACME","1.2.3","ISO"]"#)?;
38/// // Subcomponents join on `&`, one level below where components join on `^`.
39/// assert_eq!(back.to_er7(&message.separators), "ACME&1.2.3&ISO");
40/// # Ok(())
41/// # }
42/// ```
43#[derive(Debug, Clone, PartialEq, Eq, Default)]
44pub struct Component(pub er7::Component);
45
46impl From<er7::Component> for Component {
47    fn from(inner: er7::Component) -> Component {
48        Component(inner)
49    }
50}
51
52impl From<Component> for er7::Component {
53    fn from(outer: Component) -> er7::Component {
54        outer.0
55    }
56}
57
58impl Deref for Component {
59    type Target = er7::Component;
60
61    fn deref(&self) -> &er7::Component {
62        &self.0
63    }
64}
65
66impl DerefMut for Component {
67    fn deref_mut(&mut self) -> &mut er7::Component {
68        &mut self.0
69    }
70}
71
72impl Serialize for Component {
73    /// Write each subcomponent as one array element.
74    ///
75    /// This clones every subcomponent to borrow it as a [`Subcomponent`],
76    /// which is the price of keeping one owning wrapper type per tree level
77    /// instead of a second, borrowing family — a fair trade for an HL7
78    /// message, which is kilobytes, not gigabytes.
79    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
80    where
81        S: Serializer,
82    {
83        let subcomponents = &self.0.subcomponents;
84        let mut seq = serializer.serialize_seq(Some(subcomponents.len()))?;
85        for subcomponent in subcomponents {
86            seq.serialize_element(&Subcomponent(subcomponent.clone()))?;
87        }
88        seq.end()
89    }
90}
91
92struct ComponentVisitor;
93
94impl<'de> Visitor<'de> for ComponentVisitor {
95    type Value = Component;
96
97    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
98        formatter.write_str("an array of subcomponent strings")
99    }
100
101    fn visit_seq<A>(self, mut seq: A) -> Result<Component, A::Error>
102    where
103        A: SeqAccess<'de>,
104    {
105        let mut subcomponents = Vec::with_capacity(seq.size_hint().unwrap_or(0));
106        while let Some(subcomponent) = seq.next_element::<Subcomponent>()? {
107            subcomponents.push(subcomponent.0);
108        }
109        Ok(Component(er7::Component { subcomponents }))
110    }
111}
112
113impl<'de> Deserialize<'de> for Component {
114    /// Read an array of strings into `subcomponents`.
115    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
116    where
117        D: Deserializer<'de>,
118    {
119        deserializer.deserialize_seq(ComponentVisitor)
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    #[test]
128    fn round_trips_several_subcomponents() {
129        let component = Component(er7::Component {
130            subcomponents: vec![
131                er7::Subcomponent::new("ACME"),
132                er7::Subcomponent::new("1.2.3"),
133                er7::Subcomponent::new("ISO"),
134            ],
135        });
136        let json = serde_json::to_string(&component).unwrap();
137        assert_eq!(json, r#"["ACME","1.2.3","ISO"]"#);
138        let back: Component = serde_json::from_str(&json).unwrap();
139        assert_eq!(back, component);
140    }
141
142    #[test]
143    fn round_trips_an_empty_array() {
144        let component = Component::default();
145        let json = serde_json::to_string(&component).unwrap();
146        assert_eq!(json, "[]");
147        let back: Component = serde_json::from_str(&json).unwrap();
148        assert!(back.subcomponents.is_empty());
149    }
150}