use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
#[serde(tag = "objectType", rename = "CONTACT")]
pub struct ContactOwned {
pub email: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}
#[derive(Serialize)]
#[serde(tag = "objectType", rename = "CONTACT")]
pub struct Contact<'a> {
pub email: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<&'a str>,
}
impl<'a> From<&'a str> for Contact<'a> {
fn from(email: &'a str) -> Self {
Self { email, name: None }
}
}
pub trait ContactEmailAddrs {
fn addrs(&self) -> Vec<String>;
fn addrs_str(&self) -> String;
fn name_addrs(&self) -> Vec<String>;
}
impl ContactEmailAddrs for Vec<ContactOwned> {
fn addrs(&self) -> Vec<String> {
self.iter()
.map(|contact| contact.email.to_owned())
.collect()
}
fn addrs_str(&self) -> String {
let emails: Vec<_> = self.iter().map(|contact| contact.email.as_str()).collect();
emails.join(", ")
}
fn name_addrs(&self) -> Vec<String> {
self.iter()
.map(|contact| match &contact.name {
Some(name) => {
let mut s = String::with_capacity(name.len() + 3 + contact.email.len());
s.push_str(&name);
s.push(' ');
s.push('<');
s.push_str(&contact.email);
s.push('>');
s
}
None => contact.email.to_owned(),
})
.collect()
}
}
impl<'a> Contact<'a> {
pub fn email(mut self, email: &'a str) -> Self {
self.email = email;
self
}
pub fn name(mut self, name: &'a str) -> Self {
self.name = Some(name);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
use serde_json::{from_str, to_string_pretty};
#[test]
fn test_serialize_with_empty_email() {
let c = Contact::from("");
let result = to_string_pretty(&c).unwrap();
println!("{}", result);
assert_eq!(
result,
indoc!(
r#"
{
"objectType": "CONTACT",
"email": ""
}
"#
)
.trim()
)
}
#[test]
fn test_serialize() {
let c = Contact::from("my@email.com").name("My Name");
let result = to_string_pretty(&c).unwrap();
println!("{}", result);
assert_eq!(
result,
indoc!(
r#"
{
"objectType": "CONTACT",
"email": "my@email.com",
"name": "My Name"
}
"#
)
.trim()
)
}
#[test]
fn test_deserialize_with_name_address() {
let input = r#"
[
{
"objectType": "CONTACT",
"email": "john1@email.com",
"name": "My Name"
},
{
"objectType": "CONTACT",
"email": "john2@email.com",
"name": "Other Name"
}
]
"#;
let contacts: Vec<ContactOwned> = from_str(input).unwrap();
println!("Contacts: {:#?}", contacts);
let name_addrs = contacts.name_addrs();
assert_eq!(
name_addrs,
["My Name <john1@email.com>", "Other Name <john2@email.com>"]
);
}
}