1use std::fmt;
5use std::ops::{Deref, DerefMut};
6
7use serde::de::{self, MapAccess, Visitor};
8use serde::ser::SerializeStruct;
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
40pub struct Separators(pub er7::Separators);
41
42impl From<er7::Separators> for Separators {
43 fn from(inner: er7::Separators) -> Separators {
44 Separators(inner)
45 }
46}
47
48impl From<Separators> for er7::Separators {
49 fn from(outer: Separators) -> er7::Separators {
50 outer.0
51 }
52}
53
54impl Deref for Separators {
55 type Target = er7::Separators;
56
57 fn deref(&self) -> &er7::Separators {
58 &self.0
59 }
60}
61
62impl DerefMut for Separators {
63 fn deref_mut(&mut self) -> &mut er7::Separators {
64 &mut self.0
65 }
66}
67
68impl Serialize for Separators {
69 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
70 where
71 S: Serializer,
72 {
73 let mut state = serializer.serialize_struct("Separators", 6)?;
74 state.serialize_field("field", &self.0.field)?;
75 state.serialize_field("component", &self.0.component)?;
76 state.serialize_field("repetition", &self.0.repetition)?;
77 state.serialize_field("escape", &self.0.escape)?;
78 state.serialize_field("subcomponent", &self.0.subcomponent)?;
79 state.serialize_field("truncation", &self.0.truncation)?;
80 state.end()
81 }
82}
83
84const FIELDS: &[&str] = &[
85 "field",
86 "component",
87 "repetition",
88 "escape",
89 "subcomponent",
90 "truncation",
91];
92
93struct SeparatorsVisitor;
94
95impl<'de> Visitor<'de> for SeparatorsVisitor {
96 type Value = Separators;
97
98 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
99 formatter.write_str(
100 "a Separators object with \"field\", \"component\", \"repetition\", \"escape\", \
101 \"subcomponent\", and \"truncation\"",
102 )
103 }
104
105 fn visit_map<V>(self, mut map: V) -> Result<Separators, V::Error>
106 where
107 V: MapAccess<'de>,
108 {
109 let mut field = None;
110 let mut component = None;
111 let mut repetition = None;
112 let mut escape = None;
113 let mut subcomponent = None;
114 let mut truncation: Option<Option<char>> = None;
115
116 while let Some(key) = map.next_key::<String>()? {
117 match key.as_str() {
118 "field" => set_once(&mut field, &mut map, "field")?,
119 "component" => set_once(&mut component, &mut map, "component")?,
120 "repetition" => set_once(&mut repetition, &mut map, "repetition")?,
121 "escape" => set_once(&mut escape, &mut map, "escape")?,
122 "subcomponent" => set_once(&mut subcomponent, &mut map, "subcomponent")?,
123 "truncation" => {
124 if truncation.is_some() {
125 return Err(de::Error::duplicate_field("truncation"));
126 }
127 truncation = Some(map.next_value()?);
128 }
129 _ => {
130 let _ = map.next_value::<de::IgnoredAny>()?;
131 }
132 }
133 }
134
135 let field = field.ok_or_else(|| de::Error::missing_field("field"))?;
136 let component = component.ok_or_else(|| de::Error::missing_field("component"))?;
137 let repetition = repetition.ok_or_else(|| de::Error::missing_field("repetition"))?;
138 let escape = escape.ok_or_else(|| de::Error::missing_field("escape"))?;
139 let subcomponent = subcomponent.ok_or_else(|| de::Error::missing_field("subcomponent"))?;
140 let truncation = truncation.unwrap_or(None);
144
145 Ok(Separators(er7::Separators {
146 field,
147 component,
148 repetition,
149 escape,
150 subcomponent,
151 truncation,
152 }))
153 }
154}
155
156fn set_once<'de, V>(
159 slot: &mut Option<char>,
160 map: &mut V,
161 name: &'static str,
162) -> Result<(), V::Error>
163where
164 V: MapAccess<'de>,
165{
166 if slot.is_some() {
167 return Err(de::Error::duplicate_field(name));
168 }
169 *slot = Some(map.next_value()?);
170 Ok(())
171}
172
173impl<'de> Deserialize<'de> for Separators {
174 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
175 where
176 D: Deserializer<'de>,
177 {
178 deserializer.deserialize_struct("Separators", FIELDS, SeparatorsVisitor)
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn round_trips_the_default_delimiters() {
188 let separators = Separators::default();
189 let json = serde_json::to_string(&separators).unwrap();
190 let back: Separators = serde_json::from_str(&json).unwrap();
191 assert_eq!(back, separators);
192 }
193
194 #[test]
195 fn round_trips_custom_delimiters_and_truncation() {
196 let separators = Separators(er7::Separators {
197 field: '#',
198 component: '*',
199 repetition: '!',
200 escape: '?',
201 subcomponent: '@',
202 truncation: Some('%'),
203 });
204 let json = serde_json::to_string(&separators).unwrap();
205 let back: Separators = serde_json::from_str(&json).unwrap();
206 assert_eq!(back, separators);
207 }
208
209 #[test]
210 fn treats_a_missing_truncation_key_as_none() {
211 let json =
212 r#"{"field":"|","component":"^","repetition":"~","escape":"\\","subcomponent":"&"}"#;
213 let back: Separators = serde_json::from_str(json).unwrap();
214 assert_eq!(back.truncation, None);
215 }
216
217 #[test]
218 fn rejects_a_missing_required_field() {
219 let err = serde_json::from_str::<Separators>(r#"{"field":"|"}"#).unwrap_err();
220 assert!(err.to_string().contains("component"));
221 }
222}