1pub const GLYPH_W: i32 = 4;
10pub const GLYPH_H: i32 = 7;
12
13pub const UNKNOWN: [u8; 6] = [0b111, 0b111, 0b111, 0b111, 0b111, 0b000];
15
16pub fn glyph(c: char) -> [u8; 6] {
18 let i = c as u32;
19 if (32..127).contains(&i) {
20 GLYPHS[(i - 32) as usize]
21 } else {
22 UNKNOWN
23 }
24}
25
26pub fn text_width(s: &str) -> i32 {
28 s.chars().count() as i32 * GLYPH_W
29}
30
31#[rustfmt::skip]
36const GLYPHS: [[u8; 6]; 95] = [
37 [0b000, 0b000, 0b000, 0b000, 0b000, 0b000], [0b010, 0b010, 0b010, 0b000, 0b010, 0b000], [0b101, 0b101, 0b000, 0b000, 0b000, 0b000], [0b101, 0b111, 0b101, 0b111, 0b101, 0b000], [0b111, 0b110, 0b111, 0b011, 0b111, 0b000], [0b101, 0b001, 0b010, 0b100, 0b101, 0b000], [0b010, 0b101, 0b010, 0b101, 0b011, 0b000], [0b010, 0b100, 0b000, 0b000, 0b000, 0b000], [0b001, 0b010, 0b010, 0b010, 0b001, 0b000], [0b100, 0b010, 0b010, 0b010, 0b100, 0b000], [0b101, 0b010, 0b111, 0b010, 0b101, 0b000], [0b000, 0b010, 0b111, 0b010, 0b000, 0b000], [0b000, 0b000, 0b000, 0b010, 0b100, 0b000], [0b000, 0b000, 0b111, 0b000, 0b000, 0b000], [0b000, 0b000, 0b000, 0b000, 0b010, 0b000], [0b001, 0b001, 0b010, 0b100, 0b100, 0b000], [0b111, 0b101, 0b101, 0b101, 0b111, 0b000], [0b110, 0b010, 0b010, 0b010, 0b111, 0b000], [0b111, 0b001, 0b111, 0b100, 0b111, 0b000], [0b111, 0b001, 0b011, 0b001, 0b111, 0b000], [0b101, 0b101, 0b111, 0b001, 0b001, 0b000], [0b111, 0b100, 0b111, 0b001, 0b111, 0b000], [0b011, 0b100, 0b111, 0b101, 0b111, 0b000], [0b111, 0b001, 0b001, 0b001, 0b001, 0b000], [0b111, 0b101, 0b111, 0b101, 0b111, 0b000], [0b111, 0b101, 0b111, 0b001, 0b110, 0b000], [0b000, 0b010, 0b000, 0b010, 0b000, 0b000], [0b000, 0b010, 0b000, 0b010, 0b100, 0b000], [0b001, 0b010, 0b100, 0b010, 0b001, 0b000], [0b000, 0b111, 0b000, 0b111, 0b000, 0b000], [0b100, 0b010, 0b001, 0b010, 0b100, 0b000], [0b111, 0b001, 0b011, 0b000, 0b010, 0b000], [0b111, 0b101, 0b111, 0b100, 0b011, 0b000], [0b111, 0b101, 0b111, 0b101, 0b101, 0b000], [0b111, 0b101, 0b110, 0b101, 0b111, 0b000], [0b011, 0b100, 0b100, 0b100, 0b011, 0b000], [0b110, 0b101, 0b101, 0b101, 0b110, 0b000], [0b111, 0b100, 0b110, 0b100, 0b111, 0b000], [0b111, 0b100, 0b110, 0b100, 0b100, 0b000], [0b011, 0b100, 0b101, 0b101, 0b011, 0b000], [0b101, 0b101, 0b111, 0b101, 0b101, 0b000], [0b111, 0b010, 0b010, 0b010, 0b111, 0b000], [0b111, 0b010, 0b010, 0b010, 0b110, 0b000], [0b101, 0b101, 0b110, 0b101, 0b101, 0b000], [0b100, 0b100, 0b100, 0b100, 0b111, 0b000], [0b111, 0b111, 0b101, 0b101, 0b101, 0b000], [0b110, 0b101, 0b101, 0b101, 0b101, 0b000], [0b111, 0b101, 0b101, 0b101, 0b111, 0b000], [0b111, 0b101, 0b111, 0b100, 0b100, 0b000], [0b111, 0b101, 0b101, 0b111, 0b001, 0b000], [0b111, 0b101, 0b110, 0b101, 0b101, 0b000], [0b011, 0b100, 0b111, 0b001, 0b110, 0b000], [0b111, 0b010, 0b010, 0b010, 0b010, 0b000], [0b101, 0b101, 0b101, 0b101, 0b111, 0b000], [0b101, 0b101, 0b101, 0b101, 0b010, 0b000], [0b101, 0b101, 0b101, 0b111, 0b111, 0b000], [0b101, 0b101, 0b010, 0b101, 0b101, 0b000], [0b101, 0b101, 0b010, 0b010, 0b010, 0b000], [0b111, 0b001, 0b010, 0b100, 0b111, 0b000], [0b011, 0b010, 0b010, 0b010, 0b011, 0b000], [0b100, 0b100, 0b010, 0b001, 0b001, 0b000], [0b110, 0b010, 0b010, 0b010, 0b110, 0b000], [0b010, 0b101, 0b000, 0b000, 0b000, 0b000], [0b000, 0b000, 0b000, 0b000, 0b111, 0b000], [0b100, 0b010, 0b000, 0b000, 0b000, 0b000], [0b000, 0b011, 0b101, 0b111, 0b111, 0b000], [0b100, 0b100, 0b110, 0b101, 0b110, 0b000], [0b000, 0b011, 0b100, 0b100, 0b011, 0b000], [0b001, 0b001, 0b011, 0b101, 0b011, 0b000], [0b000, 0b011, 0b111, 0b100, 0b011, 0b000], [0b011, 0b010, 0b111, 0b010, 0b010, 0b000], [0b000, 0b011, 0b101, 0b011, 0b001, 0b110], [0b100, 0b100, 0b110, 0b101, 0b101, 0b000], [0b010, 0b000, 0b010, 0b010, 0b010, 0b000], [0b001, 0b000, 0b001, 0b001, 0b001, 0b110], [0b100, 0b100, 0b101, 0b110, 0b101, 0b000], [0b110, 0b010, 0b010, 0b010, 0b011, 0b000], [0b000, 0b111, 0b111, 0b101, 0b101, 0b000], [0b000, 0b110, 0b101, 0b101, 0b101, 0b000], [0b000, 0b010, 0b101, 0b101, 0b010, 0b000], [0b000, 0b110, 0b101, 0b110, 0b100, 0b100], [0b000, 0b011, 0b101, 0b011, 0b001, 0b001], [0b000, 0b110, 0b100, 0b100, 0b100, 0b000], [0b000, 0b011, 0b110, 0b011, 0b110, 0b000], [0b010, 0b111, 0b010, 0b010, 0b011, 0b000], [0b000, 0b101, 0b101, 0b101, 0b111, 0b000], [0b000, 0b101, 0b101, 0b101, 0b010, 0b000], [0b000, 0b101, 0b101, 0b111, 0b111, 0b000], [0b000, 0b101, 0b010, 0b010, 0b101, 0b000], [0b000, 0b101, 0b101, 0b011, 0b001, 0b110], [0b000, 0b111, 0b001, 0b100, 0b111, 0b000], [0b011, 0b010, 0b110, 0b010, 0b011, 0b000], [0b010, 0b010, 0b010, 0b010, 0b010, 0b000], [0b110, 0b010, 0b011, 0b010, 0b110, 0b000], [0b000, 0b001, 0b111, 0b100, 0b000, 0b000], ];
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn case_is_distinct() {
140 for (lo, up) in ('a'..='z').zip('A'..='Z') {
143 assert_ne!(glyph(lo), glyph(up), "{lo} and {up} render identically");
144 }
145 }
146
147 #[test]
148 fn lowercase_is_shorter_than_uppercase() {
149 for c in "acemnorsuvwxz".chars() {
152 assert_eq!(glyph(c)[0], 0, "{c} should not reach the cap line");
153 }
154 }
155
156 #[test]
157 fn descenders_use_the_bottom_row() {
158 for c in "gjpqy".chars() {
159 assert_ne!(glyph(c)[5], 0, "{c} should have a descender");
160 }
161 for c in "abcdefhiklmnorstuvwxz".chars() {
163 assert_eq!(glyph(c)[5], 0, "{c} should not have a descender");
164 }
165 }
166
167 #[test]
168 fn out_of_range_is_unknown() {
169 assert_eq!(glyph('\u{1F600}'), UNKNOWN);
170 assert_eq!(glyph('\u{7F}'), UNKNOWN);
171 }
172}