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