1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use std::error::Error;
use log::trace;
use regex::Regex;
use crate::{
binary::Bit,
context::{Context, ContextError, PivotByLineContext, PivotByRawLineContext},
decoder::Decoder,
encoder::{Capacity, Encoder, EncoderResult, EncodingError},
};
use super::Method;
pub const ASCII_DELIMITER: char = ' ';
pub const POSSIBLE_LINE_ENDINGS_SET: [char; 32] = [
'\u{0020}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}', '\u{2004}', '\u{2005}', '\u{2006}',
'\u{2007}', '\u{2009}', '\u{200A}', '\u{200B}', '\u{200C}', '\u{200D}', '\u{200E}', '\u{2028}',
'\u{202A}', '\u{202C}', '\u{202D}', '\u{202F}', '\u{205F}', '\u{2060}', '\u{2061}', '\u{2062}',
'\u{2063}', '\u{2064}', '\u{2066}', '\u{2068}', '\u{2069}', '\u{3000}', '\u{FEFF}', '\u{00A0}',
];
pub struct LineExtendMethod;
impl LineExtendMethod {
pub fn new() -> Self {
LineExtendMethod {}
}
}
impl Default for LineExtendMethod {
fn default() -> Self {
Self::new()
}
}
impl Capacity for LineExtendMethod {
fn bitrate(&self) -> usize {
1
}
}
impl Encoder<PivotByLineContext> for LineExtendMethod {
fn partial_encode(
&self,
context: &mut PivotByLineContext,
data: &mut dyn Iterator<Item = Bit>,
) -> Result<EncoderResult, Box<dyn Error>> {
Ok(match data.next() {
Some(Bit(1)) => {
let word = context
.next_word()
.ok_or_else(EncodingError::no_words_error)?;
trace!("Extending line with '{}'", &word);
let text = context.get_current_text_mut()?;
text.push(ASCII_DELIMITER);
text.push_str(word.as_str());
EncoderResult::Success
}
None => EncoderResult::NoDataLeft,
_ => {
trace!("Leaving line as-is");
EncoderResult::Success
}
})
}
}
impl Decoder<PivotByRawLineContext> for LineExtendMethod {
fn partial_decode(&self, context: &PivotByRawLineContext) -> Result<Vec<Bit>, ContextError> {
let repeated_whitespace_pattern = Regex::new(r"\s+").unwrap();
let cleaned_line = repeated_whitespace_pattern
.replace_all(context.get_current_text()?, " ");
let bit = if cleaned_line.trim_end_matches(&POSSIBLE_LINE_ENDINGS_SET[..]).len() > context.get_pivot() {
trace!("Line is extended over the {} length", context.get_pivot());
Bit(1)
} else {
trace!("Line not extended");
Bit(0)
};
Ok(vec![bit])
}
}
impl Method<PivotByLineContext, PivotByRawLineContext> for LineExtendMethod {}