#![allow(dead_code)]
pub fn format_usd(n: f64) -> String {
if n == 0.0 {
return "$0.00".to_string();
}
if n.abs() < 0.01 {
return format!("${:.4}", n);
}
if n.abs() < 1.0 {
return format!("${:.3}", n);
}
format!("${:.2}", n)
}
pub fn format_int(n: i64) -> String {
if n < 0 {
return format!("-{}", format_int_unsigned(n.unsigned_abs()));
}
format_int_unsigned(n as u64)
}
pub fn format_uint(n: u64) -> String {
format_int_unsigned(n)
}
fn format_int_unsigned(n: u64) -> String {
let raw = n.to_string();
let bytes = raw.as_bytes();
let len = bytes.len();
if len <= 3 {
return raw;
}
let mut out = String::with_capacity(len + (len - 1) / 3);
let first = len % 3;
if first > 0 {
out.push_str(&raw[..first]);
if len > first {
out.push(',');
}
}
let mut i = first;
while i + 3 <= len {
out.push_str(&raw[i..i + 3]);
if i + 3 < len {
out.push(',');
}
i += 3;
}
out
}
pub fn render_table(rows: &[Vec<String>]) -> String {
if rows.is_empty() {
return String::new();
}
let mut widths: Vec<usize> = Vec::new();
for row in rows {
for (i, cell) in row.iter().enumerate() {
let w = cell.chars().count();
if i >= widths.len() {
widths.push(w);
} else if widths[i] < w {
widths[i] = w;
}
}
}
let mut out = String::new();
for (ri, row) in rows.iter().enumerate() {
let mut line = String::new();
for (i, cell) in row.iter().enumerate() {
if i > 0 {
line.push_str(" ");
}
line.push_str(cell);
let target = widths[i];
let cur = cell.chars().count();
if cur < target {
for _ in 0..(target - cur) {
line.push(' ');
}
}
}
let trimmed = line.trim_end();
out.push_str(trimmed);
if ri + 1 < rows.len() {
out.push('\n');
}
}
out
}
pub fn coerce_whole_f64_to_int(v: &mut serde_json::Value) {
use serde_json::{Number, Value};
match v {
Value::Number(n) => {
if !n.is_f64() {
return;
}
let Some(f) = n.as_f64() else {
return;
};
if !(f.is_finite() && f.fract() == 0.0) {
return;
}
if f >= 0.0 && f <= u64::MAX as f64 {
let int = f as u64;
if int as f64 == f {
*n = Number::from(int);
}
} else if f < 0.0 && f >= i64::MIN as f64 {
let int = f as i64;
if int as f64 == f {
*n = Number::from(int);
}
}
}
Value::Array(arr) => {
for item in arr {
coerce_whole_f64_to_int(item);
}
}
Value::Object(obj) => {
for (_, val) in obj.iter_mut() {
coerce_whole_f64_to_int(val);
}
}
_ => {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn format_usd_zero() {
assert_eq!(format_usd(0.0), "$0.00");
}
#[test]
fn format_usd_under_one_cent() {
assert_eq!(format_usd(0.0065), "$0.0065");
}
#[test]
fn format_usd_under_one_dollar() {
assert_eq!(format_usd(0.034), "$0.034");
assert_eq!(format_usd(0.0335), "$0.034");
}
#[test]
fn format_usd_above_one_dollar() {
assert_eq!(format_usd(1.234), "$1.23");
}
#[test]
fn format_int_thousands() {
assert_eq!(format_int(0), "0");
assert_eq!(format_int(999), "999");
assert_eq!(format_int(1_000), "1,000");
assert_eq!(format_int(5_100), "5,100");
assert_eq!(format_int(19_500), "19,500");
assert_eq!(format_int(1_000_000), "1,000,000");
}
#[test]
fn format_int_negative() {
assert_eq!(format_int(-1_500), "-1,500");
}
#[test]
fn render_table_pads_columns_and_trims_trailing_space() {
let rendered = render_table(&[
vec!["model".into(), "turns".into()],
vec!["claude-sonnet-4-6".into(), "12".into()],
vec!["claude-haiku".into(), "3".into()],
]);
let expected = "model turns\nclaude-sonnet-4-6 12\nclaude-haiku 3";
assert_eq!(rendered, expected);
}
#[test]
fn render_table_handles_em_dash_as_single_char_width() {
let rendered = render_table(&[vec!["k".into(), "v".into()], vec!["x".into(), "—".into()]]);
assert_eq!(rendered, "k v\nx —");
}
#[test]
fn render_table_returns_empty_for_empty_rows() {
let rendered = render_table(&[]);
assert_eq!(rendered, "");
}
}