Reorganize

This commit is contained in:
2025-11-02 11:08:51 -08:00
parent 14d8a9b00c
commit fd48f75245
75 changed files with 8 additions and 17 deletions

View File

@@ -0,0 +1,136 @@
use std::fmt::Display;
use num::{Integer, Zero, cast::AsPrimitive};
/// Pretty-print a quantity of bytes
pub fn pp_bytes_si<T: Integer + Display + Zero + Clone + AsPrimitive<f64>>(bytes: T) -> String {
const UNITS: &[&str] = &["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
const THRESHOLD: f64 = 1000.0;
if bytes.is_zero() {
return "0 B".to_owned();
}
let bytes_f: f64 = bytes.as_();
let unit_index = (bytes_f.log10() / THRESHOLD.log10()).floor() as usize;
let unit_index = unit_index.min(UNITS.len() - 1);
let value = bytes_f / THRESHOLD.powi(unit_index as i32);
if unit_index == 0 {
format!("{} {}", bytes, UNITS[unit_index])
} else if value >= 100.0 {
format!("{:.0} {}", value, UNITS[unit_index])
} else if value >= 10.0 {
format!("{:.1} {}", value, UNITS[unit_index])
} else {
format!("{:.2} {}", value, UNITS[unit_index])
}
}
/// Pretty-print a quantity of bytes
pub fn pp_bytes_b2<T: Integer + Display + Zero + Clone + AsPrimitive<f64>>(bytes: T) -> String {
const UNITS: &[&str] = &["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
const THRESHOLD: f64 = 1024.0;
if bytes.is_zero() {
return "0 B".to_owned();
}
let bytes_f: f64 = bytes.as_();
let unit_index = (bytes_f.log2() / THRESHOLD.log2()).floor() as usize;
let unit_index = unit_index.min(UNITS.len() - 1);
let value = bytes_f / THRESHOLD.powi(unit_index as i32);
if unit_index == 0 {
format!("{} {}", bytes, UNITS[unit_index])
} else if value >= 100.0 {
format!("{:.0} {}", value, UNITS[unit_index])
} else if value >= 10.0 {
format!("{:.1} {}", value, UNITS[unit_index])
} else {
format!("{:.2} {}", value, UNITS[unit_index])
}
}
/// Pretty-print an integer with comma separators
pub fn pp_int_commas<T: Integer + Display>(value: T) -> String {
let s = value.to_string();
let mut result = String::new();
let bytes = s.as_bytes();
for (i, &byte) in bytes.iter().enumerate() {
if i > 0 && (bytes.len() - i).is_multiple_of(3) {
result.push(',');
}
result.push(byte as char);
}
result
}
/// Convert bytes to a hex string
#[inline]
pub fn to_hex(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{:02x}", b)).collect()
}
/// Parse a hex string as bytes
pub fn from_hex(hex_str: &str) -> Result<Vec<u8>, &'static str> {
if !hex_str.len().is_multiple_of(2) {
return Err("hex string must have even length");
}
let mut bytes = Vec::with_capacity(hex_str.len() / 2);
for chunk in hex_str.as_bytes().chunks(2) {
let hex_byte = std::str::from_utf8(chunk).map_err(|_err| "invalid UTF-8 in hex string")?;
let byte = u8::from_str_radix(hex_byte, 16).map_err(|_err| "invalid hex character")?;
bytes.push(byte);
}
Ok(bytes)
}
/// Truncate a string from the left, replacing the first character with "…" if truncated
pub fn truncate_left(length: usize, string: &str) -> String {
if string.chars().count() <= length {
return string.to_owned();
}
if length == 0 {
return String::new();
}
if length == 1 {
return "".to_owned();
}
let chars: Vec<char> = string.chars().collect();
let start_index = chars.len() - (length - 1);
let mut result = String::from("");
result.extend(&chars[start_index..]);
result
}
/// Truncate a string from the right, replacing the last character with "…" if truncated
pub fn truncate_right(length: usize, string: &str) -> String {
if string.chars().count() <= length {
return string.to_owned();
}
if length == 0 {
return String::new();
}
if length == 1 {
return "".to_owned();
}
let chars: Vec<char> = string.chars().collect();
let mut result = String::new();
result.extend(&chars[0..length - 1]);
result.push('…');
result
}