use crate::cp437::CP437Error;
use serde::{de, Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Default, Clone, PartialEq)]
pub struct CP437Char {
pub byte: u8,
pub ch: char,
}
impl From<u8> for CP437Char {
fn from(byte: u8) -> Self {
let ch = match byte {
1 => '\u{263A}',
2 => '\u{263B}',
3 => '\u{2665}',
4 => '\u{2666}',
5 => '\u{2663}',
6 => '\u{2660}',
7 => '\u{2022}',
8 => '\u{25D8}',
9 => '\u{25CB}',
10 => '\u{25D9}',
11 => '\u{2642}',
12 => '\u{2640}',
13 => '\u{266A}',
14 => '\u{266B}',
15 => '\u{263C}',
16 => '\u{25BA}',
17 => '\u{25C4}',
18 => '\u{2195}',
19 => '\u{203C}',
20 => '\u{00B6}',
21 => '\u{00A7}',
22 => '\u{25AC}',
23 => '\u{21A8}',
24 => '\u{2191}',
25 => '\u{2193}',
26 => '\u{2192}',
27 => '\u{2190}',
28 => '\u{221F}',
29 => '\u{2194}',
30 => '\u{25B2}',
31 => '\u{25BC}',
127 => '\u{2302}',
128 => '\u{00C7}',
129 => '\u{00FC}',
130 => '\u{00E9}',
131 => '\u{00E2}',
132 => '\u{00E4}',
133 => '\u{00E0}',
134 => '\u{00E5}',
135 => '\u{00E7}',
136 => '\u{00EA}',
137 => '\u{00EB}',
138 => '\u{00E8}',
139 => '\u{00EF}',
140 => '\u{00EE}',
141 => '\u{00EC}',
142 => '\u{00C4}',
143 => '\u{00C5}',
144 => '\u{00C9}',
145 => '\u{00E6}',
146 => '\u{00C6}',
147 => '\u{00F4}',
148 => '\u{00F6}',
149 => '\u{00F2}',
150 => '\u{00FB}',
151 => '\u{00F9}',
152 => '\u{00FF}',
153 => '\u{00D6}',
154 => '\u{00DC}',
155 => '\u{00A2}',
156 => '\u{00A3}',
157 => '\u{00A5}',
158 => '\u{20A7}',
159 => '\u{0192}',
160 => '\u{00E1}',
161 => '\u{00ED}',
162 => '\u{00F3}',
163 => '\u{00FA}',
164 => '\u{00F1}',
165 => '\u{00D1}',
166 => '\u{00AA}',
167 => '\u{00BA}',
168 => '\u{00BF}',
169 => '\u{2310}',
170 => '\u{00AC}',
171 => '\u{00BD}',
172 => '\u{00BC}',
173 => '\u{00A1}',
174 => '\u{00AB}',
175 => '\u{00BB}',
176 => '\u{2591}',
177 => '\u{2592}',
178 => '\u{2593}',
179 => '\u{2502}',
180 => '\u{2524}',
181 => '\u{2561}',
182 => '\u{2562}',
183 => '\u{2556}',
184 => '\u{2555}',
185 => '\u{2563}',
186 => '\u{2551}',
187 => '\u{2557}',
188 => '\u{255D}',
189 => '\u{255C}',
190 => '\u{255B}',
191 => '\u{2510}',
192 => '\u{2514}',
193 => '\u{2534}',
194 => '\u{252C}',
195 => '\u{251C}',
196 => '\u{2500}',
197 => '\u{253C}',
198 => '\u{255E}',
199 => '\u{255F}',
200 => '\u{255A}',
201 => '\u{2554}',
202 => '\u{2569}',
203 => '\u{2566}',
204 => '\u{2560}',
205 => '\u{2550}',
206 => '\u{256C}',
207 => '\u{2567}',
208 => '\u{2568}',
209 => '\u{2564}',
210 => '\u{2565}',
211 => '\u{2559}',
212 => '\u{2558}',
213 => '\u{2552}',
214 => '\u{2553}',
215 => '\u{256B}',
216 => '\u{256A}',
217 => '\u{2518}',
218 => '\u{250C}',
219 => '\u{2588}',
220 => '\u{2584}',
221 => '\u{258C}',
222 => '\u{2590}',
223 => '\u{2580}',
224 => '\u{03B1}',
225 => '\u{00DF}',
226 => '\u{0393}',
227 => '\u{03C0}',
228 => '\u{03A3}',
229 => '\u{03C3}',
230 => '\u{00B5}',
231 => '\u{03C4}',
232 => '\u{03A6}',
233 => '\u{0398}',
234 => '\u{03A9}',
235 => '\u{03B4}',
236 => '\u{221E}',
237 => '\u{03C6}',
238 => '\u{03B5}',
239 => '\u{2229}',
240 => '\u{2261}',
241 => '\u{00B1}',
242 => '\u{2265}',
243 => '\u{2264}',
244 => '\u{2320}',
245 => '\u{2321}',
246 => '\u{00F7}',
247 => '\u{2248}',
248 => '\u{00B0}',
249 => '\u{2219}',
250 => '\u{00B7}',
251 => '\u{221A}',
252 => '\u{207F}',
253 => '\u{00B2}',
254 => '\u{25A0}',
0 | 255 => '\u{0020}',
_ => byte as char,
};
CP437Char { byte, ch }
}
}
impl TryFrom<char> for CP437Char {
type Error = CP437Error;
fn try_from(ch: char) -> Result<Self, Self::Error> {
let unicode = ch as u32;
match unicode {
0x263A => Ok(CP437Char { byte: 1, ch }),
0x263B => Ok(CP437Char { byte: 2, ch }),
0x2665 => Ok(CP437Char { byte: 3, ch }),
0x2666 => Ok(CP437Char { byte: 4, ch }),
0x2663 => Ok(CP437Char { byte: 5, ch }),
0x2660 => Ok(CP437Char { byte: 6, ch }),
0x2022 => Ok(CP437Char { byte: 7, ch }),
0x25D8 => Ok(CP437Char { byte: 8, ch }),
0x25CB => Ok(CP437Char { byte: 9, ch }),
0x25D9 => Ok(CP437Char { byte: 10, ch }),
0x2642 => Ok(CP437Char { byte: 11, ch }),
0x2640 => Ok(CP437Char { byte: 12, ch }),
0x266A => Ok(CP437Char { byte: 13, ch }),
0x266B => Ok(CP437Char { byte: 14, ch }),
0x263C => Ok(CP437Char { byte: 15, ch }),
0x25BA => Ok(CP437Char { byte: 16, ch }),
0x25C4 => Ok(CP437Char { byte: 17, ch }),
0x2195 => Ok(CP437Char { byte: 18, ch }),
0x203C => Ok(CP437Char { byte: 19, ch }),
0x00B6 => Ok(CP437Char { byte: 20, ch }),
0x00A7 => Ok(CP437Char { byte: 21, ch }),
0x25AC => Ok(CP437Char { byte: 22, ch }),
0x21A8 => Ok(CP437Char { byte: 23, ch }),
0x2191 => Ok(CP437Char { byte: 24, ch }),
0x2193 => Ok(CP437Char { byte: 25, ch }),
0x2192 => Ok(CP437Char { byte: 26, ch }),
0x2190 => Ok(CP437Char { byte: 27, ch }),
0x221F => Ok(CP437Char { byte: 28, ch }),
0x2194 => Ok(CP437Char { byte: 29, ch }),
0x25B2 => Ok(CP437Char { byte: 30, ch }),
0x25BC => Ok(CP437Char { byte: 31, ch }),
0x2302 => Ok(CP437Char { byte: 127, ch }),
0x00C7 => Ok(CP437Char { byte: 128, ch }),
0x00FC => Ok(CP437Char { byte: 129, ch }),
0x00E9 => Ok(CP437Char { byte: 130, ch }),
0x00E2 => Ok(CP437Char { byte: 131, ch }),
0x00E4 => Ok(CP437Char { byte: 132, ch }),
0x00E0 => Ok(CP437Char { byte: 133, ch }),
0x00E5 => Ok(CP437Char { byte: 134, ch }),
0x00E7 => Ok(CP437Char { byte: 135, ch }),
0x00EA => Ok(CP437Char { byte: 136, ch }),
0x00EB => Ok(CP437Char { byte: 137, ch }),
0x00E8 => Ok(CP437Char { byte: 138, ch }),
0x00EF => Ok(CP437Char { byte: 139, ch }),
0x00EE => Ok(CP437Char { byte: 140, ch }),
0x00EC => Ok(CP437Char { byte: 141, ch }),
0x00C4 => Ok(CP437Char { byte: 142, ch }),
0x00C5 => Ok(CP437Char { byte: 143, ch }),
0x00C9 => Ok(CP437Char { byte: 144, ch }),
0x00E6 => Ok(CP437Char { byte: 145, ch }),
0x00C6 => Ok(CP437Char { byte: 146, ch }),
0x00F4 => Ok(CP437Char { byte: 147, ch }),
0x00F6 => Ok(CP437Char { byte: 148, ch }),
0x00F2 => Ok(CP437Char { byte: 149, ch }),
0x00FB => Ok(CP437Char { byte: 150, ch }),
0x00F9 => Ok(CP437Char { byte: 151, ch }),
0x00FF => Ok(CP437Char { byte: 152, ch }),
0x00D6 => Ok(CP437Char { byte: 153, ch }),
0x00DC => Ok(CP437Char { byte: 154, ch }),
0x00A2 => Ok(CP437Char { byte: 155, ch }),
0x00A3 => Ok(CP437Char { byte: 156, ch }),
0x00A5 => Ok(CP437Char { byte: 157, ch }),
0x20A7 => Ok(CP437Char { byte: 158, ch }),
0x0192 => Ok(CP437Char { byte: 159, ch }),
0x00E1 => Ok(CP437Char { byte: 160, ch }),
0x00ED => Ok(CP437Char { byte: 161, ch }),
0x00F3 => Ok(CP437Char { byte: 162, ch }),
0x00FA => Ok(CP437Char { byte: 163, ch }),
0x00F1 => Ok(CP437Char { byte: 164, ch }),
0x00D1 => Ok(CP437Char { byte: 165, ch }),
0x00AA => Ok(CP437Char { byte: 166, ch }),
0x00BA => Ok(CP437Char { byte: 167, ch }),
0x00BF => Ok(CP437Char { byte: 168, ch }),
0x2310 => Ok(CP437Char { byte: 169, ch }),
0x00AC => Ok(CP437Char { byte: 170, ch }),
0x00BD => Ok(CP437Char { byte: 171, ch }),
0x00BC => Ok(CP437Char { byte: 172, ch }),
0x00A1 => Ok(CP437Char { byte: 173, ch }),
0x00AB => Ok(CP437Char { byte: 174, ch }),
0x00BB => Ok(CP437Char { byte: 175, ch }),
0x2591 => Ok(CP437Char { byte: 176, ch }),
0x2592 => Ok(CP437Char { byte: 177, ch }),
0x2593 => Ok(CP437Char { byte: 178, ch }),
0x2502 => Ok(CP437Char { byte: 179, ch }),
0x2524 => Ok(CP437Char { byte: 180, ch }),
0x2561 => Ok(CP437Char { byte: 181, ch }),
0x2562 => Ok(CP437Char { byte: 182, ch }),
0x2556 => Ok(CP437Char { byte: 183, ch }),
0x2555 => Ok(CP437Char { byte: 184, ch }),
0x2563 => Ok(CP437Char { byte: 185, ch }),
0x2551 => Ok(CP437Char { byte: 186, ch }),
0x2557 => Ok(CP437Char { byte: 187, ch }),
0x255D => Ok(CP437Char { byte: 188, ch }),
0x255C => Ok(CP437Char { byte: 189, ch }),
0x255B => Ok(CP437Char { byte: 190, ch }),
0x2510 => Ok(CP437Char { byte: 191, ch }),
0x2514 => Ok(CP437Char { byte: 192, ch }),
0x2534 => Ok(CP437Char { byte: 193, ch }),
0x252C => Ok(CP437Char { byte: 194, ch }),
0x251C => Ok(CP437Char { byte: 195, ch }),
0x2500 => Ok(CP437Char { byte: 196, ch }),
0x253C => Ok(CP437Char { byte: 197, ch }),
0x255E => Ok(CP437Char { byte: 198, ch }),
0x255F => Ok(CP437Char { byte: 199, ch }),
0x255A => Ok(CP437Char { byte: 200, ch }),
0x2554 => Ok(CP437Char { byte: 201, ch }),
0x2569 => Ok(CP437Char { byte: 202, ch }),
0x2566 => Ok(CP437Char { byte: 203, ch }),
0x2560 => Ok(CP437Char { byte: 204, ch }),
0x2550 => Ok(CP437Char { byte: 205, ch }),
0x256C => Ok(CP437Char { byte: 206, ch }),
0x2567 => Ok(CP437Char { byte: 207, ch }),
0x2568 => Ok(CP437Char { byte: 208, ch }),
0x2564 => Ok(CP437Char { byte: 209, ch }),
0x2565 => Ok(CP437Char { byte: 210, ch }),
0x2559 => Ok(CP437Char { byte: 211, ch }),
0x2558 => Ok(CP437Char { byte: 212, ch }),
0x2552 => Ok(CP437Char { byte: 213, ch }),
0x2553 => Ok(CP437Char { byte: 214, ch }),
0x256B => Ok(CP437Char { byte: 215, ch }),
0x256A => Ok(CP437Char { byte: 216, ch }),
0x2518 => Ok(CP437Char { byte: 217, ch }),
0x250C => Ok(CP437Char { byte: 218, ch }),
0x2588 => Ok(CP437Char { byte: 219, ch }),
0x2584 => Ok(CP437Char { byte: 220, ch }),
0x258C => Ok(CP437Char { byte: 221, ch }),
0x2590 => Ok(CP437Char { byte: 222, ch }),
0x2580 => Ok(CP437Char { byte: 223, ch }),
0x03B1 => Ok(CP437Char { byte: 224, ch }),
0x00DF => Ok(CP437Char { byte: 225, ch }),
0x0393 => Ok(CP437Char { byte: 226, ch }),
0x03C0 => Ok(CP437Char { byte: 227, ch }),
0x03A3 => Ok(CP437Char { byte: 228, ch }),
0x03C3 => Ok(CP437Char { byte: 229, ch }),
0x00B5 => Ok(CP437Char { byte: 230, ch }),
0x03C4 => Ok(CP437Char { byte: 231, ch }),
0x03A6 => Ok(CP437Char { byte: 232, ch }),
0x0398 => Ok(CP437Char { byte: 233, ch }),
0x03A9 => Ok(CP437Char { byte: 234, ch }),
0x03B4 => Ok(CP437Char { byte: 235, ch }),
0x221E => Ok(CP437Char { byte: 236, ch }),
0x03C6 => Ok(CP437Char { byte: 237, ch }),
0x03B5 => Ok(CP437Char { byte: 238, ch }),
0x2229 => Ok(CP437Char { byte: 239, ch }),
0x2261 => Ok(CP437Char { byte: 240, ch }),
0x00B1 => Ok(CP437Char { byte: 241, ch }),
0x2265 => Ok(CP437Char { byte: 242, ch }),
0x2264 => Ok(CP437Char { byte: 243, ch }),
0x2320 => Ok(CP437Char { byte: 244, ch }),
0x2321 => Ok(CP437Char { byte: 245, ch }),
0x00F7 => Ok(CP437Char { byte: 246, ch }),
0x2248 => Ok(CP437Char { byte: 247, ch }),
0x00B0 => Ok(CP437Char { byte: 248, ch }),
0x2219 => Ok(CP437Char { byte: 249, ch }),
0x00B7 => Ok(CP437Char { byte: 250, ch }),
0x221A => Ok(CP437Char { byte: 251, ch }),
0x207F => Ok(CP437Char { byte: 252, ch }),
0x00B2 => Ok(CP437Char { byte: 253, ch }),
0x25A0 => Ok(CP437Char { byte: 254, ch }),
_ if unicode < 128 => Ok(CP437Char {
byte: unicode as u8,
ch,
}),
_ => Err(CP437Error::NoEquivalentGlyph),
}
}
}
impl fmt::Display for CP437Char {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.ch)
}
}
impl Serialize for CP437Char {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_char(self.ch)
}
}
struct CharVisitor;
impl<'de> de::Visitor<'de> for CharVisitor {
type Value = CP437Char;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("expecting a char")
}
fn visit_char<E>(self, value: char) -> Result<Self::Value, E>
where
E: de::Error,
{
match CP437Char::try_from(value) {
Ok(cp437) => Ok(cp437),
Err(err) => Err(E::custom(err)),
}
}
}
impl<'de> Deserialize<'de> for CP437Char {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_char(CharVisitor)
}
}
#[cfg(test)]
mod test {
use crate::cp437::CP437Char;
use serde_json::to_string;
#[test]
fn test() {
let a = CP437Char::try_from('☺').expect("cp437 string");
let b = CP437Char::from(1);
assert_eq!(a, b);
assert_eq!(to_string(&a).unwrap(), "\"☺\"")
}
}