#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Charset {
Ascii,
HalfBlocks,
Quadrants,
Sextants,
Octants,
Braille,
}
pub(super) const OCTANTS: [char; 256] = [
' ', '', '', '🮂', '', '▘', '', '', '', '', '▝', '', '', '', '', '▀', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '🮅', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '▖', '', '', '', '', '▌', '', '', '', '', '▞', '', '', '', '',
'▛', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '▗', '', '', '', '', '▚', '', '', '', '', '▐',
'', '', '', '', '▜', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '▂', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '▄', '', '', '', '', '▙', '',
'', '', '', '▟', '', '▆', '', '', '█',
];
pub(super) const QUADRANTS: [char; 16] = [
' ', '\u{2598}', '\u{259D}', '\u{2580}', '\u{2596}', '\u{258C}', '\u{259E}', '\u{259B}',
'\u{2597}', '\u{259A}', '\u{2590}', '\u{259C}', '\u{2584}', '\u{2599}', '\u{259F}', '\u{2588}',
];
const BRAILLE_DOTS: [u8; 8] = [0x01, 0x08, 0x02, 0x10, 0x04, 0x20, 0x40, 0x80];
impl Charset {
pub fn pixels_per_cell(self) -> (usize, usize) {
match self {
Charset::Ascii => (1, 1),
Charset::HalfBlocks => (1, 2),
Charset::Quadrants => (2, 2),
Charset::Sextants => (2, 3),
Charset::Octants | Charset::Braille => (2, 4),
}
}
pub(crate) fn bit(self, column: usize, row: usize) -> u8 {
match self {
Charset::Ascii => 1,
Charset::HalfBlocks => 1 << row,
Charset::Quadrants | Charset::Sextants | Charset::Octants => 1 << (row * 2 + column),
Charset::Braille => BRAILLE_DOTS[row * 2 + column],
}
}
pub(crate) fn fill_ramp(self) -> &'static [char] {
match self {
Charset::Ascii => &['#'],
_ => &[
'\u{2581}', '\u{2582}', '\u{2583}', '\u{2584}', '\u{2585}', '\u{2586}', '\u{2587}',
'\u{2588}',
],
}
}
pub(crate) fn fill_ramp_left(self) -> &'static [char] {
match self {
Charset::Ascii => &['#'],
_ => &[
'\u{258F}', '\u{258E}', '\u{258D}', '\u{258C}', '\u{258B}', '\u{258A}', '\u{2589}',
'\u{2588}',
],
}
}
pub(crate) const fn shade_ramp(self) -> [char; 4] {
match self {
Charset::Ascii => ['.', ':', '#', '@'],
_ => ['\u{2591}', '\u{2592}', '\u{2593}', '\u{2588}'],
}
}
pub(crate) fn chrome(self) -> Chrome {
match self {
Charset::Ascii => Chrome {
y_axis: "|",
y_tick: "+",
x_axis: "-",
corner: "+",
x_tick: "+",
marker: "=",
ellipsis: '.',
},
_ => Chrome {
y_axis: "\u{2502}",
y_tick: "\u{2524}",
x_axis: "\u{2500}",
corner: "\u{2514}",
x_tick: "\u{252C}",
marker: "\u{2501}",
ellipsis: '\u{2026}',
},
}
}
pub(crate) fn glyph(self, bits: u8) -> char {
if bits == 0 {
return ' ';
}
match self {
Charset::Ascii => '*',
Charset::HalfBlocks => match bits {
1 => '\u{2580}',
2 => '\u{2584}',
_ => '\u{2588}',
},
Charset::Quadrants => QUADRANTS[usize::from(bits & 0x0F)],
Charset::Sextants => match bits & 0x3F {
21 => '\u{258C}',
42 => '\u{2590}',
63 => '\u{2588}',
bits => {
let skipped = u32::from(bits > 21) + u32::from(bits > 42);
char::from_u32(0x1FB00 + u32::from(bits) - 1 - skipped)
.expect("sextant block is dense")
}
},
Charset::Octants => OCTANTS[usize::from(bits)],
Charset::Braille => {
char::from_u32(0x2800 + u32::from(bits)).expect("braille block is contiguous")
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Chrome {
pub y_axis: &'static str,
pub y_tick: &'static str,
pub x_axis: &'static str,
pub corner: &'static str,
pub x_tick: &'static str,
pub marker: &'static str,
pub ellipsis: char,
}
#[cfg(test)]
#[path = "tests/charset_tests.rs"]
mod tests;