mail_headers/header_components/
mailbox_list.rs1use std::iter::IntoIterator;
2use vec1::Vec1;
3use soft_ascii_string::SoftAsciiChar;
4
5use internals::error::EncodingError;
6use internals::encoder::{EncodableInHeader, EncodingWriter};
7use ::{ HeaderTryFrom, HeaderTryInto};
8use ::error::ComponentCreationError;
9
10use super::Mailbox;
11
12#[derive(Debug, Hash, Eq, PartialEq, Clone)]
13pub struct OptMailboxList( pub Vec<Mailbox> );
14
15#[derive(Debug, Hash, Eq, PartialEq, Clone)]
16pub struct MailboxList( pub Vec1<Mailbox> );
17
18impl MailboxList {
19 pub fn from_single( m: Mailbox ) -> Self {
20 MailboxList( Vec1::new( m ) )
21 }
22}
23
24impl IntoIterator for MailboxList {
25 type Item = <Vec1<Mailbox> as IntoIterator>::Item;
26 type IntoIter = <Vec1<Mailbox> as IntoIterator>::IntoIter;
27
28 fn into_iter(self) -> Self::IntoIter {
29 self.0.into_iter()
30 }
31}
32
33
34
35impl EncodableInHeader for OptMailboxList {
36
37 fn encode(&self, handle: &mut EncodingWriter) -> Result<(), EncodingError> {
38 encode_list( self.0.iter(), handle )
39 }
40
41 fn boxed_clone(&self) -> Box<EncodableInHeader> {
42 Box::new(self.clone())
43 }
44}
45
46impl<T> HeaderTryFrom<Vec<T>> for MailboxList
64 where T: HeaderTryInto<Mailbox>
65{
66 fn try_from(vec: Vec<T>) -> Result<Self, ComponentCreationError> {
67 try_from_into_iter( vec )
68 }
69}
70
71fn try_from_into_iter<IT>( mboxes: IT ) -> Result<MailboxList, ComponentCreationError>
72 where IT: IntoIterator, IT::Item: HeaderTryInto<Mailbox>
73{
74 let mut iter = mboxes.into_iter();
75 let mut vec = if let Some( first) = iter.next() {
76 Vec1::new( first.try_into()? )
77 } else {
78 return Err(ComponentCreationError::new("MailboxList"));
80 };
81 for mbox in iter {
82 vec.push( mbox.try_into()? );
83 }
84 Ok( MailboxList( vec ) )
85}
86
87macro_rules! impl_header_try_from_array {
88 (_MBoxList 0) => ();
89 (_MBoxList $len:tt) => (
90 impl<T> HeaderTryFrom<[T; $len]> for MailboxList
91 where T: HeaderTryInto<Mailbox>
92 {
93 fn try_from( vec: [T; $len] ) -> Result<Self, ComponentCreationError> {
94 let heapified: Box<[T]> = Box::new(vec);
96 let vecified: Vec<_> = heapified.into();
97 try_from_into_iter( vecified )
98 }
99 }
100 );
101 (_OptMBoxList $len:tt) => (
102 impl<T> HeaderTryFrom<[T; $len]> for OptMailboxList
103 where T: HeaderTryInto<Mailbox>
104 {
105 fn try_from( vec: [T; $len] ) -> Result<Self, ComponentCreationError> {
106 let heapified: Box<[T]> = Box::new(vec);
107 let vecified: Vec<_> = heapified.into();
108 let mut out = Vec::new();
109 for ele in vecified.into_iter() {
110 out.push( ele.try_into()? );
111 }
112 Ok( OptMailboxList( out ) )
113 }
114 }
115 );
116 ($($len:tt)*) => ($(
117 impl_header_try_from_array!{ _MBoxList $len }
118 impl_header_try_from_array!{ _OptMBoxList $len }
119 )*);
120}
121
122impl_header_try_from_array! {
123 0 1 2 3 4 5 6 7 8 9
124 10 11 12 13 14 15 16 17 18 19
125 20 21 22 23 24 25 26 27 28 29
126 30 31 32
127}
128
129macro_rules! impl_header_try_from_tuple {
131 (_MBoxList []) => (
132 compiler_error!("mailbox list needs at last one element")
133 );
134 (_MBoxList [ $($vs:ident),* ]) => (
135 impl< $($vs),* > HeaderTryFrom<( $($vs,)* )> for MailboxList
136 where $($vs: HeaderTryInto<Mailbox>),*
137 {
138 #[allow(non_snake_case)]
139 fn try_from( ($($vs,)*): ($($vs,)*) ) -> Result<Self, ComponentCreationError> {
140 let mut out = Vec::new();
144 $(
145 let $vs = $vs.try_into()?;
146 out.push($vs);
147 )*
148 Ok( MailboxList(
149 $crate::vec1::Vec1::try_from_vec(out).unwrap()
151 ) )
152 }
153 }
154 );
155 (_OptMBoxList [$($vs:ident),*]) => (
156 impl< $($vs),* > HeaderTryFrom<( $($vs,)* )> for OptMailboxList
157 where $($vs: HeaderTryInto<Mailbox>),*
158 {
159 #[allow(non_snake_case)]
160 fn try_from( ($($vs,)*): ($($vs,)*) ) -> Result<Self, ComponentCreationError> {
161 let mut out = Vec::new();
165 $(
166 let $vs = $vs.try_into()?;
167 out.push($vs);
168 )*
169 Ok( OptMailboxList( out ) )
170 }
171 }
172 );
173 ([]) => ();
174 ([$first_vs:ident $(, $vs:ident)*]) => (
175 impl_header_try_from_tuple!{ _MBoxList [$first_vs $(, $vs)* ] }
176 impl_header_try_from_tuple!{ _OptMBoxList [$first_vs $(, $vs)*] }
177 impl_header_try_from_tuple!{ [$($vs),*] }
178 );
179}
180
181impl_header_try_from_tuple! {
182 [
183 A0, A1, A2, A3, A4, A5, A6, A7,
184 A8, A9, A10, A11, A12, A13, A14, A15,
185 A16, A17, A18, A19, A20, A21, A22, A23,
186 A24, A25, A26, A27, A28, A29, A30, A31
187 ]
188}
189
190impl<T> HeaderTryFrom<Vec<T>> for OptMailboxList
191 where T: HeaderTryInto<Mailbox>
192{
193 fn try_from(vec: Vec<T>) -> Result<Self, ComponentCreationError> {
194 let mut out = Vec::new();
195 for ele in vec.into_iter() {
196 out.push( ele.try_into()? );
197 }
198 Ok( OptMailboxList( out ) )
199 }
200}
201
202impl EncodableInHeader for MailboxList {
203
204 fn encode(&self, handle: &mut EncodingWriter) -> Result<(), EncodingError> {
205 encode_list( self.0.iter(), handle )
206 }
207
208 fn boxed_clone(&self) -> Box<EncodableInHeader> {
209 Box::new(self.clone())
210 }
211}
212
213fn encode_list<'a, I>(list_iter: I, handle: &mut EncodingWriter) -> Result<(), EncodingError>
214 where I: Iterator<Item=&'a Mailbox>
215{
216 sep_for!{ mailbox in list_iter;
217 sep {
218 handle.write_char( SoftAsciiChar::from_unchecked(',') )?;
219 handle.write_fws();
220 };
221 mailbox.encode( handle )?;
222 }
223 Ok( () )
224}
225
226deref0!{ +mut OptMailboxList => Vec<Mailbox> }
227deref0!{ +mut MailboxList => Vec1<Mailbox> }
228
229#[cfg(test)]
230mod test {
231 use ::header_components::{ Mailbox, Email, Phrase };
232 use super::*;
233
234
235 ec_test! { empty_list, {
236 OptMailboxList( Vec::new() )
237 } => ascii => [
238
239 ]}
240
241 ec_test! { single, {
242 MailboxList( vec1![
243 Mailbox {
244 display_name: Some( Phrase::try_from( "hy ho" )? ),
245 email: Email::try_from( "ran@dom" )?
246 },
247 ] )
248 } => ascii => [
249 Text "hy",
250 MarkFWS,
251 Text " ho",
252 MarkFWS,
253 Text " <",
254 MarkFWS,
255 Text "ran",
256 MarkFWS,
257 Text "@",
258 MarkFWS,
259 Text "dom",
260 MarkFWS,
261 Text ">"
262 ]}
263
264 ec_test! { multiple, {
265 MailboxList( vec1![
266 Mailbox {
267 display_name: Some( Phrase::try_from( "hy ho" )? ),
268 email: Email::try_from( "nar@mod" )?
269 },
270 Mailbox {
271 display_name: None,
272 email: Email::try_from( "ran@dom" )?
273 }
274 ] )
275 } => ascii => [
276 Text "hy",
277 MarkFWS,
278 Text " ho",
279 MarkFWS,
280 Text " <",
281 MarkFWS,
282 Text "nar",
283 MarkFWS,
284 Text "@",
285 MarkFWS,
286 Text "mod",
287 MarkFWS,
288 Text ">,",
289 MarkFWS,
290 Text " <",
291 MarkFWS,
292 Text "ran",
293 MarkFWS,
294 Text "@",
295 MarkFWS,
296 Text "dom",
297 MarkFWS,
298 Text ">"
299 ]}
300}