use std::borrow::Cow;
use std::fmt::{self, Display};
use crate::rg::de::ArbitraryData;
type OneLine = bool;
#[derive(Debug, Copy, Clone)]
pub enum PrintableStyle {
Hidden,
Common(OneLine),
All(OneLine),
}
impl Default for PrintableStyle {
fn default() -> Self {
PrintableStyle::Hidden
}
}
impl Display for PrintableStyle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.symbol())
}
}
impl PrintableStyle {
pub fn cycle(self) -> Self {
match self {
PrintableStyle::Hidden => PrintableStyle::Common(false),
PrintableStyle::Common(false) => PrintableStyle::Common(true),
PrintableStyle::Common(true) => PrintableStyle::All(false),
PrintableStyle::All(false) => PrintableStyle::All(true),
PrintableStyle::All(true) => PrintableStyle::Hidden,
}
}
pub fn as_one_line(self) -> Self {
match self {
PrintableStyle::Hidden => PrintableStyle::Common(true),
PrintableStyle::Common(_) => PrintableStyle::Common(true),
PrintableStyle::All(_) => PrintableStyle::All(true),
}
}
pub fn is_one_line(self) -> bool {
matches!(
self,
PrintableStyle::Common(true) | PrintableStyle::All(true)
)
}
pub fn symbol(self) -> char {
match self {
PrintableStyle::Hidden => 'H',
PrintableStyle::Common(false) => 'C',
PrintableStyle::Common(true) => 'c',
PrintableStyle::All(false) => 'A',
PrintableStyle::All(true) => 'a',
}
}
}
pub trait Printable {
fn to_printable(&self, style: PrintableStyle) -> String;
}
impl Printable for &str {
fn to_printable(&self, style: PrintableStyle) -> String {
match style {
PrintableStyle::Hidden => {
let mut s = String::with_capacity(self.len());
for ch in self.chars() {
match ch {
'\x00' | '\x01' | '\x02' | '\x03' | '\x04' | '\x05' | '\x06' | '\x07'
| '\x08' | '\x0B' | '\x0C' | '\x0E' | '\x0F' | '\x10' | '\x11' | '\x12'
| '\x13' | '\x14' | '\x15' | '\x16' | '\x17' | '\x18' | '\x19' | '\x1A'
| '\x1B' | '\x1C' | '\x1D' | '\x1E' | '\x1F' | '\x7F' => {}
'\x09' | '\x0D' => s.push(' '),
_ => s.push(ch),
}
}
s
}
PrintableStyle::Common(oneline) => {
let mut s = String::with_capacity(self.len());
for ch in self.chars() {
match ch {
'\x09' => s.push('→'), '\x0A' => s.push_str(if oneline { "¬" } else { "¬\n" }), '\x0D' => s.push('¤'), '\x20' => s.push('␣'), '\x00' | '\x01' | '\x02' | '\x03' | '\x04' | '\x05' | '\x06' | '\x07'
| '\x08' | '\x0B' | '\x0C' | '\x0E' | '\x0F' | '\x10' | '\x11' | '\x12'
| '\x13' | '\x14' | '\x15' | '\x16' | '\x17' | '\x18' | '\x19' | '\x1A'
| '\x1B' | '\x1C' | '\x1D' | '\x1E' | '\x1F' | '\x7F' => s.push('•'),
c => s.push(c),
}
}
s
}
PrintableStyle::All(oneline) => {
let mut s = String::with_capacity(self.len());
for ch in self.chars() {
match ch {
'\x00' => s.push('␀'), '\x01' => s.push('␁'), '\x02' => s.push('␂'), '\x03' => s.push('␃'), '\x04' => s.push('␄'), '\x05' => s.push('␅'), '\x06' => s.push('␆'), '\x07' => s.push('␇'), '\x08' => s.push('␈'), '\x09' => s.push('␉'), '\x0A' => s.push_str(if oneline { "␊" } else { "␊\n" }), '\x0B' => s.push('␋'), '\x0C' => s.push('␌'), '\x0D' => s.push('␍'), '\x0E' => s.push('␎'), '\x0F' => s.push('␏'), '\x10' => s.push('␐'), '\x11' => s.push('␑'), '\x12' => s.push('␒'), '\x13' => s.push('␓'), '\x14' => s.push('␔'), '\x15' => s.push('␕'), '\x16' => s.push('␖'), '\x17' => s.push('␗'), '\x18' => s.push('␘'), '\x19' => s.push('␙'), '\x1A' => s.push('␚'), '\x1B' => s.push('␛'), '\x1C' => s.push('␜'), '\x1D' => s.push('␝'), '\x1E' => s.push('␞'), '\x1F' => s.push('␟'), '\x20' => s.push('␠'), '\x7F' => s.push('␡'), c => s.push(c),
}
}
s
}
}
}
}
impl Printable for &String {
fn to_printable(&self, style: PrintableStyle) -> String {
self.as_str().to_printable(style)
}
}
impl Printable for String {
fn to_printable(&self, style: PrintableStyle) -> String {
self.as_str().to_printable(style)
}
}
impl<'a> Printable for Cow<'a, str> {
fn to_printable(&self, style: PrintableStyle) -> String {
self.to_string().to_printable(style)
}
}
impl Printable for ArbitraryData {
fn to_printable(&self, style: PrintableStyle) -> String {
self.lossy_utf8().to_printable(style)
}
}
impl Printable for Vec<u8> {
fn to_printable(&self, style: PrintableStyle) -> String {
String::from_utf8_lossy(self).to_printable(style)
}
}
#[cfg(test)]
mod tests {
use base64_simd::STANDARD as base64;
use crate::model::{Printable, PrintableStyle};
use crate::rg::de::ArbitraryData;
const NON_PRINTABLE_WHITESPACE: &str = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20\x7F";
#[test]
fn test_printable() {
assert_eq!(
NON_PRINTABLE_WHITESPACE.to_printable(PrintableStyle::Hidden),
" \n "
);
assert_eq!(
NON_PRINTABLE_WHITESPACE.to_printable(PrintableStyle::All(true)),
"␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡"
);
assert_eq!(
NON_PRINTABLE_WHITESPACE.to_printable(PrintableStyle::All(false)),
"␀␁␂␃␄␅␆␇␈␉␊\n␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡"
);
assert_eq!(
NON_PRINTABLE_WHITESPACE.to_printable(PrintableStyle::Common(true)),
"•••••••••→¬••¤••••••••••••••••••␣•"
);
assert_eq!(
NON_PRINTABLE_WHITESPACE.to_printable(PrintableStyle::Common(false)),
"•••••••••→¬\n••¤••••••••••••••••••␣•"
);
}
#[test]
fn test_printable_oneline() {
assert_eq!("\n".to_printable(PrintableStyle::Hidden), "\n");
assert_eq!("\n".to_printable(PrintableStyle::Common(false)), "¬\n");
assert_eq!("\n".to_printable(PrintableStyle::Common(true)), "¬");
assert_eq!("\n".to_printable(PrintableStyle::All(false)), "␊\n");
assert_eq!("\n".to_printable(PrintableStyle::All(true)), "␊");
}
#[test]
fn test_printable_text() {
let data = ArbitraryData::new_with_text(NON_PRINTABLE_WHITESPACE.to_string());
assert_eq!(data.to_printable(PrintableStyle::Hidden), " \n ");
assert_eq!(
data.to_printable(PrintableStyle::All(true)),
"␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡"
);
assert_eq!(
data.to_printable(PrintableStyle::Common(true)),
"•••••••••→¬••¤••••••••••••••••••␣•"
);
}
#[test]
fn test_printable_base64() {
let data =
ArbitraryData::new_with_base64(base64.encode_to_string(NON_PRINTABLE_WHITESPACE));
assert_eq!(data.to_printable(PrintableStyle::Hidden), " \n ");
assert_eq!(
data.to_printable(PrintableStyle::All(true)),
"␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡"
);
assert_eq!(
data.to_printable(PrintableStyle::Common(true)),
"•••••••••→¬••¤••••••••••••••••••␣•"
);
}
}