1use chrono::{NaiveDateTime, NaiveTime};
2use serde::de;
3use std::{collections::HashMap, fmt, str::FromStr};
4
5struct CsvEncodedStringVisitor;
6
7impl<'a> de::Visitor<'a> for CsvEncodedStringVisitor {
8 type Value = Vec<i32>;
9
10 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
11 write!(formatter, "a string of comma-separated integers")
12 }
13
14 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
15 let mut result = Vec::new();
16
17 for s in v.split(',') {
18 if !s.is_empty() {
19 result.push(s.parse::<i32>().map_err(|e| {
20 de::Error::custom(format!("invalid integer {}, caused error {}", s, e))
21 })?);
22 }
23 }
24
25 Ok(result)
26 }
27}
28
29pub fn deserialize_option_csv_encoded_string<'a, D: de::Deserializer<'a>>(
30 deserializer: D,
31) -> Result<Option<Vec<i32>>, D::Error> {
32 deserializer.deserialize_option(OptionCsvEncodedStringVisitor)
33}
34
35struct OptionCsvEncodedStringVisitor;
36
37impl<'a> de::Visitor<'a> for OptionCsvEncodedStringVisitor {
38 type Value = Option<Vec<i32>>;
39
40 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
41 write!(formatter, "a string of comma-separated integers or null")
42 }
43
44 fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
45 Ok(None)
46 }
47
48 fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
49 Ok(None)
50 }
51
52 fn visit_some<D: de::Deserializer<'a>>(self, d: D) -> Result<Self::Value, D::Error> {
53 Ok(Some(d.deserialize_str(CsvEncodedStringVisitor)?))
54 }
55}
56
57pub fn deserialize_optional_string_enum<'a, D: de::Deserializer<'a>, T: FromStr + 'a>(
58 deserializer: D,
59) -> Result<Option<T>, D::Error> {
60 deserializer.deserialize_option(OptionStringEnumVisitor {
61 _marker: Default::default(),
62 })
63}
64
65#[derive(Default)]
66struct OptionStringEnumVisitor<'a, T: FromStr> {
67 _marker: std::marker::PhantomData<&'a T>,
68}
69
70impl<'a, T: FromStr> de::Visitor<'a> for OptionStringEnumVisitor<'a, T> {
71 type Value = Option<T>;
72
73 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
74 write!(
75 formatter,
76 "a string representation an enum value that can be null"
77 )
78 }
79
80 fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
82 Ok(None)
83 }
84
85 fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
86 Ok(None)
87 }
88
89 fn visit_some<D: de::Deserializer<'a>>(self, d: D) -> Result<Self::Value, D::Error> {
90 Ok(Some(d.deserialize_str(StringEnumVisitor {
91 _marker: Default::default(),
92 })?))
93 }
94}
95
96pub fn deserialize_string_enum<'a, D: de::Deserializer<'a>, T: FromStr + 'a>(
97 deserializer: D,
98) -> Result<T, D::Error> {
99 deserializer.deserialize_str(StringEnumVisitor {
100 _marker: Default::default(),
101 })
102}
103
104#[derive(Default)]
105struct StringEnumVisitor<'a, T: FromStr> {
106 _marker: std::marker::PhantomData<&'a T>,
107}
108
109impl<'a, T: FromStr> de::Visitor<'a> for StringEnumVisitor<'a, T> {
110 type Value = T;
111
112 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
113 write!(formatter, "a string representation an enum value")
114 }
115
116 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
117 let enum_value: T = v
118 .parse()
119 .map_err(|_| de::Error::custom(format!("invalid enum value {}", v)))?;
120
121 Ok(enum_value)
122 }
123}
124
125pub fn deserialize_api_error<'a, D: de::Deserializer<'a>>(
126 deserializer: D,
127) -> Result<String, D::Error> {
128 deserializer.deserialize_seq(ApiErrorVisitor)
129}
130
131struct ApiErrorVisitor;
132
133impl<'a> de::Visitor<'a> for ApiErrorVisitor {
134 type Value = String;
135
136 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
137 write!(formatter, "an SEPTA API error")
138 }
139
140 fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
141 let mut error: Option<String> = None;
142
143 while let Some(element) = seq.next_element::<HashMap<String, String>>()? {
144 if error.is_some() {
145 return Err(de::Error::custom("expected only one error"));
146 } else if element.contains_key("error") {
147 error = element.get("error").map(|s| s.to_string());
148 }
149 }
150
151 error.ok_or_else(|| de::Error::custom("expected an error"))
152 }
153}
154
155pub fn deserialize_naive_date_time<'a, D: de::Deserializer<'a>>(
156 deserializer: D,
157) -> Result<NaiveDateTime, D::Error> {
158 deserializer.deserialize_str(NaiveDateTimeVisitor)
159}
160
161const DATE_TIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S%.f";
162
163struct NaiveDateTimeVisitor;
164
165impl<'a> de::Visitor<'a> for NaiveDateTimeVisitor {
166 type Value = NaiveDateTime;
167
168 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
169 write!(formatter, "a trivially encoded date string")
170 }
171
172 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
173 match NaiveDateTime::parse_from_str(value, DATE_TIME_FORMAT) {
174 Ok(date) => Ok(date),
175 Err(e) => Err(E::custom(format!(
176 "Error {} parsing timestamp {}",
177 e, value
178 ))),
179 }
180 }
181}
182
183pub fn deserialize_naive_time<'a, D: de::Deserializer<'a>>(
184 deserializer: D,
185) -> Result<NaiveTime, D::Error> {
186 deserializer.deserialize_str(NaiveTimeVisitor)
187}
188
189const TIME_FORMAT: &str = "%I:%M%p";
190
191struct NaiveTimeVisitor;
192
193impl<'a> de::Visitor<'a> for NaiveTimeVisitor {
194 type Value = NaiveTime;
195
196 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
197 write!(formatter, "a trivially encoded time string")
198 }
199
200 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
201 match NaiveTime::parse_from_str(value, TIME_FORMAT) {
202 Ok(date) => Ok(date),
203 Err(e) => Err(E::custom(format!("Error {} parsing time {}", e, value))),
204 }
205 }
206}
207
208pub fn deserialize_naive_time_with_space<'a, D: de::Deserializer<'a>>(
209 deserializer: D,
210) -> Result<NaiveTime, D::Error> {
211 deserializer.deserialize_str(NaiveTimeWithSpaceVisitor)
212}
213
214const TIME_FORMAT_WITH_SPACE: &str = "%I:%M %p";
215
216struct NaiveTimeWithSpaceVisitor;
217
218impl<'a> de::Visitor<'a> for NaiveTimeWithSpaceVisitor {
219 type Value = NaiveTime;
220
221 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
222 write!(
223 formatter,
224 "an encoded time string with a space between the minutes and the AM/PM"
225 )
226 }
227
228 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
229 match NaiveTime::parse_from_str(value, TIME_FORMAT_WITH_SPACE) {
230 Ok(date) => Ok(date),
231 Err(e) => Err(E::custom(format!("Error {} parsing time {}", e, value))),
232 }
233 }
234}
235
236pub fn deserialize_option_naive_time_with_space<'a, D: de::Deserializer<'a>>(
237 deserializer: D,
238) -> Result<Option<NaiveTime>, D::Error> {
239 deserializer.deserialize_str(OptionNaiveTimeWithSpaceVisitor)
240}
241
242struct OptionNaiveTimeWithSpaceVisitor;
243
244impl<'a> de::Visitor<'a> for OptionNaiveTimeWithSpaceVisitor {
245 type Value = Option<NaiveTime>;
246
247 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
248 write!(
249 formatter,
250 "an encoded time string with a space between the minutes and the AM/PM or 'na'"
251 )
252 }
253
254 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
255 if value == "na" {
256 Ok(None)
257 } else {
258 match NaiveTime::parse_from_str(value, TIME_FORMAT_WITH_SPACE) {
259 Ok(date) => Ok(Some(date)),
260 Err(e) => Err(E::custom(format!("Error {} parsing time {}", e, value))),
261 }
262 }
263 }
264}
265
266pub fn deserialize_bool<'a, D: de::Deserializer<'a>>(deserializer: D) -> Result<bool, D::Error> {
267 deserializer.deserialize_str(BoolStringVisitor)
268}
269
270struct BoolStringVisitor;
271
272impl<'a> de::Visitor<'a> for BoolStringVisitor {
273 type Value = bool;
274
275 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
276 write!(formatter, "a trivially encoded bool")
277 }
278
279 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
280 match value.to_ascii_lowercase().as_str() {
281 "true" => Ok(true),
282 "false" => Ok(false),
283 _ => Err(de::Error::unknown_variant(value, &["true", "false"])),
284 }
285 }
286}
287
288pub fn deserialize_f64<'a, D: de::Deserializer<'a>>(deserializer: D) -> Result<f64, D::Error> {
289 deserializer.deserialize_str(F64StringVisitor)
290}
291
292struct F64StringVisitor;
293
294impl<'a> de::Visitor<'a> for F64StringVisitor {
295 type Value = f64;
296
297 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
298 write!(formatter, "a string encoded f64")
299 }
300
301 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
302 value
303 .parse::<f64>()
304 .map_err(|e| de::Error::custom(format!("Error {} parsing f64 {}", e, value)))
305 }
306}
307
308pub fn deserialize_optional_f64<'a, D: de::Deserializer<'a>>(
309 deserializer: D,
310) -> Result<Option<f64>, D::Error> {
311 deserializer.deserialize_option(OptionF64StringVisitor)
312}
313
314struct OptionF64StringVisitor;
315
316impl<'a> de::Visitor<'a> for OptionF64StringVisitor {
317 type Value = Option<f64>;
318
319 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
320 write!(formatter, "a string encoded f64 or null")
321 }
322
323 fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
324 Ok(None)
325 }
326
327 fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
328 Ok(None)
329 }
330
331 fn visit_some<D: de::Deserializer<'a>>(self, d: D) -> Result<Self::Value, D::Error> {
332 Ok(d.deserialize_str(F64StringVisitor)
333 .map(Some)
334 .unwrap_or(None))
335 }
336}