group cp437 functions

This commit is contained in:
Vinzenz Schroeter 2025-01-12 12:01:40 +01:00
parent dea176d0d9
commit 4f83aa3d5c
3 changed files with 60 additions and 59 deletions

View file

@ -1,25 +1,19 @@
//! Conversion between UTF-8 and CP-437.
//!
//! Most of the functionality is only available with feature "cp437" enabled.
use std::collections::HashMap; use std::collections::HashMap;
#[allow(unused)] // depends on features /// Contains functions to convert between UTF-8 and Codepage 437.
pub use feature_cp437::*; ///
/// See <https://en.wikipedia.org/wiki/Code_page_437#Character_set>
pub struct Cp437Converter;
#[cfg(feature = "cp437")] /// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters
mod feature_cp437 { ///
use super::*; /// Mostly follows CP437, except 0x0A, which is kept for use as line ending.
///
/// An array of 256 elements, mapping most of the CP437 values to UTF-8 characters /// See <https://en.wikipedia.org/wiki/Code_page_437#Character_set>
/// ///
/// Mostly follows CP437, except 0x0A, which is kept for use as line ending. /// Mostly copied from <https://github.com/kip93/cp437-tools>. License: GPL-3.0
/// #[rustfmt::skip]
/// See <https://en.wikipedia.org/wiki/Code_page_437#Character_set> const CP437_TO_UTF8: [char; 256] = [
///
/// Mostly copied from <https://github.com/kip93/cp437-tools>. License: GPL-3.0
#[rustfmt::skip]
pub const CP437_TO_UTF8: [char; 256] = [
/* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '♪', '♫', '☼', /* 0X */ '\0', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '\n', '♂', '♀', '♪', '♫', '☼',
/* 1X */ '►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼', /* 1X */ '►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼',
/* 2X */ ' ', '!', '"', '#', '$', '%', '&', '\'','(', ')', '*', '+', ',', '-', '.', '/', /* 2X */ ' ', '!', '"', '#', '$', '%', '&', '\'','(', ')', '*', '+', ',', '-', '.', '/',
@ -36,9 +30,8 @@ mod feature_cp437 {
/* DX */ '╨', '╤', '╥', '╙', '╘', '╒', '╓', '╫', '╪', '┘', '┌', '█', '▄', '▌', '▐', '▀', /* DX */ '╨', '╤', '╥', '╙', '╘', '╒', '╓', '╫', '╪', '┘', '┌', '█', '▄', '▌', '▐', '▀',
/* EX */ 'α', 'ß', 'Γ', 'π', 'Σ', 'σ', 'µ', 'τ', 'Φ', 'Θ', 'Ω', 'δ', '∞', 'φ', 'ε', '∩', /* EX */ 'α', 'ß', 'Γ', 'π', 'Σ', 'σ', 'µ', 'τ', 'Φ', 'Θ', 'Ω', 'δ', '∞', 'φ', 'ε', '∩',
/* FX */ '≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∙', '·', '√', 'ⁿ', '²', '■', ' ', /* FX */ '≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∙', '·', '√', 'ⁿ', '²', '■', ' ',
]; ];
static UTF8_TO_CP437: once_cell::sync::Lazy<HashMap<char, u8>> =
static UTF8_TO_CP437: once_cell::sync::Lazy<HashMap<char, u8>> =
once_cell::sync::Lazy::new(|| { once_cell::sync::Lazy::new(|| {
let pairs = CP437_TO_UTF8 let pairs = CP437_TO_UTF8
.iter() .iter()
@ -47,11 +40,15 @@ mod feature_cp437 {
HashMap::from_iter(pairs) HashMap::from_iter(pairs)
}); });
impl Cp437Converter {
const MISSING_CHAR_CP437: u8 = 0x3F; // '?' const MISSING_CHAR_CP437: u8 = 0x3F; // '?'
/// Convert the provided bytes to UTF-8. /// Convert the provided bytes to UTF-8.
pub fn cp437_to_str(cp437: &[u8]) -> String { pub fn cp437_to_str(cp437: &[u8]) -> String {
cp437.iter().map(move |char| cp437_to_char(*char)).collect() cp437
.iter()
.map(move |char| Self::cp437_to_char(*char))
.collect()
} }
/// Convert a single CP-437 character to UTF-8. /// Convert a single CP-437 character to UTF-8.
@ -63,17 +60,18 @@ mod feature_cp437 {
/// ///
/// Characters that are not available are mapped to '?'. /// Characters that are not available are mapped to '?'.
pub fn str_to_cp437(utf8: &str) -> Vec<u8> { pub fn str_to_cp437(utf8: &str) -> Vec<u8> {
utf8.chars().map(char_to_cp437).collect() utf8.chars().map(Self::char_to_cp437).collect()
} }
/// Convert a single UTF-8 character to CP-437. /// Convert a single UTF-8 character to CP-437.
pub fn char_to_cp437(utf8: char) -> u8 { pub fn char_to_cp437(utf8: char) -> u8 {
*UTF8_TO_CP437.get(&utf8).unwrap_or(&MISSING_CHAR_CP437) *UTF8_TO_CP437
.get(&utf8)
.unwrap_or(&Self::MISSING_CHAR_CP437)
} }
} }
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "cp437")]
mod tests_feature_cp437 { mod tests_feature_cp437 {
use super::*; use super::*;
@ -102,13 +100,16 @@ mod tests_feature_cp437 {
dx Σ x²·δx dx Σ x²·δx
"#; "#;
let cp437 = str_to_cp437(utf8); let cp437 = Cp437Converter::str_to_cp437(utf8);
let actual = cp437_to_str(&*cp437); let actual = Cp437Converter::cp437_to_str(&*cp437);
assert_eq!(utf8, actual) assert_eq!(utf8, actual)
} }
#[test] #[test]
fn convert_invalid() { fn convert_invalid() {
assert_eq!(cp437_to_char(char_to_cp437('😜')), '?'); assert_eq!(
Cp437Converter::cp437_to_char(Cp437Converter::char_to_cp437('😜')),
'?'
);
} }
} }

View file

@ -83,20 +83,17 @@ pub use feature_cp437::*;
#[cfg(feature = "cp437")] #[cfg(feature = "cp437")]
mod feature_cp437 { mod feature_cp437 {
use super::*; use super::*;
use crate::{ use crate::{CharGrid, Cp437Converter};
cp437::{char_to_cp437, cp437_to_char},
CharGrid,
};
impl From<&Cp437Grid> for CharGrid { impl From<&Cp437Grid> for CharGrid {
fn from(value: &Cp437Grid) -> Self { fn from(value: &Cp437Grid) -> Self {
value.map(cp437_to_char) value.map(Cp437Converter::cp437_to_char)
} }
} }
impl From<&CharGrid> for Cp437Grid { impl From<&CharGrid> for Cp437Grid {
fn from(value: &CharGrid) -> Self { fn from(value: &CharGrid) -> Self {
value.map(char_to_cp437) value.map(Cp437Converter::char_to_cp437)
} }
} }

View file

@ -45,6 +45,7 @@ pub use crate::command::{Command, Offset};
pub use crate::compression_code::CompressionCode; pub use crate::compression_code::CompressionCode;
pub use crate::connection::Connection; pub use crate::connection::Connection;
pub use crate::constants::*; pub use crate::constants::*;
pub use crate::cp437::Cp437Converter;
pub use crate::cp437_grid::Cp437Grid; pub use crate::cp437_grid::Cp437Grid;
pub use crate::data_ref::DataRef; pub use crate::data_ref::DataRef;
pub use crate::grid::Grid; pub use crate::grid::Grid;
@ -66,7 +67,6 @@ mod compression;
mod compression_code; mod compression_code;
mod connection; mod connection;
mod constants; mod constants;
pub mod cp437;
mod cp437_grid; mod cp437_grid;
mod data_ref; mod data_ref;
mod grid; mod grid;
@ -74,6 +74,9 @@ mod origin;
mod packet; mod packet;
mod value_grid; mod value_grid;
#[cfg(feature = "cp437")]
mod cp437;
// include README.md in doctest // include README.md in doctest
#[doc = include_str!("../README.md")] #[doc = include_str!("../README.md")]
#[cfg(doctest)] #[cfg(doctest)]