#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Style {
Typeless,
Float,
Integer,
}
pub(crate) fn value(bits: u32, style: Style) -> String {
match style {
Style::Float => float(bits),
Style::Integer => integer(bits),
Style::Typeless => {
let exponent = (bits >> 23) & 0xff;
if (exponent == 0 || exponent == 0xff) && bits != 0x8000_0000 {
integer(bits)
} else {
float(bits)
}
}
}
}
pub(crate) fn integer(bits: u32) -> String {
let signed = bits.cast_signed();
if (-10000..=10000).contains(&signed) {
signed.to_string()
} else {
format!("0x{bits:08x}")
}
}
pub(crate) fn float(bits: u32) -> String {
let value = f32::from_bits(bits);
special(
value.is_nan(),
value.is_infinite(),
bits >> 31 != 0,
bits == 0xffc0_0000,
)
.unwrap_or_else(|| format!("{:.6}", f64::from(value)))
}
pub(crate) fn double(low: u32, high: u32) -> String {
let bits = (u64::from(high) << 32) | u64::from(low);
let value = f64::from_bits(bits);
let text = special(
value.is_nan(),
value.is_infinite(),
high >> 31 != 0,
bits == 0xfff8_0000_0000_0000,
)
.unwrap_or_else(|| format!("{value:.6}"));
format!("{text}l")
}
fn special(nan: bool, infinite: bool, negative: bool, indefinite: bool) -> Option<String> {
let sign = if negative { "-" } else { "" };
if infinite {
Some(format!("{sign}1.#INF00"))
} else if indefinite {
Some("-1.#IND00".to_owned())
} else if nan {
Some(format!("{sign}1.#QNAN0"))
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn floats_and_integers() {
assert_eq!(float(0x3f80_0000), "1.000000");
assert_eq!(float(0x7149_f2ca), "1000000015047466219876688855040.000000");
assert_eq!(float(0x8000_0000), "-0.000000");
assert_eq!(float(0x7f80_0000), "1.#INF00");
assert_eq!(integer(0xffff_fc7c), "-900");
assert_eq!(integer(10001), "0x00002711");
assert_eq!(value(0x8000_0000, Style::Typeless), "-0.000000");
assert_eq!(value(1, Style::Typeless), "1");
assert_eq!(value(0x3f00_0000, Style::Typeless), "0.500000");
}
}