1use std::fmt::{Display, Formatter};
2use std::ops::Deref;
3use std::str::FromStr;
4
5use log::error;
6use serde::{Deserialize, Serialize, Serializer};
7use validate::rules::email;
8
9use crate::error::InvalidEmailError;
10
11#[derive(Deserialize, PartialEq, Hash, Eq, Clone, Debug)]
27#[serde(try_from = "String", into = "String")]
28pub struct Email(String);
29
30impl Serialize for Email {
31 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
32 where
33 S: Serializer,
34 {
35 serializer.serialize_str(&self.0)
36 }
37}
38
39impl FromStr for Email {
40 type Err = InvalidEmailError;
41
42 fn from_str(s: &str) -> Result<Self, Self::Err> {
43 match email().validate(&s) {
44 Ok(_) => Ok(Self(s.to_string())),
45
46 Err(e) => {
47 error!("invalid e-mail '{}': {}", s, e.get_message());
48 Err(InvalidEmailError::ParseError)
49 }
50 }
51 }
52}
53
54impl AsRef<str> for Email {
55 fn as_ref(&self) -> &str {
56 &self.0
57 }
58}
59
60impl TryFrom<String> for Email {
61 type Error = InvalidEmailError;
62
63 fn try_from(value: String) -> Result<Self, Self::Error> {
64 Email::from_str(&value)
65 }
66}
67
68impl From<Email> for String {
69 fn from(value: Email) -> Self {
70 value.0
71 }
72}
73
74impl Deref for Email {
75 type Target = str;
76
77 fn deref(&self) -> &Self::Target {
78 &self.0
79 }
80}
81
82impl Display for Email {
83 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
84 write!(f, "{}", self.0)
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use std::str::FromStr;
91
92 use fake::{Fake, Faker};
93 use fake::faker::internet::en::FreeEmail;
94 use serde::{Deserialize, Serialize};
95
96 use crate::email::Email;
97
98 #[derive(Serialize, Deserialize, PartialEq, Debug)]
99 struct User {
100 pub email: Email
101 }
102
103 #[test]
104 fn return_ok_for_valid_email() {
105 for _ in 1..30 {
106 let email = FreeEmail().fake::<String>();
107 assert!(Email::from_str(&email).is_ok());
108 }
109 }
110
111 #[test]
112 fn return_error_for_invalid_email() {
113 assert!(Email::from_str("").is_err());
114
115 for _ in 1..30 {
116 let value = get_random_string();
117 assert!(Email::from_str(&value).is_err());
118 }
119 }
120
121 #[test]
122 fn serialization_deserialization_test_for_invalid_value() {
123 let json = "{\"email\":\"invalid-email\"}".to_string();
124 match serde_json::from_str::<User>(&json) {
125 Ok(_) => panic!("error expected"),
126 Err(e) => println!("{}", e)
127 }
128 }
129
130 #[test]
131 fn use_as_str() {
132 let email = Email::from_str("a@b.com").unwrap();
133 assert_str_func(&email);
134 }
135
136 fn get_random_string() -> String {
137 Faker.fake::<String>()
138 }
139
140 fn assert_str_func(_: &str) {
141 assert!(true)
142 }
143}