twitter-stream 0.3.1

A library for listening on Twitter Streaming API.
Documentation
use serde::de::{Deserialize, Deserializer, Error, IgnoredAny, MapAccess, Visitor};
use std::fmt;
use user::UserId;

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Warning {
    pub message: String,
    pub code: WarningCode,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum WarningCode {
    FallingBehind(u64),
    FollowsOverLimit(UserId),
    Custom(String),
}

impl<'x> Deserialize<'x> for Warning {
    fn deserialize<D: Deserializer<'x>>(d: D) -> Result<Self, D::Error> {
        struct WarningVisitor;

        impl<'x> Visitor<'x> for WarningVisitor {
            type Value = Warning;

            fn visit_map<V: MapAccess<'x>>(self, mut v: V) -> Result<Warning, V::Error> {
                string_enums! {
                    pub enum Code {
                        :FallingBehind("FALLING_BEHIND"),
                        :FollowsOverLimit("FOLLOWS_OVER_LIMIT");
                        :Custom(_),
                    }
                }

                let mut code = None;
                let mut message: Option<String> = None;
                let mut percent_full: Option<u64> = None;
                let mut user_id: Option<UserId> = None;

                while let Some(k) = v.next_key::<String>()? {
                    match k.as_str() {
                        "code" => code = Some(v.next_value::<Code>()?),
                        "message" => message = Some(v.next_value()?),
                        "percent_full" => percent_full = Some(v.next_value()?),
                        "user_id" => user_id = Some(v.next_value()?),
                        _ => { v.next_value::<IgnoredAny>()?; },
                    }

                    macro_rules! end {
                        () => {{
                            while v.next_entry::<IgnoredAny,IgnoredAny>()?.is_some() {}
                        }};
                    }

                    match (code.as_ref(), message.as_ref(), percent_full, user_id) {
                        (Some(&Code::FallingBehind), Some(_), Some(percent_full), _) => {
                            end!();
                            return Ok(Warning {
                                message: message.unwrap(),
                                code: WarningCode::FallingBehind(percent_full),
                            });
                        },
                        (Some(&Code::FollowsOverLimit), Some(_), _, Some(user_id)) => {
                            end!();
                            return Ok(Warning {
                                message: message.unwrap(),
                                code: WarningCode::FollowsOverLimit(user_id),
                            });
                        },
                        (Some(&Code::Custom(_)), Some(_), _, _) => {
                            end!();
                            if let Some(Code::Custom(code)) = code {
                                return Ok(Warning {
                                    message: message.unwrap(),
                                    code: WarningCode::Custom(code),
                                });
                            } else {
                                unreachable!();
                            }
                        },
                        _ => (),
                    }
                }

                if code.is_none() {
                    Err(V::Error::missing_field("code"))
                } else if message.is_none() {
                    Err(V::Error::missing_field("message"))
                } else if code == Some(Code::FallingBehind) {
                    Err(V::Error::missing_field("percent_full"))
                } else {
                    Err(V::Error::missing_field("user_id"))
                }
            }

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "a map")
            }
        }

        d.deserialize_map(WarningVisitor)
    }
}