use anyhow::{Result, bail};
pub fn fmt_num(v: f64) -> String {
let r = (v * 1_000_000.0).round() / 1_000_000.0;
let r = if r == 0.0 { 0.0 } else { r };
format!("{r}")
}
pub fn split_num_unit(v: &str) -> Option<(f64, &str)> {
let v = v.trim();
let end = v
.find(|c: char| !(c.is_ascii_digit() || matches!(c, '.' | '-' | '+' | 'e' | 'E')))
.unwrap_or(v.len());
let (num, unit) = v.split_at(end);
let n: f64 = num.parse().ok()?;
Some((n, unit.trim()))
}
pub fn scale_length(v: &str, s: f64) -> String {
match split_num_unit(v) {
Some((n, "")) => fmt_num(n * s),
Some((n, "px")) => format!("{}px", fmt_num(n * s)),
_ => v.to_string(),
}
}
pub fn affine_length(v: &str, s: f64, t: f64) -> String {
match split_num_unit(v) {
Some((n, "")) => fmt_num(s * n + t),
Some((n, "px")) => format!("{}px", fmt_num(s * n + t)),
_ => v.to_string(),
}
}
pub fn parse_px(v: &str) -> Result<f64> {
match split_num_unit(v) {
Some((n, "" | "px")) => Ok(n),
_ => bail!("unsupported length '{v}' (need unitless or px, or add a viewBox)"),
}
}
pub fn parse_num_list(v: &str) -> Vec<f64> {
v.split([',', ' ', '\t', '\n', '\r'])
.filter(|t| !t.is_empty())
.filter_map(|t| t.parse::<f64>().ok())
.collect()
}
pub fn scale_len_list(v: &str, s: f64) -> String {
v.split([',', ' ', '\t', '\n', '\r'])
.filter(|t| !t.is_empty())
.map(|t| scale_length(t, s))
.collect::<Vec<_>>()
.join(" ")
}