use crate::{
fmt::{FmtArg, FmtKind},
fmt_impls::basic_fmt_impls::primitive_static_panicfmt,
panic_val::{PanicVal, PanicVariant},
utils::{string_cap, PreFmtString, StartAndBytes},
};
#[cfg(all(test, not(miri)))]
mod tests;
impl PanicVal<'_> {
pub const fn from_char(c: char, fmtarg: FmtArg) -> Self {
let StartAndBytes { start, bytes } = match fmtarg.fmt_kind {
FmtKind::Display => {
let (arr, len) = char_to_utf8(c);
crate::utils::tail_byte_array::<{ string_cap::PREFMT }>(len, &arr)
}
FmtKind::Debug => {
let fmtchar = char_to_debug(c);
crate::utils::tail_byte_array(fmtchar.len(), &fmtchar.encoded)
}
};
let prefmt = unsafe { PreFmtString::new(start, bytes) };
PanicVal {
var: PanicVariant::PreFmt(prefmt),
}
}
}
primitive_static_panicfmt! {
fn[](&self: char, fmtarg) {
PanicVal::from_char(*self.0, fmtarg)
}
}
#[inline]
const fn hex_as_ascii(n: u8) -> u8 {
if n < 10 {
n + b'0'
} else {
n - 10 + b'A'
}
}
#[cfg(any(test, feature = "fmt"))]
pub(crate) const fn char_debug_len(c: char) -> usize {
let inner = match c {
'\t' | '\r' | '\n' | '\\' | '\'' => 2,
'\x00'..='\x1F' => 4,
_ => c.len_utf8(),
};
inner + 2
}
const fn char_to_utf8(char: char) -> ([u8; 4], usize) {
let u32 = char as u32;
match u32 {
0..=127 => ([u32 as u8, 0, 0, 0], 1),
0x80..=0x7FF => {
let b0 = 0b1100_0000 | (u32 >> 6) as u8;
let b1 = 0b1000_0000 | (u32 & 0b0011_1111) as u8;
([b0, b1, 0, 0], 2)
}
0x800..=0xFFFF => {
let b0 = 0b1110_0000 | (u32 >> 12) as u8;
let b1 = 0b1000_0000 | ((u32 >> 6) & 0b0011_1111) as u8;
let b2 = 0b1000_0000 | (u32 & 0b0011_1111) as u8;
([b0, b1, b2, 0], 3)
}
0x10000..=u32::MAX => {
let b0 = 0b1111_0000 | (u32 >> 18) as u8;
let b1 = 0b1000_0000 | ((u32 >> 12) & 0b0011_1111) as u8;
let b2 = 0b1000_0000 | ((u32 >> 6) & 0b0011_1111) as u8;
let b3 = 0b1000_0000 | (u32 & 0b0011_1111) as u8;
([b0, b1, b2, b3], 4)
}
}
}
pub const fn char_to_display(char: char) -> FmtChar {
let ([b0, b1, b2, b3], len) = char_to_utf8(char);
FmtChar {
encoded: [b0, b1, b2, b3, 0, 0, 0, 0, 0, 0, 0, 0],
len: len as u8,
}
}
pub const fn char_to_debug(c: char) -> FmtChar {
let ([b0, b1, b2, b3], len) = match c {
'\t' => (*br#"\t "#, 2),
'\r' => (*br#"\r "#, 2),
'\n' => (*br#"\n "#, 2),
'\\' => (*br#"\\ "#, 2),
'\'' => (*br#"\' "#, 2),
'\"' => (*br#"" "#, 1),
'\x00'..='\x1F' => {
let n = c as u8;
(
[b'\\', b'x', hex_as_ascii(n >> 4), hex_as_ascii(n & 0b1111)],
4,
)
}
_ => char_to_utf8(c),
};
let mut encoded = [b'\'', b0, b1, b2, b3, 0, 0, 0, 0, 0, 0, 0];
encoded[len + 1] = b'\'';
FmtChar {
encoded,
len: (len as u8) + 2,
}
}
#[derive(Copy, Clone)]
pub struct FmtChar {
encoded: [u8; 12],
len: u8,
}
impl FmtChar {
pub const fn encoded(&self) -> &[u8; 12] {
&self.encoded
}
pub const fn len(&self) -> usize {
self.len as usize
}
}