1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use serde::de::{Deserialize, Deserializer, MapVisitor, Visitor};
use serde::de::impls::IgnoredAny;
use super::super::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 Deserialize for Warning {
    fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
        struct WarningVisitor;

        impl Visitor for WarningVisitor {
            type Value = Warning;

            fn visit_map<V: MapVisitor>(&mut 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.visit_key::<String>()? {
                    match k.as_str() {
                        "code" => code = Some(v.visit_value::<Code>()?),
                        "message" => message = Some(v.visit_value()?),
                        "percent_full" => percent_full = Some(v.visit_value()?),
                        "user_id" => user_id = Some(v.visit_value()?),
                        _ => { v.visit_value::<IgnoredAny>()?; },
                    }

                    macro_rules! end {
                        () => {{
                            while let Some(_) = v.visit::<IgnoredAny,IgnoredAny>()? {}
                            v.end()?;
                        }};
                    }

                    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(ref c)), Some(_), _, _) => {
                            end!();
                            return Ok(Warning {
                                message: message.unwrap(),
                                code: WarningCode::Custom(c.to_owned()),
                            });
                        },
                        _ => (),
                    }
                }

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

        d.deserialize_map(WarningVisitor)
    }
}