mail_headers/header_components/
mailbox_list.rs

1use 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
46//impl HeaderTryFrom<Mailbox> for OptMailboxList {
47//    fn try_from( mbox: Mailbox ) -> Result<Self> {
48//        Ok( OptMailboxList( vec![ mbox ] ) )
49//    }
50//}
51
52//impl<T> HeaderTryFrom<T> for MailboxList
53//    where T: HeaderTryInto<Mailbox>
54//{
55//    fn try_from( mbox: T ) -> Result<Self> {
56//        let mbox = mbox.try_into()?;
57//        Ok( MailboxList( Vec1::new( mbox ) ) )
58//    }
59//}
60
61//TODO-RUST-RFC: allow conflicting wildcard implementations if priority is specified
62// if done then we can implement it for IntoIterator instead of Vec and slice
63impl<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        //TODO chain vec1 Size0Error
79        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                //due to only supporting arrays halfheartedly for now
95                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
129//TODO also implement for phrase list
130macro_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                // we use the type names as variable names,
141                // not nice but it works
142                //let ($($vs),*) = src;
143                let mut out = Vec::new();
144                $(
145                    let $vs = $vs.try_into()?;
146                    out.push($vs);
147                )*
148                Ok( MailboxList(
149                    //UNWRAP_SAFE: len 0 is not implemented with the macro
150                    $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                // we use the type names as variable names,
162                // not nice but it works
163                //let ($($vs),*) = src;
164                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}