Skip to main content

codepage_rs/
lib.rs

1use std::fmt;
2
3/// The table of characters in Codepage 437.
4#[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
622// I don't know who would want this, but I'll provide it regardless.
623impl 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}