1use std::hash::{Hasher, Hash};
2use std::borrow::Cow;
3use std::{cmp, fmt};
4
5
6#[derive(Clone)]
10pub struct Cp437Dialect {
11 cp437_to_unicode: [char; 256],
12
13 overlap_unicode: fn(unicode: char) -> bool,
14 overlap_cp437: fn(cp437: u8) -> bool,
15
16 encode: fn(unicode: char) -> Option<u8>,
17
18 remaps: Cow<'static, [(u8, char, char)]>,
20}
21
22impl Cp437Dialect {
23 #[inline]
25 pub fn overlap_unicode(&self, unicode: char) -> bool {
26 (self.overlap_unicode)(unicode) && !self.remaps.iter().rev().find(|&&(_, _, to)| to == unicode).is_some()
27 }
28
29 #[inline]
31 pub fn overlap_cp437(&self, cp437: u8) -> bool {
32 (self.overlap_cp437)(cp437) && !self.remaps.iter().rev().find(|&&(whom, _, _)| whom == cp437).is_some()
33 }
34
35 #[inline(always)]
37 pub fn decode(&self, cp437: u8) -> char {
38 self.cp437_to_unicode[cp437 as usize]
39 }
40
41 #[inline]
43 pub fn encode(&self, unicode: char) -> Option<u8> {
44 self.remaps.iter().rev().find(|&&(_, _, to)| to == unicode).map(|&(whom, _, _)| whom).or_else(|| (self.encode)(unicode))
45 }
46
47 pub fn remap(&mut self, cp437: u8, unicode: char) -> &mut Cp437Dialect {
62 self.remaps.to_mut().push((cp437, self.cp437_to_unicode[cp437 as usize], unicode));
63 self.cp437_to_unicode[cp437 as usize] = unicode;
64 self
65 }
66}
67
68impl fmt::Debug for Cp437Dialect {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71 f.debug_struct("Cp437Dialect")
72 .field("cp437_to_unicode", &&self.cp437_to_unicode[..])
73 .field("overlap_unicode", &self.overlap_unicode)
74 .field("overlap_cp437", &self.overlap_cp437)
75 .field("encode", &self.encode)
76 .field("remaps", &self.remaps)
77 .finish()
78 }
79}
80
81impl Hash for Cp437Dialect {
82 fn hash<H: Hasher>(&self, state: &mut H) {
83 self.cp437_to_unicode[..].hash(state);
84 self.overlap_unicode.hash(state);
85 self.overlap_cp437.hash(state);
86 self.encode.hash(state);
87 self.remaps.hash(state);
88 }
89}
90
91impl cmp::Eq for Cp437Dialect {}
92
93impl cmp::PartialEq for Cp437Dialect {
94 fn eq(&self, other: &Cp437Dialect) -> bool {
95 self.cp437_to_unicode[..] == other.cp437_to_unicode[..] && self.overlap_unicode == other.overlap_unicode && self.overlap_cp437 == other.overlap_cp437 && self.encode == other.encode && self.remaps == other.remaps
100 }
101}
102
103impl cmp::Ord for Cp437Dialect {
104 fn cmp(&self, other: &Cp437Dialect) -> cmp::Ordering {
105 self.cp437_to_unicode[..]
106 .cmp(&other.cp437_to_unicode[..])
107 .then(self.overlap_unicode.cmp(&other.overlap_unicode))
108 .then(self.overlap_cp437.cmp(&other.overlap_cp437))
109 .then(self.encode.cmp(&other.encode))
110 .then(self.remaps.cmp(&other.remaps))
111 }
112}
113
114impl cmp::PartialOrd for Cp437Dialect {
115 fn partial_cmp(&self, other: &Cp437Dialect) -> Option<cmp::Ordering> {
116 Some(self.cmp(other))
117 }
118}
119
120
121include!(concat!(env!("OUT_DIR"), "/dialects.rs"));