diff options
Diffstat (limited to 'headers/src/header_components/mailbox.rs')
-rw-r--r-- | headers/src/header_components/mailbox.rs | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/headers/src/header_components/mailbox.rs b/headers/src/header_components/mailbox.rs new file mode 100644 index 0000000..fa1e34d --- /dev/null +++ b/headers/src/header_components/mailbox.rs @@ -0,0 +1,212 @@ +use soft_ascii_string::SoftAsciiChar; + +use internals::error::EncodingError; +use internals::encoder::{EncodableInHeader, EncodingWriter}; +use ::{HeaderTryFrom, HeaderTryInto}; +use ::error::ComponentCreationError; + +use super::Phrase; +use super::Email; + +pub struct NoDisplayName; + +#[derive(Debug, Hash, Eq, PartialEq, Clone)] +pub struct Mailbox { + pub display_name: Option<Phrase>, + pub email: Email +} + +impl Mailbox { + + pub fn auto_gen_name<F>(&mut self, default_fn: F) -> Result<(), ComponentCreationError> + where F: FnOnce(&Email) -> Result<Option<Phrase>, ComponentCreationError> + { + if self.display_name.is_none() { + let default_name = default_fn(&self.email)?; + self.display_name = default_name; + } + Ok(()) + } + + pub fn with_default_name<F>(mut self, default_fn: F) -> Result<Mailbox, ComponentCreationError> + where F: FnOnce(&Email) -> Result<Option<Phrase>, ComponentCreationError> + { + self.auto_gen_name(default_fn)?; + Ok(self) + } +} + +impl From<Email> for Mailbox { + + fn from( email: Email ) -> Self { + Mailbox { + email, + display_name: None, + } + } +} + +impl From<(Option<Phrase>, Email)> for Mailbox { + fn from( pair: (Option<Phrase>, Email) ) -> Self { + let (display_name, email) = pair; + Mailbox { display_name, email } + } +} + +impl<E> HeaderTryFrom<E> for Mailbox + where E: HeaderTryInto<Email> +{ + fn try_from(email: E) -> Result<Self, ComponentCreationError> { + Ok( Mailbox::from( email.try_into()? ) ) + } +} + +impl<E> HeaderTryFrom<(NoDisplayName, E)> for Mailbox + where E: HeaderTryInto<Email> +{ + fn try_from( pair: (NoDisplayName, E) ) -> Result<Self, ComponentCreationError> { + let email = pair.1.try_into()?; + Ok( Mailbox { display_name: None, email } ) + } +} +impl<P, E> HeaderTryFrom<(Option<P>, E)> for Mailbox + where P: HeaderTryInto<Phrase>, E: HeaderTryInto<Email> +{ + fn try_from(pair: (Option<P>, E)) -> Result<Self, ComponentCreationError> { + let display_name = if let Some( dn )= pair.0 { + Some( dn.try_into()? ) + } else { None }; + let email = pair.1.try_into()?; + Ok( Mailbox { display_name, email } ) + } +} + +impl<P, E> HeaderTryFrom<(P, E)> for Mailbox + where P: HeaderTryInto<Phrase>, E: HeaderTryInto<Email> +{ + fn try_from( pair: (P, E) ) -> Result<Self, ComponentCreationError> { + let display_name = Some( pair.0.try_into()? ); + let email = pair.1.try_into()?; + Ok( Mailbox { display_name, email } ) + } +} + + +impl EncodableInHeader for Mailbox { + + fn encode(&self, handle: &mut EncodingWriter) -> Result<(), EncodingError> { + if let Some( display_name ) = self.display_name.as_ref() { + display_name.encode( handle )?; + handle.write_fws(); + } + //for now this always uses the "<user@do.main>" form even if no display-name is given + handle.write_char( SoftAsciiChar::from_unchecked('<') )?; + self.email.encode( handle )?; + handle.write_char( SoftAsciiChar::from_unchecked('>') )?; + Ok( () ) + } + + fn boxed_clone(&self) -> Box<EncodableInHeader> { + Box::new(self.clone()) + } +} + + +#[cfg(test)] +mod test { + use ::header_components::{ Email, Phrase }; + use super::*; + + ec_test!{ email_only, { + let email = Email::try_from( "affen@haus" )?; + Mailbox::from(email) + } => ascii => [ + Text "<", + MarkFWS, + Text "affen", + MarkFWS, + Text "@", + MarkFWS, + Text "haus", + MarkFWS, + Text ">" + ]} + + ec_test!{ with_display_text, { + Mailbox { + display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ), + email: Email::try_from( "affen@haus" ).unwrap(), + } + } => ascii => [ + Text "ay", + MarkFWS, + Text " ya", + MarkFWS, + Text " <", + MarkFWS, + Text "affen", + MarkFWS, + Text "@", + MarkFWS, + Text "haus", + MarkFWS, + Text ">" + ]} + + + mod with_default_name { + use super::*; + + #[test] + fn does_nothing_if_display_name_is_set() { + let mailbox = Mailbox { + display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ), + email: Email::try_from( "ab@cd" ).unwrap(), + }; + let mailbox2 = mailbox.clone(); + let mailbox = mailbox.with_default_name(|_| Ok(None)).unwrap(); + assert_eq!(mailbox, mailbox2); + } + + #[test] + fn generates_a_display_name_if_needed() { + let mailbox = Mailbox { + display_name: None, + email: Email::try_from( "ab@cd" ).unwrap(), + }; + let mailbox = mailbox.with_default_name(|email| { + assert_eq!(email, &Email::try_from( "ab@cd" ).unwrap()); + Ok(Some(Phrase::try_from( "ay ya" )?)) + }).unwrap(); + + assert_eq!(mailbox, Mailbox { + display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ), + email: Email::try_from( "ab@cd" ).unwrap(), + }); + } + + #[test] + fn can_decide_to_not_generate_a_name() { + let mailbox = Mailbox { + display_name: None, + email: Email::try_from( "ab@cd" ).unwrap(), + }; + let new_mailbox = mailbox.clone().with_default_name(|_| Ok(None)).unwrap(); + assert_eq!(mailbox, new_mailbox); + } + + #[test] + fn forward_errors() { + let mailbox = Mailbox { + display_name: None, + email: Email::try_from( "ab@cd" ).unwrap(), + }; + let result = mailbox.clone().with_default_name(|_| { + Err(ComponentCreationError::new("DisplayName")) + }); + let err = assert_err!(result); + assert_eq!(err.to_string(), "creating component DisplayName failed"); + } + } +} + |