use std::fmt::{self, Write};
use unicode_general_category::{GeneralCategory, get_general_category};
pub fn string_repr_fmt(s: &str, f: &mut impl Write) -> fmt::Result {
let quote = if s.contains('\'') && !s.contains('"') {
'"'
} else {
'\''
};
f.write_char(quote)?;
for c in s.chars() {
match c {
'\\' => f.write_str("\\\\")?,
'\n' => f.write_str("\\n")?,
'\t' => f.write_str("\\t")?,
'\r' => f.write_str("\\r")?,
_ if c == quote => {
f.write_char('\\')?;
f.write_char(quote)?;
}
_ if repr_needs_escape(c) => write_char_escape(c, f)?,
_ => f.write_char(c)?,
}
}
f.write_char(quote)
}
fn repr_needs_escape(c: char) -> bool {
c != ' '
&& matches!(
get_general_category(c),
GeneralCategory::Control
| GeneralCategory::Format
| GeneralCategory::Surrogate
| GeneralCategory::PrivateUse
| GeneralCategory::Unassigned
| GeneralCategory::LineSeparator
| GeneralCategory::ParagraphSeparator
| GeneralCategory::SpaceSeparator
)
}
fn write_char_escape(c: char, f: &mut impl Write) -> fmt::Result {
let cp = c as u32;
if cp <= 0xFF {
write!(f, "\\x{cp:02x}")
} else if cp <= 0xFFFF {
write!(f, "\\u{cp:04x}")
} else {
write!(f, "\\U{cp:08x}")
}
}
#[derive(Debug)]
pub struct StringRepr<'a>(pub &'a str);
impl fmt::Display for StringRepr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
string_repr_fmt(self.0, f)
}
}
pub fn bytes_repr_fmt(bytes: &[u8], f: &mut impl Write) -> fmt::Result {
let has_single = bytes.contains(&b'\'');
let has_double = bytes.contains(&b'"');
let quote = if has_single && !has_double { '"' } else { '\'' };
f.write_char('b')?;
f.write_char(quote)?;
for &byte in bytes {
match byte {
b'\\' => f.write_str("\\\\")?,
b'\t' => f.write_str("\\t")?,
b'\n' => f.write_str("\\n")?,
b'\r' => f.write_str("\\r")?,
b'\'' if quote == '\'' => f.write_str("\\'")?,
b'"' if quote == '"' => f.write_str("\\\"")?,
0x20..=0x7e => f.write_char(byte as char)?,
_ => write!(f, "\\x{byte:02x}")?,
}
}
f.write_char(quote)
}
#[must_use]
#[expect(clippy::missing_panics_doc, reason = "writing to a String cannot fail")]
pub fn bytes_repr(bytes: &[u8]) -> String {
let mut result = String::new();
bytes_repr_fmt(bytes, &mut result).unwrap();
result
}
pub struct FormatFloat(pub f64);
impl fmt::Display for FormatFloat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let v = self.0;
if v.is_nan() {
return f.write_str("nan");
}
if v.is_sign_negative() {
f.write_char('-')?;
}
if v.is_infinite() {
return f.write_str("inf");
}
let mut sci = StackStr::new();
write!(sci, "{:e}", v.abs())?;
let sci = sci.as_str();
let (mantissa, exp_str) = sci.split_once('e').ok_or(fmt::Error)?;
let (int_part, frac) = mantissa.split_once('.').unwrap_or((mantissa, ""));
let exp10: i32 = exp_str.parse().map_err(|_| fmt::Error)?;
let ndigits = int_part.len() + frac.len();
let decpt = exp10 + 1;
if !(-4..16).contains(&exp10) {
f.write_str(int_part)?;
if !frac.is_empty() {
f.write_char('.')?;
f.write_str(frac)?;
}
let exp_sign = if exp10 < 0 { '-' } else { '+' };
write!(f, "e{exp_sign}{:02}", exp10.unsigned_abs())
} else if decpt <= 0 {
f.write_str("0.")?;
for _ in 0..-decpt {
f.write_char('0')?;
}
f.write_str(int_part)?;
f.write_str(frac)
} else {
let decpt = usize::try_from(decpt).expect("decpt is positive in this branch");
if decpt >= ndigits {
f.write_str(int_part)?;
f.write_str(frac)?;
for _ in 0..decpt - ndigits {
f.write_char('0')?;
}
f.write_str(".0")
} else {
f.write_str(int_part)?;
let split = decpt - int_part.len();
f.write_str(&frac[..split])?;
f.write_char('.')?;
f.write_str(&frac[split..])
}
}
}
}
struct StackStr {
buf: [u8; 32],
len: usize,
}
impl StackStr {
fn new() -> Self {
Self { buf: [0; 32], len: 0 }
}
fn as_str(&self) -> &str {
str::from_utf8(&self.buf[..self.len]).unwrap_or("")
}
}
impl fmt::Write for StackStr {
fn write_str(&mut self, s: &str) -> fmt::Result {
let end = self.len.checked_add(s.len()).ok_or(fmt::Error)?;
let slot = self.buf.get_mut(self.len..end).ok_or(fmt::Error)?;
slot.copy_from_slice(s.as_bytes());
self.len = end;
Ok(())
}
}
#[must_use]
pub fn utf8_error_reason(first_bad_byte: u8, error_len: Option<usize>) -> &'static str {
if error_len.is_none() {
"unexpected end of data"
} else if (0xC2..=0xF4).contains(&first_bad_byte) {
"invalid continuation byte"
} else {
"invalid start byte"
}
}
#[must_use]
pub fn format_offset_timedelta_repr(offset_seconds: i32) -> String {
const SECONDS_PER_DAY: i32 = 86_400;
let days = offset_seconds.div_euclid(SECONDS_PER_DAY);
let seconds = offset_seconds.rem_euclid(SECONDS_PER_DAY);
if days == 0 && seconds == 0 {
"datetime.timedelta(0)".to_owned()
} else {
let mut out = String::from("datetime.timedelta(");
if days != 0 {
write!(out, "days={days}").expect("writing to String never fails");
}
if seconds != 0 {
if days != 0 {
out.push_str(", ");
}
write!(out, "seconds={seconds}").expect("writing to String never fails");
}
out.push(')');
out
}
}