mail_headers_ng/header_components/utils/
text_partition.rs1use internals::grammar::{is_vchar, is_ws};
2use internals::MailType;
3
4
5#[derive(Copy, Clone, Debug, Fail, PartialEq, Eq, Hash)]
6#[fail(display = "text contained control characters")]
7pub struct PartitionError;
8
9#[derive(Copy, Clone)]
10pub enum Partition<'a> {
11 SPACE(&'a str),
13 VCHAR(&'a str)
14}
15
16#[derive(Clone, Copy, PartialEq)]
17enum Type { SPACE, VCHAR }
18
19pub fn partition<'a>( text: &'a str ) -> Result<Vec<Partition<'a>>, PartitionError> {
20 use self::Type::*;
21
22 if text.len() == 0 {
23 return Ok( Vec::new() );
24 }
25
26 let start_with_vchar = is_vchar( text.chars().next().unwrap(), MailType::Internationalized);
28
29 let mut partitions = Vec::new();
30 let mut current_type = if start_with_vchar { VCHAR } else { SPACE };
31
32 let mut start_of_current = 0;
33 for (idx, ch) in text.char_indices() {
34 if is_vchar(ch, MailType::Internationalized) {
35 if current_type == SPACE {
36 partitions.push(Partition::SPACE(&text[start_of_current..idx]));
40 start_of_current = idx;
41 current_type = VCHAR
42 }
43 } else if is_ws(ch) || ch == '\r' || ch == '\n' {
44 if current_type == VCHAR {
45 partitions.push(Partition::VCHAR(&text[start_of_current..idx]));
46 start_of_current = idx;
47 current_type = SPACE
48 }
49 } else {
50 return Err(PartitionError);
52 }
53 }
54
55
56 partitions.push( match current_type {
57 SPACE => Partition::SPACE(&text[start_of_current..]),
58 VCHAR => Partition::VCHAR(&text[start_of_current..])
59 } );
60
61 Ok( partitions )
62}