email_pass 0.9.0

Email and Password Type in Rust
Documentation
use crate::errors::EmailError;

use once_cell::sync::Lazy;
use regex::Regex;

use std::fmt::{Display, Formatter};
use std::ops::Deref;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

static EMAIL_REGEX: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r"(?P<local>[a-zA-Z0-9_.+-]+)@(?P<domain>[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)").unwrap()
});

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "String"))]
#[cfg_attr(feature = "serde", serde(into = "String"))]
pub struct Email(String);

impl Email {
    pub fn new(email: &str) -> Result<Self, EmailError> {
        if !(6..=254).contains(&email.len()) {
            return Err(EmailError::Length);
        }

        if !EMAIL_REGEX.is_match(email) {
            return Err(EmailError::Format);
        }

        Ok(Self(email.to_string()))
    }
}

impl Display for Email {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl Deref for Email {
    type Target = String;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl TryFrom<String> for Email {
    type Error = EmailError;

    fn try_from(email: String) -> Result<Self, Self::Error> {
        Self::new(&email)
    }
}

impl From<Email> for String {
    fn from(email: Email) -> Self {
        email.to_string()
    }
}