mail_headers/header_components/
phrase_list.rs

1use soft_ascii_string::SoftAsciiChar;
2
3use vec1::{Vec1, Size0Error};
4
5use internals::error::EncodingError;
6use internals::encoder::{EncodingWriter, EncodableInHeader};
7use ::{HeaderTryFrom, HeaderTryInto};
8use ::error::ComponentCreationError;
9
10
11use super::Phrase;
12
13
14#[derive(Debug, Clone, Hash, Eq, PartialEq)]
15pub struct PhraseList(pub Vec1<Phrase>);
16
17impl IntoIterator for PhraseList {
18    type Item = <Vec1<Phrase> as IntoIterator>::Item;
19    type IntoIter = <Vec1<Phrase> as IntoIterator>::IntoIter;
20
21    fn into_iter(self) -> Self::IntoIter {
22        self.0.into_iter()
23    }
24}
25
26
27impl EncodableInHeader for  PhraseList {
28
29    fn encode(&self, handle: &mut EncodingWriter) -> Result<(), EncodingError> {
30        sep_for!{ word in self.0.iter();
31            sep {
32                //TODO handle this better by collapsing FWS
33                // <= isn't that allready fixed by FWS+ has content on line in EncodingBuffer
34                //Note that we do not want to write FWS as the following word might contains
35                // a left_padding with a MarkFWS, NowChar, Text " " but a space if fine
36                handle.write_char( SoftAsciiChar::from_unchecked(',') )?;
37                handle.write_char( SoftAsciiChar::from_unchecked(' ') )?;
38            };
39            word.encode( handle )?;
40
41        }
42
43        Ok( () )
44    }
45
46    fn boxed_clone(&self) -> Box<EncodableInHeader> {
47        Box::new(self.clone())
48    }
49}
50
51impl<T> HeaderTryFrom<T> for PhraseList
52    where T: HeaderTryInto<Phrase>
53{
54    fn try_from( phrase: T ) -> Result<Self, ComponentCreationError> {
55        let phrase = phrase.try_into()?;
56        Ok( PhraseList( Vec1::new( phrase ) ) )
57    }
58}
59
60
61impl<T> HeaderTryFrom<Vec<T>> for PhraseList
62    where T: HeaderTryInto<Phrase>
63{
64    fn try_from(vec: Vec<T>) -> Result<Self, ComponentCreationError> {
65        try_from_into_iter( vec )
66    }
67}
68
69fn try_from_into_iter<IT>( phrases: IT ) -> Result<PhraseList, ComponentCreationError>
70    where IT: IntoIterator, IT::Item: HeaderTryInto<Phrase>
71{
72    let mut iter = phrases.into_iter();
73    let mut vec = if let Some( first) = iter.next() {
74        Vec1::new( first.try_into()? )
75    } else {
76        return Err(
77            ComponentCreationError
78            ::from_parent(Size0Error, "PhraseList")
79        );
80    };
81    for phrase in iter {
82        vec.push( phrase.try_into()? );
83    }
84    Ok( PhraseList( vec ) )
85}
86
87//FIXME: dedup code duplication with:
88// MailboxList, PhraseList(this think here) and ?? possible future types??
89macro_rules! impl_header_try_from_array {
90    (_MBoxList 0) => ();
91    (_MBoxList $len:tt) => (
92        impl<T> HeaderTryFrom<[T; $len]> for PhraseList
93            where T: HeaderTryInto<Phrase>
94        {
95            fn try_from( vec: [T; $len] ) -> Result<Self, ComponentCreationError> {
96                //due to only supporting arrays halfheartedly for now
97                let heapified: Box<[T]> = Box::new(vec);
98                let vecified: Vec<_> = heapified.into();
99                try_from_into_iter( vecified )
100            }
101        }
102    );
103    ($($len:tt)*) => ($(
104        impl_header_try_from_array!{ _MBoxList $len }
105    )*);
106}
107
108impl_header_try_from_array! {
109     0  1  2  3  4  5  6  7  8  9
110    10 11 12 13 14 15 16 17 18 19
111    20 21 22 23 24 25 26 27 28 29
112    30 31 32
113}
114
115#[cfg(test)]
116mod test {
117    use super::*;
118
119    ec_test!{ some_phrases, {
120        PhraseList( vec1![
121            Phrase::try_from( "hy there" )?,
122            Phrase::try_from( "magic man" )?
123        ])
124    } => ascii => [
125        Text "hy",
126        MarkFWS,
127        //TODO really no FWS by the seperator??
128        // (currently it's this way as word can start with a FWS making it a double FWS)
129        Text " there, magic",
130        MarkFWS,
131        Text " man"
132    ]}
133
134    ec_test!{ some_simple_phrases_try_from, {
135        PhraseList::try_from(
136            "hy there"
137        )?
138    } => ascii => [
139        Text "hy",
140        MarkFWS,
141        Text " there"
142    ]}
143
144    ec_test!{ some_phrases_try_from, {
145        PhraseList::try_from( [
146            "hy there",
147            "magic man"
148        ] )?
149    } => ascii => [
150        Text "hy",
151        MarkFWS,
152        Text " there, magic",
153        MarkFWS,
154        Text " man"
155    ]}
156}
157