1use std::fmt;
2
3#[rustfmt::skip]
5pub const CP437CHARS: &[char] = &[
6 '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '◙', '♂', '♀', '♪', '♫', '☼',
7 '►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼',
8 ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
9 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
10 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
11 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
12 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
13 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '⌂',
14 'Ç', 'ü', 'é', 'â', 'ä', 'à', 'å', 'ç', 'ê', 'ë', 'è', 'ï', 'î', 'ì', 'Ä', 'Å',
15 'É', 'æ', 'Æ', 'ô', 'ö', 'ò', 'û', 'ù', 'ÿ', 'Ö', 'Ü', '¢', '£', '¥', '₧', 'ƒ',
16 'á', 'í', 'ó', 'ú', 'ñ', 'Ñ', 'ª', 'º', '¿', '⌐', '¬', '½', '¼', '¡', '«', '»',
17 '░', '▒', '▓', '│', '┤', '╡', '╢', '╖', '╕', '╣', '║', '╗', '╝', '╜', '╛', '┐',
18 '└', '┴', '┬', '├', '─', '┼', '╞', '╟', '╚', '╔', '╩', '╦', '╠', '═', '╬', '╧',
19 '╨', '╤', '╥', '╙', '╘', '╒', '╓', '╫', '╪', '┘', '┌', '█', '▄', '▌', '▐', '▀',
20 'α', 'ß', 'Γ', 'π', 'Σ', 'σ', 'µ', 'τ', 'Φ', 'Θ', 'Ω', 'δ', '∞', 'φ', 'ε', '∩',
21 '≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∙', '·', '√', 'ⁿ', '²', '■', '\u{a0}'
22];
23
24#[repr(transparent)]
25#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
26pub struct CP437Char(u8);
27
28impl CP437Char {
29 #[must_use]
30 #[inline]
31 pub const fn from_byte(val: u8) -> Self {
32 Self(val)
33 }
34
35 #[must_use]
36 #[inline]
37 pub const fn to_byte(self) -> u8 {
38 self.0
39 }
40
41 #[must_use]
42 pub const fn location(self) -> (u8, u8) {
43 (self.0 % 16, self.0 / (16))
44 }
45
46 #[must_use]
47 #[expect(
48 clippy::too_many_lines,
49 reason = "It's just one massive match statement"
50 )]
51 pub const fn from_char(char: char) -> Option<Self> {
52 match char {
53 '\0' => Some(Self(0)),
54 '☺' => Some(Self(1)),
55 '☻' => Some(Self(2)),
56 '♥' => Some(Self(3)),
57 '♦' => Some(Self(4)),
58 '♣' => Some(Self(5)),
59 '♠' => Some(Self(6)),
60 '•' => Some(Self(7)),
61 '◘' => Some(Self(8)),
62 '○' => Some(Self(9)),
63 '◙' => Some(Self(10)),
64 '♂' => Some(Self(11)),
65 '♀' => Some(Self(12)),
66 '♪' => Some(Self(13)),
67 '♫' => Some(Self(14)),
68 '☼' => Some(Self(15)),
69 '►' => Some(Self(16)),
70 '◄' => Some(Self(17)),
71 '↕' => Some(Self(18)),
72 '‼' => Some(Self(19)),
73 '¶' => Some(Self(20)),
74 '§' => Some(Self(21)),
75 '▬' => Some(Self(22)),
76 '↨' => Some(Self(23)),
77 '↑' => Some(Self(24)),
78 '↓' => Some(Self(25)),
79 '→' => Some(Self(26)),
80 '←' => Some(Self(27)),
81 '∟' => Some(Self(28)),
82 '↔' => Some(Self(29)),
83 '▲' => Some(Self(30)),
84 '▼' => Some(Self(31)),
85 ' ' => Some(Self(32)),
86 '!' => Some(Self(33)),
87 '"' => Some(Self(34)),
88 '#' => Some(Self(35)),
89 '$' => Some(Self(36)),
90 '%' => Some(Self(37)),
91 '&' => Some(Self(38)),
92 '\'' => Some(Self(39)),
93 '(' => Some(Self(40)),
94 ')' => Some(Self(41)),
95 '*' => Some(Self(42)),
96 '+' => Some(Self(43)),
97 ',' => Some(Self(44)),
98 '-' => Some(Self(45)),
99 '.' => Some(Self(46)),
100 '/' => Some(Self(47)),
101 '0' => Some(Self(48)),
102 '1' => Some(Self(49)),
103 '2' => Some(Self(50)),
104 '3' => Some(Self(51)),
105 '4' => Some(Self(52)),
106 '5' => Some(Self(53)),
107 '6' => Some(Self(54)),
108 '7' => Some(Self(55)),
109 '8' => Some(Self(56)),
110 '9' => Some(Self(57)),
111 ':' => Some(Self(58)),
112 ';' => Some(Self(59)),
113 '<' => Some(Self(60)),
114 '=' => Some(Self(61)),
115 '>' => Some(Self(62)),
116 '?' => Some(Self(63)),
117 '@' => Some(Self(64)),
118 'A' => Some(Self(65)),
119 'B' => Some(Self(66)),
120 'C' => Some(Self(67)),
121 'D' => Some(Self(68)),
122 'E' => Some(Self(69)),
123 'F' => Some(Self(70)),
124 'G' => Some(Self(71)),
125 'H' => Some(Self(72)),
126 'I' => Some(Self(73)),
127 'J' => Some(Self(74)),
128 'K' => Some(Self(75)),
129 'L' => Some(Self(76)),
130 'M' => Some(Self(77)),
131 'N' => Some(Self(78)),
132 'O' => Some(Self(79)),
133 'P' => Some(Self(80)),
134 'Q' => Some(Self(81)),
135 'R' => Some(Self(82)),
136 'S' => Some(Self(83)),
137 'T' => Some(Self(84)),
138 'U' => Some(Self(85)),
139 'V' => Some(Self(86)),
140 'W' => Some(Self(87)),
141 'X' => Some(Self(88)),
142 'Y' => Some(Self(89)),
143 'Z' => Some(Self(90)),
144 '[' => Some(Self(91)),
145 '\\' => Some(Self(92)),
146 ']' => Some(Self(93)),
147 '^' => Some(Self(94)),
148 '_' => Some(Self(95)),
149 '`' => Some(Self(96)),
150 'a' => Some(Self(97)),
151 'b' => Some(Self(98)),
152 'c' => Some(Self(99)),
153 'd' => Some(Self(100)),
154 'e' => Some(Self(101)),
155 'f' => Some(Self(102)),
156 'g' => Some(Self(103)),
157 'h' => Some(Self(104)),
158 'i' => Some(Self(105)),
159 'j' => Some(Self(106)),
160 'k' => Some(Self(107)),
161 'l' => Some(Self(108)),
162 'm' => Some(Self(109)),
163 'n' => Some(Self(110)),
164 'o' => Some(Self(111)),
165 'p' => Some(Self(112)),
166 'q' => Some(Self(113)),
167 'r' => Some(Self(114)),
168 's' => Some(Self(115)),
169 't' => Some(Self(116)),
170 'u' => Some(Self(117)),
171 'v' => Some(Self(118)),
172 'w' => Some(Self(119)),
173 'x' => Some(Self(120)),
174 'y' => Some(Self(121)),
175 'z' => Some(Self(122)),
176 '{' => Some(Self(123)),
177 '|' => Some(Self(124)),
178 '}' => Some(Self(125)),
179 '~' => Some(Self(126)),
180 '⌂' => Some(Self(127)),
181 'Ç' => Some(Self(128)),
182 'ü' => Some(Self(129)),
183 'é' => Some(Self(130)),
184 'â' => Some(Self(131)),
185 'ä' => Some(Self(132)),
186 'à' => Some(Self(133)),
187 'å' => Some(Self(134)),
188 'ç' => Some(Self(135)),
189 'ê' => Some(Self(136)),
190 'ë' => Some(Self(137)),
191 'è' => Some(Self(138)),
192 'ï' => Some(Self(139)),
193 'î' => Some(Self(140)),
194 'ì' => Some(Self(141)),
195 'Ä' => Some(Self(142)),
196 'Å' => Some(Self(143)),
197 'É' => Some(Self(144)),
198 'æ' => Some(Self(145)),
199 'Æ' => Some(Self(146)),
200 'ô' => Some(Self(147)),
201 'ö' => Some(Self(148)),
202 'ò' => Some(Self(149)),
203 'û' => Some(Self(150)),
204 'ù' => Some(Self(151)),
205 'ÿ' => Some(Self(152)),
206 'Ö' => Some(Self(153)),
207 'Ü' => Some(Self(154)),
208 '¢' => Some(Self(155)),
209 '£' => Some(Self(156)),
210 '¥' => Some(Self(157)),
211 '₧' => Some(Self(158)),
212 'ƒ' => Some(Self(159)),
213 'á' => Some(Self(160)),
214 'í' => Some(Self(161)),
215 'ó' => Some(Self(162)),
216 'ú' => Some(Self(163)),
217 'ñ' => Some(Self(164)),
218 'Ñ' => Some(Self(165)),
219 'ª' => Some(Self(166)),
220 'º' => Some(Self(167)),
221 '¿' => Some(Self(168)),
222 '⌐' => Some(Self(169)),
223 '¬' => Some(Self(170)),
224 '½' => Some(Self(171)),
225 '¼' => Some(Self(172)),
226 '¡' => Some(Self(173)),
227 '«' => Some(Self(174)),
228 '»' => Some(Self(175)),
229 '░' => Some(Self(176)),
230 '▒' => Some(Self(177)),
231 '▓' => Some(Self(178)),
232 '│' => Some(Self(179)),
233 '┤' => Some(Self(180)),
234 '╡' => Some(Self(181)),
235 '╢' => Some(Self(182)),
236 '╖' => Some(Self(183)),
237 '╕' => Some(Self(184)),
238 '╣' => Some(Self(185)),
239 '║' => Some(Self(186)),
240 '╗' => Some(Self(187)),
241 '╝' => Some(Self(188)),
242 '╜' => Some(Self(189)),
243 '╛' => Some(Self(190)),
244 '┐' => Some(Self(191)),
245 '└' => Some(Self(192)),
246 '┴' => Some(Self(193)),
247 '┬' => Some(Self(194)),
248 '├' => Some(Self(195)),
249 '─' => Some(Self(196)),
250 '┼' => Some(Self(197)),
251 '╞' => Some(Self(198)),
252 '╟' => Some(Self(199)),
253 '╚' => Some(Self(200)),
254 '╔' => Some(Self(201)),
255 '╩' => Some(Self(202)),
256 '╦' => Some(Self(203)),
257 '╠' => Some(Self(204)),
258 '═' => Some(Self(205)),
259 '╬' => Some(Self(206)),
260 '╧' => Some(Self(207)),
261 '╨' => Some(Self(208)),
262 '╤' => Some(Self(209)),
263 '╥' => Some(Self(210)),
264 '╙' => Some(Self(211)),
265 '╘' => Some(Self(212)),
266 '╒' => Some(Self(213)),
267 '╓' => Some(Self(214)),
268 '╫' => Some(Self(215)),
269 '╪' => Some(Self(216)),
270 '┘' => Some(Self(217)),
271 '┌' => Some(Self(218)),
272 '█' => Some(Self(219)),
273 '▄' => Some(Self(220)),
274 '▌' => Some(Self(221)),
275 '▐' => Some(Self(222)),
276 '▀' => Some(Self(223)),
277 'α' => Some(Self(224)),
278 'ß' => Some(Self(225)),
279 'Γ' => Some(Self(226)),
280 'π' => Some(Self(227)),
281 'Σ' => Some(Self(228)),
282 'σ' => Some(Self(229)),
283 'µ' => Some(Self(230)),
284 'τ' => Some(Self(231)),
285 'Φ' => Some(Self(232)),
286 'Θ' => Some(Self(233)),
287 'Ω' => Some(Self(234)),
288 'δ' => Some(Self(235)),
289 '∞' => Some(Self(236)),
290 'φ' => Some(Self(237)),
291 'ε' => Some(Self(238)),
292 '∩' => Some(Self(239)),
293 '≡' => Some(Self(240)),
294 '±' => Some(Self(241)),
295 '≥' => Some(Self(242)),
296 '≤' => Some(Self(243)),
297 '⌠' => Some(Self(244)),
298 '⌡' => Some(Self(245)),
299 '÷' => Some(Self(246)),
300 '≈' => Some(Self(247)),
301 '°' => Some(Self(248)),
302 '∙' => Some(Self(249)),
303 '·' => Some(Self(250)),
304 '√' => Some(Self(251)),
305 'ⁿ' => Some(Self(252)),
306 '²' => Some(Self(253)),
307 '■' => Some(Self(254)),
308 '\u{a0}' => Some(Self(255)),
309 _ => None,
310 }
311 }
312
313 #[must_use]
314 #[expect(
315 clippy::too_many_lines,
316 reason = "It's just one massive match statement"
317 )]
318 pub const fn to_char(self) -> char {
319 match self {
320 Self(0) => '\0',
321 Self(1) => '☺',
322 Self(2) => '☻',
323 Self(3) => '♥',
324 Self(4) => '♦',
325 Self(5) => '♣',
326 Self(6) => '♠',
327 Self(7) => '•',
328 Self(8) => '◘',
329 Self(9) => '○',
330 Self(10) => '◙',
331 Self(11) => '♂',
332 Self(12) => '♀',
333 Self(13) => '♪',
334 Self(14) => '♫',
335 Self(15) => '☼',
336 Self(16) => '►',
337 Self(17) => '◄',
338 Self(18) => '↕',
339 Self(19) => '‼',
340 Self(20) => '¶',
341 Self(21) => '§',
342 Self(22) => '▬',
343 Self(23) => '↨',
344 Self(24) => '↑',
345 Self(25) => '↓',
346 Self(26) => '→',
347 Self(27) => '←',
348 Self(28) => '∟',
349 Self(29) => '↔',
350 Self(30) => '▲',
351 Self(31) => '▼',
352 Self(32) => ' ',
353 Self(33) => '!',
354 Self(34) => '"',
355 Self(35) => '#',
356 Self(36) => '$',
357 Self(37) => '%',
358 Self(38) => '&',
359 Self(39) => '\'',
360 Self(40) => '(',
361 Self(41) => ')',
362 Self(42) => '*',
363 Self(43) => '+',
364 Self(44) => ',',
365 Self(45) => '-',
366 Self(46) => '.',
367 Self(47) => '/',
368 Self(48) => '0',
369 Self(49) => '1',
370 Self(50) => '2',
371 Self(51) => '3',
372 Self(52) => '4',
373 Self(53) => '5',
374 Self(54) => '6',
375 Self(55) => '7',
376 Self(56) => '8',
377 Self(57) => '9',
378 Self(58) => ':',
379 Self(59) => ';',
380 Self(60) => '<',
381 Self(61) => '=',
382 Self(62) => '>',
383 Self(63) => '?',
384 Self(64) => '@',
385 Self(65) => 'A',
386 Self(66) => 'B',
387 Self(67) => 'C',
388 Self(68) => 'D',
389 Self(69) => 'E',
390 Self(70) => 'F',
391 Self(71) => 'G',
392 Self(72) => 'H',
393 Self(73) => 'I',
394 Self(74) => 'J',
395 Self(75) => 'K',
396 Self(76) => 'L',
397 Self(77) => 'M',
398 Self(78) => 'N',
399 Self(79) => 'O',
400 Self(80) => 'P',
401 Self(81) => 'Q',
402 Self(82) => 'R',
403 Self(83) => 'S',
404 Self(84) => 'T',
405 Self(85) => 'U',
406 Self(86) => 'V',
407 Self(87) => 'W',
408 Self(88) => 'X',
409 Self(89) => 'Y',
410 Self(90) => 'Z',
411 Self(91) => '[',
412 Self(92) => '\\',
413 Self(93) => ']',
414 Self(94) => '^',
415 Self(95) => '_',
416 Self(96) => '`',
417 Self(97) => 'a',
418 Self(98) => 'b',
419 Self(99) => 'c',
420 Self(100) => 'd',
421 Self(101) => 'e',
422 Self(102) => 'f',
423 Self(103) => 'g',
424 Self(104) => 'h',
425 Self(105) => 'i',
426 Self(106) => 'j',
427 Self(107) => 'k',
428 Self(108) => 'l',
429 Self(109) => 'm',
430 Self(110) => 'n',
431 Self(111) => 'o',
432 Self(112) => 'p',
433 Self(113) => 'q',
434 Self(114) => 'r',
435 Self(115) => 's',
436 Self(116) => 't',
437 Self(117) => 'u',
438 Self(118) => 'v',
439 Self(119) => 'w',
440 Self(120) => 'x',
441 Self(121) => 'y',
442 Self(122) => 'z',
443 Self(123) => '{',
444 Self(124) => '|',
445 Self(125) => '}',
446 Self(126) => '~',
447 Self(127) => '⌂',
448 Self(128) => 'Ç',
449 Self(129) => 'ü',
450 Self(130) => 'é',
451 Self(131) => 'â',
452 Self(132) => 'ä',
453 Self(133) => 'à',
454 Self(134) => 'å',
455 Self(135) => 'ç',
456 Self(136) => 'ê',
457 Self(137) => 'ë',
458 Self(138) => 'è',
459 Self(139) => 'ï',
460 Self(140) => 'î',
461 Self(141) => 'ì',
462 Self(142) => 'Ä',
463 Self(143) => 'Å',
464 Self(144) => 'É',
465 Self(145) => 'æ',
466 Self(146) => 'Æ',
467 Self(147) => 'ô',
468 Self(148) => 'ö',
469 Self(149) => 'ò',
470 Self(150) => 'û',
471 Self(151) => 'ù',
472 Self(152) => 'ÿ',
473 Self(153) => 'Ö',
474 Self(154) => 'Ü',
475 Self(155) => '¢',
476 Self(156) => '£',
477 Self(157) => '¥',
478 Self(158) => '₧',
479 Self(159) => 'ƒ',
480 Self(160) => 'á',
481 Self(161) => 'í',
482 Self(162) => 'ó',
483 Self(163) => 'ú',
484 Self(164) => 'ñ',
485 Self(165) => 'Ñ',
486 Self(166) => 'ª',
487 Self(167) => 'º',
488 Self(168) => '¿',
489 Self(169) => '⌐',
490 Self(170) => '¬',
491 Self(171) => '½',
492 Self(172) => '¼',
493 Self(173) => '¡',
494 Self(174) => '«',
495 Self(175) => '»',
496 Self(176) => '░',
497 Self(177) => '▒',
498 Self(178) => '▓',
499 Self(179) => '│',
500 Self(180) => '┤',
501 Self(181) => '╡',
502 Self(182) => '╢',
503 Self(183) => '╖',
504 Self(184) => '╕',
505 Self(185) => '╣',
506 Self(186) => '║',
507 Self(187) => '╗',
508 Self(188) => '╝',
509 Self(189) => '╜',
510 Self(190) => '╛',
511 Self(191) => '┐',
512 Self(192) => '└',
513 Self(193) => '┴',
514 Self(194) => '┬',
515 Self(195) => '├',
516 Self(196) => '─',
517 Self(197) => '┼',
518 Self(198) => '╞',
519 Self(199) => '╟',
520 Self(200) => '╚',
521 Self(201) => '╔',
522 Self(202) => '╩',
523 Self(203) => '╦',
524 Self(204) => '╠',
525 Self(205) => '═',
526 Self(206) => '╬',
527 Self(207) => '╧',
528 Self(208) => '╨',
529 Self(209) => '╤',
530 Self(210) => '╥',
531 Self(211) => '╙',
532 Self(212) => '╘',
533 Self(213) => '╒',
534 Self(214) => '╓',
535 Self(215) => '╫',
536 Self(216) => '╪',
537 Self(217) => '┘',
538 Self(218) => '┌',
539 Self(219) => '█',
540 Self(220) => '▄',
541 Self(221) => '▌',
542 Self(222) => '▐',
543 Self(223) => '▀',
544 Self(224) => 'α',
545 Self(225) => 'ß',
546 Self(226) => 'Γ',
547 Self(227) => 'π',
548 Self(228) => 'Σ',
549 Self(229) => 'σ',
550 Self(230) => 'µ',
551 Self(231) => 'τ',
552 Self(232) => 'Φ',
553 Self(233) => 'Θ',
554 Self(234) => 'Ω',
555 Self(235) => 'δ',
556 Self(236) => '∞',
557 Self(237) => 'φ',
558 Self(238) => 'ε',
559 Self(239) => '∩',
560 Self(240) => '≡',
561 Self(241) => '±',
562 Self(242) => '≥',
563 Self(243) => '≤',
564 Self(244) => '⌠',
565 Self(245) => '⌡',
566 Self(246) => '÷',
567 Self(247) => '≈',
568 Self(248) => '°',
569 Self(249) => '∙',
570 Self(250) => '·',
571 Self(251) => '√',
572 Self(252) => 'ⁿ',
573 Self(253) => '²',
574 Self(254) => '■',
575 Self(255) => '\u{a0}',
576 }
577 }
578}
579
580impl From<CP437Char> for char {
581 fn from(value: CP437Char) -> Self {
582 value.to_char()
583 }
584}
585
586impl TryFrom<char> for CP437Char {
587 type Error = ();
588
589 fn try_from(value: char) -> Result<Self, ()> {
590 Self::from_char(value).ok_or(())
591 }
592}
593
594impl fmt::Display for CP437Char {
595 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596 write!(f, "{}", self.to_char())
597 }
598}
599
600pub trait CP437CharExt {
601 fn is_cp437(&self) -> bool;
602
603 fn to_cp437_byte(self) -> Option<u8>;
604
605 fn to_cp437(self) -> Option<CP437Char>;
606}
607
608impl CP437CharExt for char {
609 fn is_cp437(&self) -> bool {
610 CP437CHARS.contains(self)
611 }
612
613 fn to_cp437_byte(self) -> Option<u8> {
614 self.to_cp437().map(CP437Char::to_byte)
615 }
616
617 fn to_cp437(self) -> Option<CP437Char> {
618 CP437Char::from_char(self)
619 }
620}
621
622impl CP437CharExt for CP437Char {
624 fn is_cp437(&self) -> bool {
625 true
626 }
627
628 fn to_cp437_byte(self) -> Option<u8> {
629 Some(self.to_byte())
630 }
631
632 fn to_cp437(self) -> Option<CP437Char> {
633 Some(self)
634 }
635}