twitter_stream_message/
util.rs

1use std::borrow::Cow;
2use std::collections::HashMap;
3use std::fmt::{self, Formatter};
4use std::mem;
5use std::ops::Deref;
6
7use serde::de::{
8    Deserialize,
9    DeserializeSeed,
10    Deserializer,
11    Error as SerdeError,
12    IntoDeserializer,
13    MapAccess,
14    Visitor
15};
16
17use types::{DateTime, JsonValue};
18
19macro_rules! string_enums {
20    (
21        $(
22            $(#[$attr:meta])*
23            pub enum $E:ident<$lifetime:tt> {
24                $(
25                    $(#[$v_attr:meta])*
26                    $V:ident($by:expr)
27                ),*;
28                $(#[$u_attr:meta])*
29                $U:ident(_),
30            }
31        )*
32    ) => {
33        $(
34            $(#[$attr])*
35            pub enum $E<$lifetime> {
36                $(
37                    $(#[$v_attr])*
38                    $V,
39                )*
40                $(#[$u_attr])*
41                $U(::std::borrow::Cow<$lifetime, str>),
42            }
43
44            impl<'de: 'a, 'a> ::serde::Deserialize<'de> for $E<'a> {
45                fn deserialize<D: ::serde::Deserializer<'de>>(d: D)
46                    -> ::std::result::Result<Self, D::Error>
47                {
48                    struct V;
49
50                    impl<'a> ::serde::de::Visitor<'a> for V {
51                        type Value = $E<'a>;
52
53                        fn visit_str<E>(self, s: &str)
54                            -> ::std::result::Result<$E<'a>, E>
55                        {
56                            match s {
57                                $($by => Ok($E::$V),)*
58                                _ => Ok($E::$U(s.to_owned().into())),
59                            }
60                        }
61
62                        fn visit_borrowed_str<E>(self, s: &'a str)
63                            -> ::std::result::Result<$E<'a>, E>
64                        {
65                            match s {
66                                $($by => Ok($E::$V),)*
67                                _ => Ok($E::$U(s.into())),
68                            }
69                        }
70
71                        fn visit_string<E>(self, s: String)
72                            -> ::std::result::Result<$E<'a>, E>
73                        {
74                            match s.as_str() {
75                                $($by => Ok($E::$V),)*
76                                _ => Ok($E::$U(s.into())),
77                            }
78                        }
79
80                        fn expecting(&self, f: &mut ::std::fmt::Formatter)
81                            -> ::std::fmt::Result
82                        {
83                            write!(f, "a string")
84                        }
85                    }
86
87                    d.deserialize_str(V)
88                }
89            }
90
91            impl<'a> ::std::convert::AsRef<str> for $E<'a> {
92                fn as_ref(&self) -> &str {
93                    match *self {
94                        $($E::$V => $by,)*
95                        $E::$U(ref s) => s,
96                    }
97                }
98            }
99
100            impl<'a> ::std::cmp::PartialEq for $E<'a> {
101                fn eq(&self, other: &$E) -> bool {
102                    match *self {
103                        $($E::$V => match *other {
104                            $E::$V => true,
105                            $E::$U(ref s) if $by == s => true,
106                            _ => false,
107                        },)*
108                        $E::$U(ref s) => match *other {
109                            $($E::$V => $by == s,)*
110                            $E::$U(ref t) => s == t,
111                        },
112                    }
113                }
114            }
115
116            impl<'a> ::std::hash::Hash for $E<'a> {
117                fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
118                    match *self {
119                        $($E::$V => $by.hash(state),)*
120                        $E::$U(ref s) => s.hash(state),
121                    }
122                }
123            }
124
125            impl<'a> ::std::cmp::Eq for $E<'a> {}
126        )*
127    }
128}
129
130#[derive(Deserialize, Eq, PartialEq, Hash)]
131pub struct CowStr<'a>(
132    #[serde(borrow)]
133    pub Cow<'a, str>
134);
135
136/// A `MapAccess` that first yields values from `keys` and `vals`,
137/// and after they are exhausted, yields from `tail`.
138pub struct MapAccessChain<I, J, A> {
139    keys: I,
140    vals: J,
141    tail: A,
142}
143
144impl<'a> AsRef<str> for CowStr<'a> {
145    fn as_ref(&self) -> &str {
146        self.0.as_ref()
147    }
148}
149
150impl<'a> Deref for CowStr<'a> {
151    type Target = str;
152
153    fn deref(&self) -> &str {
154        self.as_ref()
155    }
156}
157
158impl<I: Iterator, J: Iterator, A> MapAccessChain<I, J, A> {
159    pub fn new<K, V>(keys: K, vals: V, a: A) -> MapAccessChain<I, J, A>
160    where
161        K: IntoIterator<IntoIter=I, Item=I::Item>,
162        V: IntoIterator<IntoIter=J, Item=J::Item>,
163    {
164        MapAccessChain {
165            keys: keys.into_iter(),
166            vals: vals.into_iter(),
167            tail: a,
168        }
169    }
170}
171
172impl<'de: 'a, 'a, I, J, A> MapAccess<'de> for MapAccessChain<I, J, A>
173where
174    I: Iterator<Item=Cow<'a, str>>,
175    J: Iterator<Item=JsonValue>,
176    A: MapAccess<'de>,
177{
178    type Error = A::Error;
179
180    fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K)
181        -> Result<Option<K::Value>, A::Error>
182    {
183        if let Some(k) = self.keys.next() {
184            seed.deserialize(k.into_deserializer()).map(Some)
185        } else {
186            self.tail.next_key_seed(seed)
187        }
188    }
189
190    fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V)
191        -> Result<V::Value, A::Error>
192    {
193        if let Some(v) = self.vals.next() {
194            seed.deserialize(v).map_err(A::Error::custom)
195        } else {
196            // FIXME: The code below unnecessarily copies data from the input.
197            // Initially, I wrote it like `self.tail.next_value_seed(seed)`,
198            // but this somehow caused `message::tests::parse` test to fail,
199            // with the following error:
200            // ```
201            // ErrorImpl {
202            //     code: ExpectedObjectCommaOrEnd,
203            //     line: 67,
204            //     column: 38
205            // }
206            // ```
207            // self.tail.next_value::<JsonValue>().and_then(|v| {
208            //     seed.deserialize(v).map_err(A::Error::custom)
209            // })
210            self.tail.next_value_seed(seed)
211        }
212    }
213}
214
215pub fn deserialize_default<'de, D, T>(d: D) -> Result<T, D::Error>
216    where D: Deserializer<'de>, T: Default + Deserialize<'de>
217{
218    Option::deserialize(d).map(|o| o.unwrap_or_else(T::default))
219}
220
221pub fn parse_datetime(s: &str) -> ::chrono::format::ParseResult<DateTime> {
222    use chrono::Utc;
223    use chrono::format::{self, Fixed, Item, Numeric, Pad, Parsed};
224
225    // "%a %b %e %H:%M:%S %z %Y"
226    const ITEMS: &[Item] = &[
227        Item::Fixed(Fixed::ShortWeekdayName),
228        Item::Space(" "),
229        Item::Fixed(Fixed::ShortMonthName),
230        Item::Space(" "),
231        Item::Numeric(Numeric::Day, Pad::Space),
232        Item::Space(" "),
233        Item::Numeric(Numeric::Hour, Pad::Zero),
234        Item::Literal(":"),
235        Item::Numeric(Numeric::Minute, Pad::Zero),
236        Item::Literal(":"),
237        Item::Numeric(Numeric::Second, Pad::Zero),
238        Item::Space(" "),
239        Item::Fixed(Fixed::TimezoneOffset),
240        Item::Space(" "),
241        Item::Numeric(Numeric::Year, Pad::Zero),
242    ];
243
244    let mut parsed = Parsed::new();
245    format::parse(&mut parsed, s, ITEMS.iter().cloned())?;
246    parsed.to_datetime_with_timezone(&Utc)
247}
248
249pub fn deserialize_datetime<'x, D: Deserializer<'x>>(d: D) -> Result<DateTime, D::Error> {
250    struct DTVisitor;
251
252    impl<'x> Visitor<'x> for DTVisitor {
253        type Value = DateTime;
254
255        fn visit_str<E: SerdeError>(self, s: &str) -> Result<DateTime, E> {
256            parse_datetime(s).map_err(|e| E::custom(e.to_string()))
257        }
258
259        fn expecting(&self, f: &mut Formatter) -> fmt::Result {
260            write!(f, "a formatted date and time string")
261        }
262    }
263
264    d.deserialize_str(DTVisitor)
265}
266
267/// Deserializes a map of strings in zero-copy fashion.
268pub fn deserialize_map_cow_str<'de: 'a, 'a, D: Deserializer<'de>>(d: D)
269    -> Result<HashMap<Cow<'a, str>, Cow<'a, str>>, D::Error>
270{
271    #[derive(Deserialize)]
272    struct MapDeserialize<'a>(
273        #[serde(borrow)]
274        HashMap<CowStr<'a>, CowStr<'a>>
275    );
276
277    MapDeserialize::deserialize(d).map(|m| unsafe {
278        mem::transmute::<
279            HashMap<CowStr<'a>, CowStr<'a>>,
280            HashMap<Cow<'a, str>, Cow<'a, str>,
281        >>(m.0)
282    }).map_err(D::Error::custom)
283}
284
285/// Deserializes an optional string in zero-copy fashion.
286pub fn deserialize_opt_cow_str<'de: 'a, 'a, D: Deserializer<'de>>(d: D)
287    -> Result<Option<Cow<'a, str>>, D::Error>
288{
289    #[derive(Deserialize)]
290    struct OptDeserialize<'a>(
291        #[serde(borrow)]
292        Option<CowStr<'a>>
293    );
294
295    OptDeserialize::deserialize(d)
296        .map(|de| de.0.map(|c| c.0))
297        .map_err(D::Error::custom)
298}
299
300/// Deserializes a sequenve of strings in zero-copy fashion.
301pub fn deserialize_vec_cow_str<'de: 'a, 'a, D: Deserializer<'de>>(d: D)
302    -> Result<Vec<Cow<'a, str>>, D::Error>
303{
304    #[derive(Deserialize)]
305    struct VecDeserialize<'a>(
306        #[serde(borrow)]
307        Vec<CowStr<'a>>
308    );
309
310    VecDeserialize::deserialize(d).map(|v| unsafe {
311        mem::transmute::<Vec<CowStr<'a>>, Vec<Cow<'a, str>>>(v.0)
312    }).map_err(D::Error::custom)
313}
314
315#[cfg(test)]
316mod tests {
317    use json;
318
319    use super::*;
320
321    #[test]
322    fn test_deserialize_default() {
323        use json;
324
325        #[derive(Debug, Default, Deserialize, PartialEq)]
326        struct S {
327            #[serde(deserialize_with = "deserialize_default")]
328            #[serde(default)]
329            n: u32,
330            #[serde(deserialize_with = "deserialize_default")]
331            #[serde(default)]
332            o: Option<bool>,
333            #[serde(deserialize_with = "deserialize_default")]
334            #[serde(default)]
335            s: String,
336            #[serde(deserialize_with = "deserialize_default")]
337            #[serde(default)]
338            v: Vec<u8>,
339        }
340
341        assert_eq!(
342            json::from_str::<S>(r#"{"n":null,"s":null}"#).unwrap(),
343            json::from_str(r#"{"o":null,"v":null}"#).unwrap()
344        );
345        assert_eq!(
346            S { n: 1, o: Some(true), s: "s".to_owned(), v: vec![255] },
347            json::from_str(r#"{"n":1,"o":true,"s":"s","v":[255]}"#).unwrap()
348        );
349    }
350
351    #[test]
352    fn test_parse_datetime() {
353        use chrono::{NaiveDate, Utc};
354        use types::DateTime;
355
356        assert_eq!(
357            DateTime::from_utc(NaiveDate::from_ymd(2017, 5, 1).and_hms(0, 1, 2), Utc),
358            parse_datetime("Mon May 01 00:01:02 +0000 2017").unwrap()
359        );
360        assert!(parse_datetime("2017-05-01T00:01:02Z").is_err());
361    }
362
363    #[test]
364    fn test_deserialize_cow() {
365        match deserialize_map_cow_str(
366            &mut json::Deserializer::from_str(r#"{"a":"b"}"#)
367        ).unwrap().into_iter().next().unwrap()
368        {
369            (Cow::Borrowed(_), Cow::Borrowed(_)) => (),
370            _ => panic!("`deserialize_map_cow_str` didn't borrow")
371        }
372
373        if let Cow::Owned(_) = deserialize_opt_cow_str(
374            &mut json::Deserializer::from_str(r#""a""#)
375        ).unwrap().unwrap()
376        {
377            panic!("`deserialize_opt_cow_str` didn't borrow");
378        }
379
380        if let Cow::Owned(_) = deserialize_vec_cow_str(
381            &mut json::Deserializer::from_str(r#"["a"]"#)
382        ).unwrap()[0]
383        {
384            panic!("`deserialize_vec_cow_str` didn't borrow");
385        }
386    }
387}