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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::fmt::{Formatter, Result as FmtResult};

use serde::{
    de::{Deserializer, Error as DeError, MapAccess, Visitor},
    ser::Serializer,
    Deserialize, Serialize,
};

use super::Address;

impl Serialize for Address {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_ref())
    }
}

impl<'de> Deserialize<'de> for Address {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        enum Field {
            User,
            Domain,
        }

        const FIELDS: &[&str] = &["user", "domain"];

        impl<'de> Deserialize<'de> for Field {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where
                D: Deserializer<'de>,
            {
                struct FieldVisitor;

                impl<'de> Visitor<'de> for FieldVisitor {
                    type Value = Field;

                    fn expecting(&self, formatter: &mut Formatter<'_>) -> FmtResult {
                        formatter.write_str("'user' or 'domain'")
                    }

                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
                    where
                        E: DeError,
                    {
                        match value {
                            "user" => Ok(Field::User),
                            "domain" => Ok(Field::Domain),
                            _ => Err(DeError::unknown_field(value, FIELDS)),
                        }
                    }
                }

                deserializer.deserialize_identifier(FieldVisitor)
            }
        }

        struct AddressVisitor;

        impl<'de> Visitor<'de> for AddressVisitor {
            type Value = Address;

            fn expecting(&self, formatter: &mut Formatter<'_>) -> FmtResult {
                formatter.write_str("email address string or object")
            }

            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
            where
                E: DeError,
            {
                s.parse().map_err(DeError::custom)
            }

            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
            where
                V: MapAccess<'de>,
            {
                let mut user = None;
                let mut domain = None;
                while let Some(key) = map.next_key()? {
                    match key {
                        Field::User => {
                            if user.is_some() {
                                return Err(DeError::duplicate_field("user"));
                            }
                            let val = map.next_value()?;
                            Address::check_user(val).map_err(DeError::custom)?;
                            user = Some(val);
                        }
                        Field::Domain => {
                            if domain.is_some() {
                                return Err(DeError::duplicate_field("domain"));
                            }
                            let val = map.next_value()?;
                            Address::check_domain(val).map_err(DeError::custom)?;
                            domain = Some(val);
                        }
                    }
                }
                let user: &str = user.ok_or_else(|| DeError::missing_field("user"))?;
                let domain: &str = domain.ok_or_else(|| DeError::missing_field("domain"))?;
                Ok(Address::new(user, domain).unwrap())
            }
        }

        deserializer.deserialize_any(AddressVisitor)
    }
}