use ::std::convert::AsRef;
use ::std::convert::From;
use ::std::fmt::Debug;
use ::std::fmt::Display;
use ::std::fmt::Formatter;
use ::std::fmt::Result as FmtResult;
use ::std::str::FromStr;
use crate::is_valid_email;
use crate::EmailError;
#[cfg(feature = "serde")]
mod email_visitor;
#[cfg(feature = "serde")]
pub(crate) use self::email_visitor::*;
#[cfg(feature = "serde")]
mod serde_support;
#[cfg(feature = "sea-orm")]
mod sea_orm_support;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Email {
raw_email: String,
}
impl Email {
pub fn from_string(raw_email: String) -> Result<Self, EmailError> {
if !is_valid_email(&raw_email) {
let err = EmailError::Invalid { raw_email };
return Err(err);
}
Ok(Self { raw_email })
}
pub fn from_str<S>(raw_email: S) -> Result<Self, EmailError>
where
S: AsRef<str>,
{
Self::from_string(raw_email.as_ref().to_string())
}
pub fn to_lowercase(&self) -> Self {
Self {
raw_email: self.raw_email.to_lowercase(),
}
}
pub fn to_uppercase(&self) -> Self {
Self {
raw_email: self.raw_email.to_uppercase(),
}
}
pub fn as_str<'a>(&'a self) -> &'a str {
&self.raw_email
}
}
impl Default for Email {
fn default() -> Self {
Self::from_str("default@example.com").expect("Default Email should always be valid")
}
}
impl Display for Email {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{}", self.raw_email)
}
}
impl From<Email> for String {
fn from(email: Email) -> Self {
email.raw_email
}
}
impl AsRef<str> for Email {
fn as_ref(&self) -> &str {
&self.raw_email
}
}
impl AsRef<String> for Email {
fn as_ref(&self) -> &String {
&self.raw_email
}
}
impl FromStr for Email {
type Err = EmailError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Email::from_str(s)
}
}
impl TryFrom<String> for Email {
type Error = EmailError;
fn try_from(raw: String) -> Result<Self, Self::Error> {
Email::from_string(raw)
}
}
impl<'a> TryFrom<&'a str> for Email {
type Error = EmailError;
fn try_from(raw: &'a str) -> Result<Self, Self::Error> {
Email::from_str(raw)
}
}
impl<'a> PartialEq<&'a str> for Email {
fn eq(&self, other: &&'a str) -> bool {
self.raw_email == *other
}
}
impl PartialEq<String> for Email {
fn eq(&self, other: &String) -> bool {
self.raw_email == *other
}
}
#[cfg(test)]
mod test_from_string {
use super::*;
#[test]
fn it_should_accept_a_valid_email() {
let maybe_email = Email::from_string("john@example.com".to_string());
assert!(maybe_email.is_ok());
}
#[test]
fn it_should_not_accept_a_non_valid_email() {
let maybe_email = Email::from_string("foxes".to_string());
assert!(maybe_email.is_err());
}
#[test]
fn it_should_not_accept_a_domain_on_its_own() {
let maybe_email = Email::from_string("@example.com".to_string());
assert!(maybe_email.is_err());
}
#[test]
fn it_should_not_accept_a_user_part_on_its_own() {
let maybe_email = Email::from_string("john@".to_string());
assert!(maybe_email.is_err());
}
#[test]
fn it_should_not_accept_an_empty_string() {
let maybe_email = Email::from_string("".to_string());
assert!(maybe_email.is_err());
}
}
#[cfg(test)]
mod test_from_str {
use super::*;
#[test]
fn it_should_accept_a_valid_email() {
let maybe_email = Email::from_str("john@example.com");
assert!(maybe_email.is_ok());
}
#[test]
fn it_should_not_accept_a_non_valid_email() {
let maybe_email = Email::from_str("foxes");
assert!(maybe_email.is_err());
}
}
#[cfg(test)]
mod test_try_from {
use super::*;
#[test]
fn it_should_parse_valid_email_from_str() {
let email: Email = "fox@example.com".try_into().unwrap();
assert_eq!(email, "fox@example.com");
}
#[test]
fn it_should_not_parse_invalid_email_from_str() {
let maybe_email: Result<Email, EmailError> = "🦊🦊🦊".try_into();
assert!(maybe_email.is_err());
}
#[test]
fn it_should_parse_valid_email_from_string() {
let email: Email = "fox@example.com".to_string().try_into().unwrap();
assert_eq!(email, "fox@example.com");
}
#[test]
fn it_should_not_parse_invalid_email_from_string() {
let maybe_email: Result<Email, EmailError> = "🦊🦊🦊".to_string().try_into();
assert!(maybe_email.is_err());
}
}
#[cfg(test)]
mod test_parse {
use super::*;
#[test]
fn it_should_parse_valid_email_from_string() {
let email: Email = "fox@example.com".parse().unwrap();
assert_eq!(email, "fox@example.com");
}
#[test]
fn it_should_not_parse_invalid_email_from_string() {
let maybe_email: Result<Email, EmailError> = "🦊🦊🦊".parse();
assert!(maybe_email.is_err());
}
}
#[cfg(test)]
mod test_display {
use super::*;
#[test]
fn it_should_write_same_email_as_given() {
let email: Email = "fox@example.com".parse().unwrap();
let output: String = format!("{}", email);
assert!(email == output);
assert_eq!(output, "fox@example.com");
}
}
#[cfg(test)]
mod test_default {
use super::*;
#[test]
fn it_should_create_a_valid_default() {
let email = Email::default();
assert!(is_valid_email(&email));
}
}
#[cfg(test)]
mod test_to_lowercase {
use super::*;
#[test]
fn it_should_make_it_lowercase() {
let email: Email = "JoE@eXaMpLe.com".parse().unwrap();
assert_eq!(
email.to_lowercase(),
Email::from_str("joe@example.com").unwrap()
);
}
#[test]
fn it_should_not_change_already_lowercase() {
let email: Email = "joe@example.com".parse().unwrap();
assert_eq!(
email.to_lowercase(),
Email::from_str("joe@example.com").unwrap()
);
}
}
#[cfg(test)]
mod test_to_uppercase {
use super::*;
#[test]
fn it_should_make_it_uppercase() {
let email: Email = "JoE@eXaMpLe.com".parse().unwrap();
assert_eq!(
email.to_uppercase(),
Email::from_str("JOE@EXAMPLE.COM").unwrap()
);
}
#[test]
fn it_should_not_change_already_uppercase() {
let email: Email = "joe@example.com".parse().unwrap();
assert_eq!(
email.to_uppercase(),
Email::from_str("JOE@EXAMPLE.COM").unwrap()
);
}
}
#[cfg(test)]
mod test_partial_eq {
use super::*;
#[test]
fn it_should_be_equal_to_strs() {
let email: Email = "joe@example.com".parse().unwrap();
let is_equal = email == "joe@example.com";
assert!(is_equal);
}
#[test]
fn it_should_not_be_equal_to_different_strs() {
let email: Email = "joe@example.com".parse().unwrap();
let is_not_equal = email != "🦊@example.com";
assert!(is_not_equal);
}
}