Skip to main content

serde_er7/
segment.rs

1//! [`Segment`]: a name and its [`Field`]s, serialized as an object.
2
3use std::fmt;
4use std::ops::{Deref, DerefMut};
5
6use serde::de::{self, MapAccess, Visitor};
7use serde::ser::SerializeStruct;
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10use crate::Field;
11
12/// A Serde-enabled [`er7::Segment`].
13///
14/// Unlike the levels below it, a segment carries two different kinds of
15/// information — its name and its fields — so it serializes as an object
16/// with two named fields, `"name"` and `"fields"`, the same shape
17/// [`serde`'s own manual-implementation guide](https://docs.rs/serde)
18/// walks through for a struct with named fields.
19///
20/// Example:
21///
22/// ```
23/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
24/// use serde_er7::Segment;
25///
26/// let message = er7::parse("MSH|^~\\&|LAB\rPID|1||9|4|SMITH^JOHN")?;
27/// let pid = message.segment("PID").unwrap().clone();
28///
29/// let json = serde_json::to_string(&Segment(pid))?;
30/// assert!(json.starts_with(r#"{"name":"PID","fields":"#));
31///
32/// let back: Segment = serde_json::from_str(&json)?;
33/// assert_eq!(back.to_er7(&message.separators), "PID|1||9|4|SMITH^JOHN");
34/// # Ok(())
35/// # }
36/// ```
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Segment(pub er7::Segment);
39
40impl From<er7::Segment> for Segment {
41    fn from(inner: er7::Segment) -> Segment {
42        Segment(inner)
43    }
44}
45
46impl From<Segment> for er7::Segment {
47    fn from(outer: Segment) -> er7::Segment {
48        outer.0
49    }
50}
51
52impl Deref for Segment {
53    type Target = er7::Segment;
54
55    fn deref(&self) -> &er7::Segment {
56        &self.0
57    }
58}
59
60impl DerefMut for Segment {
61    fn deref_mut(&mut self) -> &mut er7::Segment {
62        &mut self.0
63    }
64}
65
66impl Serialize for Segment {
67    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68    where
69        S: Serializer,
70    {
71        let fields: Vec<Field> = self.0.fields.iter().map(|f| Field(f.clone())).collect();
72        let mut state = serializer.serialize_struct("Segment", 2)?;
73        state.serialize_field("name", &self.0.name)?;
74        state.serialize_field("fields", &fields)?;
75        state.end()
76    }
77}
78
79const FIELDS: &[&str] = &["name", "fields"];
80
81struct SegmentVisitor;
82
83impl<'de> Visitor<'de> for SegmentVisitor {
84    type Value = Segment;
85
86    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
87        formatter.write_str("a segment object with \"name\" and \"fields\"")
88    }
89
90    fn visit_map<V>(self, mut map: V) -> Result<Segment, V::Error>
91    where
92        V: MapAccess<'de>,
93    {
94        let mut name: Option<String> = None;
95        let mut fields: Option<Vec<Field>> = None;
96
97        while let Some(key) = map.next_key::<String>()? {
98            match key.as_str() {
99                "name" => {
100                    if name.is_some() {
101                        return Err(de::Error::duplicate_field("name"));
102                    }
103                    name = Some(map.next_value()?);
104                }
105                "fields" => {
106                    if fields.is_some() {
107                        return Err(de::Error::duplicate_field("fields"));
108                    }
109                    fields = Some(map.next_value()?);
110                }
111                _ => {
112                    let _ = map.next_value::<de::IgnoredAny>()?;
113                }
114            }
115        }
116
117        let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
118        let fields = fields.ok_or_else(|| de::Error::missing_field("fields"))?;
119        Ok(Segment(er7::Segment {
120            name,
121            fields: fields.into_iter().map(|f| f.0).collect(),
122        }))
123    }
124}
125
126impl<'de> Deserialize<'de> for Segment {
127    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
128    where
129        D: Deserializer<'de>,
130    {
131        deserializer.deserialize_struct("Segment", FIELDS, SegmentVisitor)
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    #[test]
140    fn round_trips_a_segment() {
141        let segment = Segment(er7::Segment {
142            name: "PID".into(),
143            fields: vec![er7::Field {
144                repetitions: vec![er7::Repetition {
145                    components: vec![er7::Component {
146                        subcomponents: vec![er7::Subcomponent::new("1")],
147                    }],
148                }],
149            }],
150        });
151        let json = serde_json::to_string(&segment).unwrap();
152        let back: Segment = serde_json::from_str(&json).unwrap();
153        assert_eq!(back, segment);
154    }
155
156    #[test]
157    fn rejects_a_missing_name() {
158        let err = serde_json::from_str::<Segment>(r#"{"fields":[]}"#).unwrap_err();
159        assert!(err.to_string().contains("name"));
160    }
161
162    #[test]
163    fn ignores_unknown_fields() {
164        let json = r#"{"name":"ZZZ","fields":[],"extra":true}"#;
165        let back: Segment = serde_json::from_str(json).unwrap();
166        assert_eq!(back.name, "ZZZ");
167    }
168}