Skip to main content

serde_er7/
subcomponent.rs

1//! [`Subcomponent`]: the leaf of the tree, serialized as a bare string.
2
3use std::fmt;
4use std::ops::{Deref, DerefMut};
5
6use serde::de::Visitor;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9/// A Serde-enabled [`er7::Subcomponent`].
10///
11/// A subcomponent holds only text — [`er7::Subcomponent::raw`] — so it
12/// serializes as a bare string rather than as a one-field object. That
13/// choice is the one that makes the whole tree read naturally in JSON:
14/// `PID-5.1` becomes `"SMITH"`, not `{"raw": "SMITH"}`.
15///
16/// The text serialized is `raw`, exactly as the sender wrote it — escape
17/// sequences included, not [`er7::Subcomponent::value`]-decoded. That keeps
18/// the crate's core promise: `Message::parse(text)?` followed by
19/// `.to_er7()` on the other end of any Serde format reproduces the
20/// original bytes. Decode with [`er7::Subcomponent::value`] yourself where
21/// you want the resolved text instead.
22///
23/// Example:
24///
25/// ```
26/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
27/// use serde_er7::Subcomponent;
28///
29/// let leaf = Subcomponent(er7::Subcomponent::new(r"Smith \T\ Jones"));
30/// let json = serde_json::to_string(&leaf)?;
31/// assert_eq!(json, r#""Smith \\T\\ Jones""#);
32///
33/// let back: Subcomponent = serde_json::from_str(&json)?;
34/// assert_eq!(back.raw, r"Smith \T\ Jones");
35/// # Ok(())
36/// # }
37/// ```
38#[derive(Debug, Clone, PartialEq, Eq, Default)]
39pub struct Subcomponent(pub er7::Subcomponent);
40
41impl From<er7::Subcomponent> for Subcomponent {
42    fn from(inner: er7::Subcomponent) -> Subcomponent {
43        Subcomponent(inner)
44    }
45}
46
47impl From<Subcomponent> for er7::Subcomponent {
48    fn from(outer: Subcomponent) -> er7::Subcomponent {
49        outer.0
50    }
51}
52
53impl Deref for Subcomponent {
54    type Target = er7::Subcomponent;
55
56    fn deref(&self) -> &er7::Subcomponent {
57        &self.0
58    }
59}
60
61impl DerefMut for Subcomponent {
62    fn deref_mut(&mut self) -> &mut er7::Subcomponent {
63        &mut self.0
64    }
65}
66
67impl Serialize for Subcomponent {
68    /// Write `raw` as a string, via [`Serializer::serialize_str`].
69    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
70    where
71        S: Serializer,
72    {
73        serializer.serialize_str(&self.0.raw)
74    }
75}
76
77/// Reads any string into a [`Subcomponent`]. There is no way for a string
78/// to be malformed here — every byte sequence is valid `raw` text — so this
79/// visitor never returns an error.
80struct SubcomponentVisitor;
81
82impl Visitor<'_> for SubcomponentVisitor {
83    type Value = Subcomponent;
84
85    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
86        formatter.write_str("a string holding one ER7 subcomponent, escape sequences as sent")
87    }
88
89    fn visit_str<E>(self, value: &str) -> Result<Subcomponent, E>
90    where
91        E: serde::de::Error,
92    {
93        Ok(Subcomponent(er7::Subcomponent::new(value)))
94    }
95}
96
97impl<'de> Deserialize<'de> for Subcomponent {
98    /// Read a string into `raw`, via [`Deserializer::deserialize_str`].
99    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100    where
101        D: Deserializer<'de>,
102    {
103        deserializer.deserialize_str(SubcomponentVisitor)
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn serializes_as_a_bare_string() {
113        let leaf = Subcomponent(er7::Subcomponent::new("SMITH"));
114        assert_eq!(serde_json::to_string(&leaf).unwrap(), r#""SMITH""#);
115    }
116
117    #[test]
118    fn round_trips_the_explicit_null() {
119        let null = Subcomponent(er7::Subcomponent::new(er7::message::NULL));
120        let json = serde_json::to_string(&null).unwrap();
121        let back: Subcomponent = serde_json::from_str(&json).unwrap();
122        assert!(back.is_null());
123    }
124
125    #[test]
126    fn round_trips_an_empty_subcomponent() {
127        let empty = Subcomponent::default();
128        let json = serde_json::to_string(&empty).unwrap();
129        let back: Subcomponent = serde_json::from_str(&json).unwrap();
130        assert!(back.is_empty());
131        assert!(!back.is_null());
132    }
133
134    #[test]
135    fn deref_reaches_the_inner_api() {
136        let separators = er7::Separators::default();
137        let leaf = Subcomponent(er7::Subcomponent::new(r"a\T\b"));
138        // `.value(...)` is a method on `er7::Subcomponent`, reached through Deref.
139        assert_eq!(leaf.value(&separators), "a&b");
140    }
141}