use crate::*;
#[repr(C)]
pub struct tty_acs_entry {
pub key: u8,
pub string: &'static [u8; 4],
}
impl tty_acs_entry {
#[expect(clippy::trivially_copy_pass_by_ref, reason = "false positive")]
pub const fn new(key: u8, string: &'static [u8; 4]) -> Self {
Self { key, string }
}
}
static TTY_ACS_TABLE: [tty_acs_entry; 36] = [
tty_acs_entry::new(b'+', &[0o342, 0o206, 0o222, 0o000]), tty_acs_entry::new(b',', &[0o342, 0o206, 0o220, 0o000]), tty_acs_entry::new(b'-', &[0o342, 0o206, 0o221, 0o000]), tty_acs_entry::new(b'.', &[0o342, 0o206, 0o223, 0o000]), tty_acs_entry::new(b'0', &[0o342, 0o226, 0o256, 0o000]), tty_acs_entry::new(b'`', &[0o342, 0o227, 0o206, 0o000]), tty_acs_entry::new(b'a', &[0o342, 0o226, 0o222, 0o000]), tty_acs_entry::new(b'b', &[0o342, 0o220, 0o211, 0o000]),
tty_acs_entry::new(b'c', &[0o342, 0o220, 0o214, 0o000]),
tty_acs_entry::new(b'd', &[0o342, 0o220, 0o215, 0o000]),
tty_acs_entry::new(b'e', &[0o342, 0o220, 0o212, 0o000]),
tty_acs_entry::new(b'f', &[0o302, 0o260, 0o000, 0o000]), tty_acs_entry::new(b'g', &[0o302, 0o261, 0o000, 0o000]), tty_acs_entry::new(b'h', &[0o342, 0o220, 0o244, 0o000]),
tty_acs_entry::new(b'i', &[0o342, 0o220, 0o213, 0o000]),
tty_acs_entry::new(b'j', &[0o342, 0o224, 0o230, 0o000]), tty_acs_entry::new(b'k', &[0o342, 0o224, 0o220, 0o000]), tty_acs_entry::new(b'l', &[0o342, 0o224, 0o214, 0o000]), tty_acs_entry::new(b'm', &[0o342, 0o224, 0o224, 0o000]), tty_acs_entry::new(b'n', &[0o342, 0o224, 0o274, 0o000]), tty_acs_entry::new(b'o', &[0o342, 0o216, 0o272, 0o000]), tty_acs_entry::new(b'p', &[0o342, 0o216, 0o273, 0o000]), tty_acs_entry::new(b'q', &[0o342, 0o224, 0o200, 0o000]), tty_acs_entry::new(b'r', &[0o342, 0o216, 0o274, 0o000]), tty_acs_entry::new(b's', &[0o342, 0o216, 0o275, 0o000]), tty_acs_entry::new(b't', &[0o342, 0o224, 0o234, 0o000]), tty_acs_entry::new(b'u', &[0o342, 0o224, 0o244, 0o000]), tty_acs_entry::new(b'v', &[0o342, 0o224, 0o264, 0o000]), tty_acs_entry::new(b'w', &[0o342, 0o224, 0o254, 0o000]), tty_acs_entry::new(b'x', &[0o342, 0o224, 0o202, 0o000]), tty_acs_entry::new(b'y', &[0o342, 0o211, 0o244, 0o000]), tty_acs_entry::new(b'z', &[0o342, 0o211, 0o245, 0o000]), tty_acs_entry::new(b'{', &[0o317, 0o200, 0o000, 0o000]), tty_acs_entry::new(b'|', &[0o342, 0o211, 0o240, 0o000]), tty_acs_entry::new(b'}', &[0o302, 0o243, 0o000, 0o000]), tty_acs_entry::new(b'~', &[0o302, 0o267, 0o000, 0o000]), ];
#[repr(C)]
pub struct tty_acs_reverse_entry {
pub string: &'static [u8; 4],
pub key: u8,
}
impl tty_acs_reverse_entry {
#[expect(clippy::trivially_copy_pass_by_ref, reason = "false positive")]
const fn new(string: &'static [u8; 4], key: u8) -> Self {
Self { string, key }
}
}
static TTY_ACS_REVERSE2: [tty_acs_reverse_entry; 1] = [tty_acs_reverse_entry::new(
&[0o302, 0o267, 0o000, 0o000],
b'~',
)];
static TTY_ACS_REVERSE3: [tty_acs_reverse_entry; 32] = [
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o200, 0o000], b'q'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o201, 0o000], b'q'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o202, 0o000], b'x'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o203, 0o000], b'x'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o214, 0o000], b'l'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o217, 0o000], b'k'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o220, 0o000], b'k'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o223, 0o000], b'l'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o224, 0o000], b'm'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o227, 0o000], b'm'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o230, 0o000], b'j'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o233, 0o000], b'j'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o234, 0o000], b't'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o243, 0o000], b't'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o244, 0o000], b'u'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o253, 0o000], b'u'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o263, 0o000], b'w'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o264, 0o000], b'v'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o273, 0o000], b'v'),
tty_acs_reverse_entry::new(&[0o342, 0o224, 0o274, 0o000], b'n'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o213, 0o000], b'n'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o220, 0o000], b'q'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o221, 0o000], b'x'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o224, 0o000], b'l'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o227, 0o000], b'k'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o232, 0o000], b'm'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o235, 0o000], b'j'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o240, 0o000], b't'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o243, 0o000], b'u'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o246, 0o000], b'w'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o251, 0o000], b'v'),
tty_acs_reverse_entry::new(&[0o342, 0o225, 0o254, 0o000], b'n'),
];
static TTY_ACS_DOUBLE_BORDERS_LIST: [utf8_data; 13] = [
utf8_data::new([0o000, 0o000, 0o000, 0o000], 0, 0, 0),
utf8_data::new([0o342, 0o225, 0o221, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o220, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o224, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o227, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o232, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o235, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o246, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o251, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o240, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o243, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o254, 0o000], 0, 3, 1), utf8_data::new([0o302, 0o267, 0o000, 0o000], 0, 2, 1), ];
static TTY_ACS_HEAVY_BORDERS_LIST: [utf8_data; 13] = [
utf8_data::new([0o000, 0o000, 0o000, 0o000], 0, 0, 0),
utf8_data::new([0o342, 0o224, 0o203, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o201, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o217, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o223, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o227, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o233, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o263, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o273, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o243, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o253, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o213, 0o000], 0, 3, 1), utf8_data::new([0o302, 0o267, 0o000, 0o000], 0, 2, 1), ];
static TTY_ACS_ROUNDED_BORDERS_LIST: [utf8_data; 13] = [
utf8_data::new([0o000, 0o000, 0o000, 0o000], 0, 0, 0),
utf8_data::new([0o342, 0o224, 0o202, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o200, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o255, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o256, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o260, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o257, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o263, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o273, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o234, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o224, 0o244, 0o000], 0, 3, 1), utf8_data::new([0o342, 0o225, 0o213, 0o000], 0, 3, 1), utf8_data::new([0o302, 0o267, 0o000, 0o000], 0, 2, 1), ];
pub fn tty_acs_double_borders(cell_type: cell_type) -> &'static utf8_data {
&TTY_ACS_DOUBLE_BORDERS_LIST[cell_type as usize]
}
pub fn tty_acs_heavy_borders(cell_type: cell_type) -> &'static utf8_data {
&TTY_ACS_HEAVY_BORDERS_LIST[cell_type as usize]
}
pub fn tty_acs_rounded_borders(cell_type: cell_type) -> &'static utf8_data {
&TTY_ACS_ROUNDED_BORDERS_LIST[cell_type as usize]
}
pub fn tty_acs_cmp(test: u8, entry: &tty_acs_entry) -> std::cmp::Ordering {
test.cmp(&entry.key)
}
pub unsafe fn tty_acs_reverse_cmp(
key: *const u8,
entry: *const tty_acs_reverse_entry,
) -> std::cmp::Ordering {
unsafe { i32_to_ordering(libc::strcmp(key, (*entry).string.as_ptr().cast())) }
}
pub unsafe fn tty_acs_needed(tty: *const tty) -> bool {
unsafe {
if tty.is_null() {
return false;
}
if tty_term_has((*tty).term, tty_code_code::TTYC_U8)
&& tty_term_number((*tty).term, tty_code_code::TTYC_U8) == 0
{
return true;
}
if (*(*tty).client).flags.intersects(client_flag::UTF8) {
return false;
}
true
}
}
pub unsafe fn tty_acs_get(tty: *mut tty, ch: u8) -> *const u8 {
unsafe {
if tty_acs_needed(tty) {
if (*(*tty).term).acs[ch as usize][0] == b'\0' {
return null();
}
return &raw const (*(*tty).term).acs[ch as usize][0];
}
let Ok(entry) = TTY_ACS_TABLE.binary_search_by(|e| tty_acs_cmp(ch, e).reverse()) else {
return null_mut();
};
TTY_ACS_TABLE[entry].string.as_ptr().cast()
}
}
pub unsafe fn tty_acs_reverse_get(_tty: *const tty, s: *const u8, slen: usize) -> i32 {
unsafe {
let table = if slen == 2 {
TTY_ACS_REVERSE2.as_slice()
} else if slen == 3 {
TTY_ACS_REVERSE3.as_slice()
} else {
return -1;
};
let Ok(entry) = table.binary_search_by(|e| tty_acs_reverse_cmp(s, e).reverse()) else {
return -1;
};
table[entry].key as _
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cmp::Ordering;
unsafe fn cstr_bytes(p: *const u8) -> Vec<u8> {
assert!(!p.is_null(), "unexpected NULL C string");
let mut v = Vec::new();
let mut i = 0usize;
unsafe {
while *p.add(i) != 0 {
v.push(*p.add(i));
i += 1;
}
}
v
}
#[test]
fn get_known_line_drawing_mappings() {
unsafe {
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'q')), vec![0o342, 0o224, 0o200]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'x')), vec![0o342, 0o224, 0o202]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'j')), vec![0o342, 0o224, 0o230]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'k')), vec![0o342, 0o224, 0o220]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'l')), vec![0o342, 0o224, 0o214]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'm')), vec![0o342, 0o224, 0o224]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'n')), vec![0o342, 0o224, 0o274]);
}
}
#[test]
fn get_two_byte_and_boundary_entries() {
unsafe {
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'f')), vec![0o302, 0o260]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'g')), vec![0o302, 0o261]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'+')), vec![0o342, 0o206, 0o222]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'~')), vec![0o302, 0o267]);
}
}
#[test]
fn get_out_of_table_returns_null() {
unsafe {
assert!(tty_acs_get(null_mut(), b'*').is_null());
assert!(tty_acs_get(null_mut(), 0x7f).is_null());
assert!(tty_acs_get(null_mut(), 0).is_null());
assert!(tty_acs_get(null_mut(), b'1').is_null());
assert!(tty_acs_get(null_mut(), b'9').is_null());
assert!(tty_acs_get(null_mut(), b'A').is_null());
assert!(tty_acs_get(null_mut(), b'Z').is_null());
assert!(tty_acs_get(null_mut(), b'_').is_null());
assert!(tty_acs_get(null_mut(), b' ').is_null());
}
}
#[test]
fn reverse_get_three_byte() {
unsafe {
let s = [0o342u8, 0o224, 0o200, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 3), b'q' as i32);
let s = [0o342u8, 0o224, 0o202, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 3), b'x' as i32);
let s = [0o342u8, 0o224, 0o201, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 3), b'q' as i32);
let s = [0o342u8, 0o225, 0o224, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 3), b'l' as i32);
let s = [0o342u8, 0o225, 0o254, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 3), b'n' as i32);
let s = [0o342u8, 0o225, 0o213, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 3), b'n' as i32);
}
}
#[test]
fn reverse_get_two_byte() {
unsafe {
let s = [0o302u8, 0o267, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 2), b'~' as i32);
}
}
#[test]
fn reverse_get_misses_and_bad_lengths() {
unsafe {
let s = [0o342u8, 0o224, 0o204, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 3), -1);
let s = [0o302u8, 0o260, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 2), -1);
let s = [0o342u8, 0o224, 0o200, 0];
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 1), -1);
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 4), -1);
assert_eq!(tty_acs_reverse_get(null(), s.as_ptr(), 0), -1);
}
}
#[test]
fn get_reverse_round_trip() {
unsafe {
for &key in b"qxjklmtuvn" {
let bytes = cstr_bytes(tty_acs_get(null_mut(), key));
assert_eq!(bytes.len(), 3, "expected 3-byte UTF-8 for {}", key as char);
let mut buf = [0u8; 4];
buf[..3].copy_from_slice(&bytes);
assert_eq!(
tty_acs_reverse_get(null(), buf.as_ptr(), 3),
key as i32,
"round trip failed for {}",
key as char
);
}
let bytes = cstr_bytes(tty_acs_get(null_mut(), b'~'));
assert_eq!(bytes, vec![0o302, 0o267]);
let mut buf = [0u8; 3];
buf[..2].copy_from_slice(&bytes);
assert_eq!(tty_acs_reverse_get(null(), buf.as_ptr(), 2), b'~' as i32);
}
}
#[test]
fn cmp_orders_by_key() {
let entry = tty_acs_entry::new(b'q', &[0o342, 0o224, 0o200, 0o000]);
assert_eq!(tty_acs_cmp(b'q', &entry), Ordering::Equal);
assert_eq!(tty_acs_cmp(b'p', &entry), Ordering::Less);
assert_eq!(tty_acs_cmp(b'r', &entry), Ordering::Greater);
}
#[test]
fn table_is_sorted_by_key() {
assert!(TTY_ACS_TABLE.windows(2).all(|w| w[0].key < w[1].key));
assert_eq!(TTY_ACS_TABLE.len(), 36);
}
#[test]
fn reverse_tables_are_sorted() {
assert!(TTY_ACS_REVERSE3.windows(2).all(|w| w[0].string < w[1].string));
assert_eq!(TTY_ACS_REVERSE3.len(), 32);
assert_eq!(TTY_ACS_REVERSE2.len(), 1);
}
#[test]
fn border_style_lookups() {
let d = tty_acs_double_borders(cell_type::CELL_INSIDE);
assert_eq!(d.size, 0);
assert_eq!(d.width, 0);
let d = tty_acs_double_borders(cell_type::CELL_TOPBOTTOM);
assert_eq!(&d.data[..3], &[0o342, 0o225, 0o221]);
assert_eq!(d.size, 3);
assert_eq!(d.width, 1);
let h = tty_acs_heavy_borders(cell_type::CELL_TOPBOTTOM);
assert_eq!(&h.data[..3], &[0o342, 0o224, 0o203]);
let r = tty_acs_rounded_borders(cell_type::CELL_LEFTRIGHT);
assert_eq!(&r.data[..3], &[0o342, 0o224, 0o200]);
let r = tty_acs_rounded_borders(cell_type::CELL_TOPLEFT);
assert_eq!(&r.data[..3], &[0o342, 0o225, 0o255]);
let d = tty_acs_double_borders(cell_type::CELL_OUTSIDE);
assert_eq!(&d.data[..2], &[0o302, 0o267]);
assert_eq!(d.size, 2);
}
#[test]
fn get_tees_scanlines_and_symbols() {
unsafe {
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b't')), vec![0o342, 0o224, 0o234]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'u')), vec![0o342, 0o224, 0o244]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'v')), vec![0o342, 0o224, 0o264]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'w')), vec![0o342, 0o224, 0o254]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'o')), vec![0o342, 0o216, 0o272]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'p')), vec![0o342, 0o216, 0o273]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'r')), vec![0o342, 0o216, 0o274]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b's')), vec![0o342, 0o216, 0o275]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'y')), vec![0o342, 0o211, 0o244]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'z')), vec![0o342, 0o211, 0o245]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'|')), vec![0o342, 0o211, 0o240]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'`')), vec![0o342, 0o227, 0o206]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'a')), vec![0o342, 0o226, 0o222]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'0')), vec![0o342, 0o226, 0o256]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'{')), vec![0o317, 0o200]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'}')), vec![0o302, 0o243]);
}
}
#[test]
fn get_arrow_glyphs() {
unsafe {
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'+')), vec![0o342, 0o206, 0o222]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b',')), vec![0o342, 0o206, 0o220]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'-')), vec![0o342, 0o206, 0o221]);
assert_eq!(cstr_bytes(tty_acs_get(null_mut(), b'.')), vec![0o342, 0o206, 0o223]);
}
}
#[test]
fn reverse_get_heavy_box_drawing() {
unsafe {
let rev = |b: [u8; 4]| tty_acs_reverse_get(null(), b.as_ptr(), 3);
assert_eq!(rev([0o342, 0o224, 0o201, 0]), b'q' as i32);
assert_eq!(rev([0o342, 0o224, 0o203, 0]), b'x' as i32);
assert_eq!(rev([0o342, 0o224, 0o214, 0]), b'l' as i32);
assert_eq!(rev([0o342, 0o224, 0o220, 0]), b'k' as i32);
assert_eq!(rev([0o342, 0o224, 0o224, 0]), b'm' as i32);
assert_eq!(rev([0o342, 0o224, 0o230, 0]), b'j' as i32);
assert_eq!(rev([0o342, 0o224, 0o217, 0]), b'k' as i32);
assert_eq!(rev([0o342, 0o224, 0o223, 0]), b'l' as i32);
assert_eq!(rev([0o342, 0o224, 0o227, 0]), b'm' as i32);
assert_eq!(rev([0o342, 0o224, 0o233, 0]), b'j' as i32);
}
}
#[test]
fn reverse_get_double_box_drawing() {
unsafe {
let rev = |b: [u8; 4]| tty_acs_reverse_get(null(), b.as_ptr(), 3);
assert_eq!(rev([0o342, 0o225, 0o220, 0]), b'q' as i32);
assert_eq!(rev([0o342, 0o225, 0o221, 0]), b'x' as i32);
assert_eq!(rev([0o342, 0o225, 0o224, 0]), b'l' as i32);
assert_eq!(rev([0o342, 0o225, 0o227, 0]), b'k' as i32);
assert_eq!(rev([0o342, 0o225, 0o232, 0]), b'm' as i32);
assert_eq!(rev([0o342, 0o225, 0o235, 0]), b'j' as i32);
assert_eq!(rev([0o342, 0o225, 0o240, 0]), b't' as i32);
assert_eq!(rev([0o342, 0o225, 0o243, 0]), b'u' as i32);
assert_eq!(rev([0o342, 0o225, 0o246, 0]), b'w' as i32);
assert_eq!(rev([0o342, 0o225, 0o251, 0]), b'v' as i32);
}
}
#[test]
fn cmp_matches_key_ordering_across_table() {
for e in &TTY_ACS_TABLE {
assert_eq!(tty_acs_cmp(e.key, e), Ordering::Equal);
if e.key > 0 {
assert_eq!(tty_acs_cmp(e.key - 1, e), Ordering::Less);
}
if e.key < 0xff {
assert_eq!(tty_acs_cmp(e.key + 1, e), Ordering::Greater);
}
}
}
#[test]
fn all_border_cell_types_are_consistent() {
let types = [
cell_type::CELL_INSIDE,
cell_type::CELL_TOPBOTTOM,
cell_type::CELL_LEFTRIGHT,
cell_type::CELL_TOPLEFT,
cell_type::CELL_TOPRIGHT,
cell_type::CELL_BOTTOMLEFT,
cell_type::CELL_BOTTOMRIGHT,
cell_type::CELL_TOPJOIN,
cell_type::CELL_BOTTOMJOIN,
cell_type::CELL_LEFTJOIN,
cell_type::CELL_RIGHTJOIN,
cell_type::CELL_JOIN,
cell_type::CELL_OUTSIDE,
];
for (i, &t) in types.iter().enumerate() {
for d in [
tty_acs_double_borders(t),
tty_acs_heavy_borders(t),
tty_acs_rounded_borders(t),
] {
if i == 0 {
assert_eq!(d.size, 0, "sentinel size at index 0");
assert_eq!(d.width, 0);
} else {
assert!(d.size == 2 || d.size == 3, "glyph size 2 or 3");
assert_eq!(d.width, 1, "border glyph width is 1");
}
}
}
}
#[test]
fn full_forward_reverse_agreement() {
unsafe {
let mut round_tripped = 0;
for e in &TTY_ACS_TABLE {
let p = tty_acs_get(null_mut(), e.key);
if p.is_null() {
continue;
}
let bytes = cstr_bytes(p);
if bytes.len() != 3 {
continue;
}
let mut buf = [0u8; 4];
buf[..3].copy_from_slice(&bytes);
let back = tty_acs_reverse_get(null(), buf.as_ptr(), 3);
if back != -1 {
assert_eq!(
back, e.key as i32,
"reverse of {:?} should map back to {}",
bytes, e.key as char
);
round_tripped += 1;
}
}
assert!(round_tripped >= 10, "expected many round-trips, got {round_tripped}");
}
}
}