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) } }