Initial Rust WSON serde implementation
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
/// Formats `f64` with Java `Double.toString` semantics as closely as Rust's
|
||||
/// shortest-roundtrip formatting allows.
|
||||
pub fn format_java_double(value: f64) -> String {
|
||||
if value.is_nan() {
|
||||
return "NaN".to_string();
|
||||
}
|
||||
if value == f64::INFINITY {
|
||||
return "Infinity".to_string();
|
||||
}
|
||||
if value == f64::NEG_INFINITY {
|
||||
return "-Infinity".to_string();
|
||||
}
|
||||
if value == 0.0 {
|
||||
return if value.is_sign_negative() {
|
||||
"-0.0".to_string()
|
||||
} else {
|
||||
"0.0".to_string()
|
||||
};
|
||||
}
|
||||
|
||||
let scientific = format!("{value:e}");
|
||||
let (mantissa, exp) = scientific
|
||||
.split_once('e')
|
||||
.expect("lowerexp formatting always contains e");
|
||||
let exponent: i32 = exp.parse().expect("lowerexp exponent is an integer");
|
||||
let negative = mantissa.starts_with('-');
|
||||
let mantissa = mantissa.trim_start_matches('-');
|
||||
let digits: String = mantissa.chars().filter(|c| *c != '.').collect();
|
||||
|
||||
// Java uses plain decimal notation for 1e-3 <= abs(value) < 1e7.
|
||||
if (-3..7).contains(&exponent) {
|
||||
let point_pos = exponent + 1;
|
||||
let mut out = String::new();
|
||||
if negative {
|
||||
out.push('-');
|
||||
}
|
||||
if point_pos <= 0 {
|
||||
out.push_str("0.");
|
||||
for _ in 0..(-point_pos) {
|
||||
out.push('0');
|
||||
}
|
||||
out.push_str(&digits);
|
||||
} else if point_pos as usize >= digits.len() {
|
||||
out.push_str(&digits);
|
||||
for _ in 0..(point_pos as usize - digits.len()) {
|
||||
out.push('0');
|
||||
}
|
||||
out.push_str(".0");
|
||||
} else {
|
||||
let split = point_pos as usize;
|
||||
out.push_str(&digits[..split]);
|
||||
out.push('.');
|
||||
out.push_str(&digits[split..]);
|
||||
}
|
||||
out
|
||||
} else {
|
||||
let mut out = String::new();
|
||||
if negative {
|
||||
out.push('-');
|
||||
}
|
||||
out.push(digits.as_bytes()[0] as char);
|
||||
out.push('.');
|
||||
if digits.len() == 1 {
|
||||
out.push('0');
|
||||
} else {
|
||||
out.push_str(&digits[1..]);
|
||||
}
|
||||
out.push('E');
|
||||
out.push_str(&exponent.to_string());
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::format_java_double;
|
||||
|
||||
#[test]
|
||||
fn java_double_formatting() {
|
||||
assert_eq!(format_java_double(1.0), "1.0");
|
||||
assert_eq!(format_java_double(36.0), "36.0");
|
||||
assert_eq!(format_java_double(0.001), "0.001");
|
||||
assert_eq!(format_java_double(0.0001), "1.0E-4");
|
||||
assert_eq!(format_java_double(9_999_999.0), "9999999.0");
|
||||
assert_eq!(format_java_double(10_000_000.0), "1.0E7");
|
||||
assert_eq!(format_java_double(1e22), "1.0E22");
|
||||
assert_eq!(format_java_double(1e-7), "1.0E-7");
|
||||
assert_eq!(format_java_double(-2.5), "-2.5");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user