text2art/
art_symbol.rs

1use std::hash::{Hash, Hasher};
2
3#[derive(Debug, PartialEq, Eq)]
4pub(crate) struct ArtSymbol {
5    width: u32,
6    height: u32,
7    shift: i32,
8    symbol: String,
9    lines: Vec<String>,
10    empty_line: String,
11}
12
13impl ArtSymbol {
14    pub(crate) fn new(symbol: &str, data: &str, shift: i32) -> ArtSymbol {
15        let width: u32 = data
16            .split("\\n")
17            .filter(|&x| !x.is_empty())
18            .map(str::len)
19            .max()
20            .unwrap() as u32;
21        let height: u32 = data.matches("\\n").count() as u32;
22        ArtSymbol {
23            width,
24            height,
25            shift,
26            symbol: symbol.to_owned(),
27            lines: data
28                .split("\\n")
29                .collect::<Vec<&str>>()
30                .into_iter()
31                .rev()
32                .filter(|&x| !x.is_empty())
33                .map(str::to_string)
34                .collect::<Vec<String>>(),
35            empty_line: " ".repeat(width as usize),
36        }
37    }
38
39    pub(crate) fn width(&self) -> u32 {
40        self.width
41    }
42
43    pub(crate) fn height(&self) -> u32 {
44        self.height
45    }
46
47    pub(crate) fn shift(&self) -> i32 {
48        self.shift
49    }
50
51    pub(crate) fn get_line(&self, line: i32) -> &str {
52        if line < self.shift || line > (self.height as i32 + self.shift) {
53            self.empty_line.as_str()
54        } else {
55            match self.lines.get((line - self.shift) as usize) {
56                Some(line) => line,
57                None => self.empty_line.as_str(),
58            }
59        }
60    }
61}
62
63impl Hash for ArtSymbol {
64    fn hash<H: Hasher>(&self, state: &mut H) {
65        self.symbol.hash(state);
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use crate::art_symbol;
72
73    #[test]
74    fn test_art_symbol_simple() {
75        let test_symbol = "a";
76        let test_data = "line_1\\nline_0\\n";
77        let test_shift = 0i32;
78        let asym = art_symbol::ArtSymbol::new(test_symbol, test_data, test_shift);
79
80        assert_eq!(asym.symbol, test_symbol);
81        assert_eq!(asym.shift, test_shift);
82        assert_eq!(asym.height, 2);
83        assert_eq!(asym.lines.len(), 2);
84        assert_eq!(asym.get_line(2), "      ");
85        assert_eq!(asym.get_line(1), "line_1");
86        assert_eq!(asym.get_line(0), "line_0");
87        assert_eq!(asym.get_line(-1), "      ");
88    }
89
90    #[test]
91    fn test_art_symbol_with_positive_shift() {
92        let test_symbol = "a";
93        let test_data = "line_2\\nline_1\\n";
94        let test_shift = 1i32;
95        let asym = art_symbol::ArtSymbol::new(test_symbol, test_data, test_shift);
96
97        assert_eq!(asym.symbol, test_symbol);
98        assert_eq!(asym.shift, test_shift);
99        assert_eq!(asym.height, 2);
100        assert_eq!(asym.lines.len(), 2);
101        assert_eq!(asym.get_line(3), "      ");
102        assert_eq!(asym.get_line(2), "line_2");
103        assert_eq!(asym.get_line(1), "line_1");
104        assert_eq!(asym.get_line(0), "      ");
105    }
106
107    #[test]
108    fn test_art_symbol_with_negative_shift() {
109        let test_symbol = "a";
110        let test_data = "line_0\\nline_-1\\n";
111        let test_shift = -1i32;
112        let asym = art_symbol::ArtSymbol::new(test_symbol, test_data, test_shift);
113
114        assert_eq!(asym.symbol, test_symbol);
115        assert_eq!(asym.shift, test_shift);
116        assert_eq!(asym.height, 2);
117        assert_eq!(asym.lines.len(), 2);
118        assert_eq!(asym.get_line(1), "       ");
119        assert_eq!(asym.get_line(0), "line_0");
120        assert_eq!(asym.get_line(-1), "line_-1");
121        assert_eq!(asym.get_line(-2), "       ");
122    }
123}