mail_headers/header_components/
mailbox.rs1use soft_ascii_string::SoftAsciiChar;
2
3use internals::error::EncodingError;
4use internals::encoder::{EncodableInHeader, EncodingWriter};
5use ::{HeaderTryFrom, HeaderTryInto};
6use ::error::ComponentCreationError;
7
8use super::Phrase;
9use super::Email;
10
11pub struct NoDisplayName;
12
13#[derive(Debug, Hash, Eq, PartialEq, Clone)]
14pub struct Mailbox {
15 pub display_name: Option<Phrase>,
16 pub email: Email
17}
18
19impl Mailbox {
20
21 pub fn auto_gen_name<F>(&mut self, default_fn: F) -> Result<(), ComponentCreationError>
22 where F: FnOnce(&Email) -> Result<Option<Phrase>, ComponentCreationError>
23 {
24 if self.display_name.is_none() {
25 let default_name = default_fn(&self.email)?;
26 self.display_name = default_name;
27 }
28 Ok(())
29 }
30
31 pub fn with_default_name<F>(mut self, default_fn: F) -> Result<Mailbox, ComponentCreationError>
32 where F: FnOnce(&Email) -> Result<Option<Phrase>, ComponentCreationError>
33 {
34 self.auto_gen_name(default_fn)?;
35 Ok(self)
36 }
37}
38
39impl From<Email> for Mailbox {
40
41 fn from( email: Email ) -> Self {
42 Mailbox {
43 email,
44 display_name: None,
45 }
46 }
47}
48
49impl From<(Option<Phrase>, Email)> for Mailbox {
50 fn from( pair: (Option<Phrase>, Email) ) -> Self {
51 let (display_name, email) = pair;
52 Mailbox { display_name, email }
53 }
54}
55
56impl<E> HeaderTryFrom<E> for Mailbox
57 where E: HeaderTryInto<Email>
58{
59 fn try_from(email: E) -> Result<Self, ComponentCreationError> {
60 Ok( Mailbox::from( email.try_into()? ) )
61 }
62}
63
64impl<E> HeaderTryFrom<(NoDisplayName, E)> for Mailbox
65 where E: HeaderTryInto<Email>
66{
67 fn try_from( pair: (NoDisplayName, E) ) -> Result<Self, ComponentCreationError> {
68 let email = pair.1.try_into()?;
69 Ok( Mailbox { display_name: None, email } )
70 }
71}
72impl<P, E> HeaderTryFrom<(Option<P>, E)> for Mailbox
73 where P: HeaderTryInto<Phrase>, E: HeaderTryInto<Email>
74{
75 fn try_from(pair: (Option<P>, E)) -> Result<Self, ComponentCreationError> {
76 let display_name = if let Some( dn )= pair.0 {
77 Some( dn.try_into()? )
78 } else { None };
79 let email = pair.1.try_into()?;
80 Ok( Mailbox { display_name, email } )
81 }
82}
83
84impl<P, E> HeaderTryFrom<(P, E)> for Mailbox
85 where P: HeaderTryInto<Phrase>, E: HeaderTryInto<Email>
86{
87 fn try_from( pair: (P, E) ) -> Result<Self, ComponentCreationError> {
88 let display_name = Some( pair.0.try_into()? );
89 let email = pair.1.try_into()?;
90 Ok( Mailbox { display_name, email } )
91 }
92}
93
94
95impl EncodableInHeader for Mailbox {
96
97 fn encode(&self, handle: &mut EncodingWriter) -> Result<(), EncodingError> {
98 if let Some( display_name ) = self.display_name.as_ref() {
99 display_name.encode( handle )?;
100 handle.write_fws();
101 }
102 handle.write_char( SoftAsciiChar::from_unchecked('<') )?;
104 self.email.encode( handle )?;
105 handle.write_char( SoftAsciiChar::from_unchecked('>') )?;
106 Ok( () )
107 }
108
109 fn boxed_clone(&self) -> Box<EncodableInHeader> {
110 Box::new(self.clone())
111 }
112}
113
114
115#[cfg(test)]
116mod test {
117 use ::header_components::{ Email, Phrase };
118 use super::*;
119
120 ec_test!{ email_only, {
121 let email = Email::try_from( "affen@haus" )?;
122 Mailbox::from(email)
123 } => ascii => [
124 Text "<",
125 MarkFWS,
126 Text "affen",
127 MarkFWS,
128 Text "@",
129 MarkFWS,
130 Text "haus",
131 MarkFWS,
132 Text ">"
133 ]}
134
135 ec_test!{ with_display_text, {
136 Mailbox {
137 display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ),
138 email: Email::try_from( "affen@haus" ).unwrap(),
139 }
140 } => ascii => [
141 Text "ay",
142 MarkFWS,
143 Text " ya",
144 MarkFWS,
145 Text " <",
146 MarkFWS,
147 Text "affen",
148 MarkFWS,
149 Text "@",
150 MarkFWS,
151 Text "haus",
152 MarkFWS,
153 Text ">"
154 ]}
155
156
157 mod with_default_name {
158 use super::*;
159
160 #[test]
161 fn does_nothing_if_display_name_is_set() {
162 let mailbox = Mailbox {
163 display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ),
164 email: Email::try_from( "ab@cd" ).unwrap(),
165 };
166 let mailbox2 = mailbox.clone();
167 let mailbox = mailbox.with_default_name(|_| Ok(None)).unwrap();
168 assert_eq!(mailbox, mailbox2);
169 }
170
171 #[test]
172 fn generates_a_display_name_if_needed() {
173 let mailbox = Mailbox {
174 display_name: None,
175 email: Email::try_from( "ab@cd" ).unwrap(),
176 };
177 let mailbox = mailbox.with_default_name(|email| {
178 assert_eq!(email, &Email::try_from( "ab@cd" ).unwrap());
179 Ok(Some(Phrase::try_from( "ay ya" )?))
180 }).unwrap();
181
182 assert_eq!(mailbox, Mailbox {
183 display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ),
184 email: Email::try_from( "ab@cd" ).unwrap(),
185 });
186 }
187
188 #[test]
189 fn can_decide_to_not_generate_a_name() {
190 let mailbox = Mailbox {
191 display_name: None,
192 email: Email::try_from( "ab@cd" ).unwrap(),
193 };
194 let new_mailbox = mailbox.clone().with_default_name(|_| Ok(None)).unwrap();
195 assert_eq!(mailbox, new_mailbox);
196 }
197
198 #[test]
199 fn forward_errors() {
200 let mailbox = Mailbox {
201 display_name: None,
202 email: Email::try_from( "ab@cd" ).unwrap(),
203 };
204 let result = mailbox.clone().with_default_name(|_| {
205 Err(ComponentCreationError::new("DisplayName"))
206 });
207 let err = assert_err!(result);
208 assert_eq!(err.to_string(), "creating component DisplayName failed");
209 }
210 }
211}
212