summaryrefslogtreecommitdiff
path: root/protocol/src/member/email.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-03-18 11:19:51 +0800
committer魏曹先生 <1992414357@qq.com>2026-03-18 11:19:51 +0800
commit2372495e1a0acb9ffead7651d8ed36a3bb98a15b (patch)
tree5f330cdf1616b1e56a7b85b2b2530cdf1422ed54 /protocol/src/member/email.rs
parent6f8906f06f3efd009275dc23f861f5aaba76ce72 (diff)
Add new protocol crate with basic types and operations
Diffstat (limited to 'protocol/src/member/email.rs')
-rw-r--r--protocol/src/member/email.rs74
1 files changed, 74 insertions, 0 deletions
diff --git a/protocol/src/member/email.rs b/protocol/src/member/email.rs
new file mode 100644
index 0000000..a3b829f
--- /dev/null
+++ b/protocol/src/member/email.rs
@@ -0,0 +1,74 @@
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+
+use crate::member::error::EMailAddressParseError;
+use std::fmt::{Display, Formatter};
+
+#[derive(Clone, Debug, Eq)]
+pub struct EMailAddress {
+ account: String,
+ domain: String,
+}
+
+impl std::hash::Hash for EMailAddress {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.account.hash(state);
+ self.domain.hash(state);
+ }
+}
+
+impl PartialEq for EMailAddress {
+ fn eq(&self, other: &Self) -> bool {
+ self.account == other.account && self.domain == other.domain
+ }
+}
+
+impl Display for EMailAddress {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}@{}", self.account, self.domain)
+ }
+}
+
+impl TryFrom<&str> for EMailAddress {
+ type Error = EMailAddressParseError;
+
+ fn try_from(value: &str) -> Result<Self, Self::Error> {
+ let trimmed_value = value.trim();
+ let parts: Vec<&str> = trimmed_value.split('@').collect();
+ if parts.len() != 2 {
+ return Err(EMailAddressParseError::InvalidFormat);
+ }
+ let account = parts[0].trim().to_string();
+ let domain = parts[1].trim().to_string();
+ if account.is_empty() || domain.is_empty() {
+ return Err(EMailAddressParseError::EmptyPart);
+ }
+ Ok(Self { account, domain })
+ }
+}
+
+impl TryFrom<String> for EMailAddress {
+ type Error = EMailAddressParseError;
+
+ fn try_from(value: String) -> Result<Self, Self::Error> {
+ Self::try_from(value.as_str())
+ }
+}
+
+impl Serialize for EMailAddress {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_str(&self.to_string())
+ }
+}
+
+impl<'de> Deserialize<'de> for EMailAddress {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let s = String::deserialize(deserializer)?;
+ EMailAddress::try_from(s).map_err(serde::de::Error::custom)
+ }
+}