#[derive(Debug, Default)]
pub struct CodePage437 {
skip: bool,
trim: bool
}
impl CodePage437 {
pub fn new() -> Self {
Self {
skip: false,
trim: true
}
}
pub fn new_with_option(remove_empty_lines: bool) -> Self {
Self {
skip: false,
trim: remove_empty_lines
}
}
pub fn map(&mut self, raw: &[u8]) -> String {
let buffer_size = raw.len() * 2;
let mut buffer = String::with_capacity(buffer_size);
let mut pos = 0;
while pos < raw.len() {
let (step, c) = self.map_bytes(raw, pos);
pos += step;
if let Some(c) = c {
if !self.skip {
buffer += &c.to_string();
}
}
}
if self.trim {
self.remove_empty_lines(buffer)
} else if buffer.ends_with('\n') {
buffer
} else {
buffer + "\n"
}
}
fn map_bytes(&mut self, raw: &[u8], pos: usize) -> (usize, Option<char>) {
match raw[pos] {
65 => (1, Some('A')),
66 => (1, Some('B')),
67 => (1, Some('C')),
68 => (1, Some('D')),
69 => (1, Some('E')),
70 => (1, Some('F')),
77 => (1, Some('M')),
82 => (1, Some('R')),
83 => (1, Some('S')),
86 => (1, Some('V')),
87 => (1, Some('W')),
88 => (1, Some('X')),
89 => (1, Some('Y')),
90 => (1, Some('Z')),
48 => (1, Some('0')),
49 => (1, Some('1')),
50 => (1, Some('2')),
51 => (1, Some('3')),
52 => (1, Some('4')),
53 => (1, Some('5')),
54 => (1, Some('6')),
55 => (1, Some('7')),
56 => (1, Some('8')),
57 => (1, Some('9')),
4 => (1, Some('⋄')),
23 => (1, Some('↕')),
24 => (1, Some('↑')),
25 => (1, Some('↓')),
35 => (1, Some('#')),
42 => (1, Some('*')),
43 => (1, Some('+')),
45 => (1, Some('-')),
47 => (1, Some('/')),
120 => (1, Some('x')),
246 => (1, Some('÷')),
251 => (1, Some('√')),
10 => {
self.skip = false;
(1, Some('\n'))
},
13 => {
self.skip = false;
if pos + 1 < raw.len() && raw[pos + 1] == 10 {
(2, Some('\n'))
} else {
(1, Some('\n'))
}
},
39 => {
self.skip = true;
(1, None)
},
_ => (1, None)
}
}
fn remove_empty_lines(&self, input: String) -> String {
input.lines()
.filter(|s| !s.is_empty())
.map(|s| format!("{}\n", s))
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn map_upper_alpha() {
let input: Vec<u8> = vec![65, 66, 67, 68, 69, 70, 77, 82, 83, 86, 87, 88, 89, 90];
let mut cp = CodePage437::new();
let output = cp.map(&input);
assert_eq!("ABCDEFMRSVWXYZ\n", output);
}
#[test]
pub fn map_numbers() {
let input: Vec<u8> = vec![48, 49, 50, 51, 52, 53, 54, 55, 56, 57];
let mut cp = CodePage437::new();
let output = cp.map(&input);
assert_eq!("0123456789\n", output);
}
#[test]
pub fn map_symbols() {
let input: Vec<u8> = vec![4, 23, 24, 25, 42, 43, 45, 47, 120, 246, 251];
let mut cp = CodePage437::new();
let output = cp.map(&input);
assert_eq!("⋄↕↑↓*+-/x÷√\n", output);
}
#[test]
pub fn skip_everything_after_an_apostrophe() {
let input: Vec<u8> = vec![65, 66, 67, 32, 39, 68, 69, 70, 77, 82, 83, 86, 87, 88, 89, 90];
let mut cp = CodePage437::new();
let output = cp.map(&input);
assert_eq!("ABC\n", output);
}
#[test]
pub fn skip_everything_after_an_apostrophe_until_newline() {
let input: Vec<u8> = vec![65, 66, 67, 39, 68, 69, 10, 65];
let mut cp = CodePage437::new();
let output = cp.map(&input);
assert_eq!("ABC\nA\n", output);
}
#[test]
pub fn break_lines_after_carriage_return_or_line_feed_or_both() {
let input: Vec<u8> = vec![65, 10, 66, 13, 67, 10, 13, 68];
let mut cp = CodePage437::new();
let output = cp.map(&input);
assert_eq!("A\nB\nC\nD\n", output);
}
#[test]
pub fn preserve_empty_lines() {
let input: Vec<u8> = vec![65, 10, 66, 13, 67, 13, 10, 10, 68];
let mut cp = CodePage437::new_with_option(false);
let output = cp.map(&input);
assert_eq!("A\nB\nC\n\nD\n", output);
}
}