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}