use super::JsValue;
pub fn to_number(val: &JsValue) -> f64 {
match val {
JsValue::Number(n) => *n,
JsValue::Boolean(true) => 1.0,
JsValue::Boolean(false) => 0.0,
JsValue::Null => 0.0,
JsValue::Undefined => f64::NAN,
JsValue::String(s) => string_to_number(s),
}
}
pub fn string_to_number(s: &str) -> f64 {
let trimmed = s.trim();
if trimmed.is_empty() {
return 0.0;
}
if let Some(rest) = trimmed.strip_prefix("0x").or_else(|| trimmed.strip_prefix("0X")) {
return i64::from_str_radix(rest, 16)
.map(|v| v as f64)
.unwrap_or(f64::NAN);
}
if let Some(rest) = trimmed.strip_prefix("0o").or_else(|| trimmed.strip_prefix("0O")) {
return i64::from_str_radix(rest, 8)
.map(|v| v as f64)
.unwrap_or(f64::NAN);
}
if let Some(rest) = trimmed.strip_prefix("0b").or_else(|| trimmed.strip_prefix("0B")) {
return i64::from_str_radix(rest, 2)
.map(|v| v as f64)
.unwrap_or(f64::NAN);
}
match trimmed {
"Infinity" | "+Infinity" => f64::INFINITY,
"-Infinity" => f64::NEG_INFINITY,
_ => trimmed.parse::<f64>().unwrap_or(f64::NAN),
}
}
pub fn to_string(val: &JsValue) -> String {
match val {
JsValue::Number(n) => number_to_string(*n),
JsValue::String(s) => s.clone(),
JsValue::Boolean(b) => b.to_string(),
JsValue::Null => "null".to_string(),
JsValue::Undefined => "undefined".to_string(),
}
}
pub fn number_to_string(n: f64) -> String {
if n.is_nan() {
"NaN".to_string()
} else if n.is_infinite() {
if n.is_sign_positive() {
"Infinity".to_string()
} else {
"-Infinity".to_string()
}
} else if n == 0.0 {
"0".to_string()
} else if n.fract() == 0.0 && n.abs() < 1e15 {
format!("{}", n as i64)
} else {
format!("{n}")
}
}
#[inline]
pub fn to_boolean(val: &JsValue) -> bool {
val.is_truthy()
}
pub fn to_int32(val: &JsValue) -> i32 {
let n = to_number(val);
if n.is_nan() || n.is_infinite() || n == 0.0 {
return 0;
}
let int_val = n.trunc();
const TWO_POW_32: f64 = 4294967296.0; let int32bit = int_val.rem_euclid(TWO_POW_32);
const TWO_POW_31: f64 = 2147483648.0; if int32bit >= TWO_POW_31 {
(int32bit - TWO_POW_32) as i32
} else {
int32bit as i32
}
}
pub fn to_uint32(val: &JsValue) -> u32 {
let n = to_number(val);
if n.is_nan() || n.is_infinite() || n == 0.0 {
return 0;
}
let int_val = n.trunc();
const TWO_POW_32: f64 = 4294967296.0;
let int32bit = int_val.rem_euclid(TWO_POW_32);
int32bit as u32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_number() {
assert_eq!(to_number(&JsValue::Number(42.0)), 42.0);
assert_eq!(to_number(&JsValue::Boolean(true)), 1.0);
assert_eq!(to_number(&JsValue::Boolean(false)), 0.0);
assert_eq!(to_number(&JsValue::Null), 0.0);
assert!(to_number(&JsValue::Undefined).is_nan());
assert_eq!(to_number(&JsValue::String("".into())), 0.0);
assert_eq!(to_number(&JsValue::String("42".into())), 42.0);
assert_eq!(to_number(&JsValue::String(" 3.14 ".into())), 3.14);
assert!(to_number(&JsValue::String("abc".into())).is_nan());
assert_eq!(to_number(&JsValue::String("0xff".into())), 255.0);
assert_eq!(to_number(&JsValue::String("0o77".into())), 63.0);
assert_eq!(to_number(&JsValue::String("0b1010".into())), 10.0);
assert_eq!(to_number(&JsValue::String("Infinity".into())), f64::INFINITY);
assert_eq!(to_number(&JsValue::String("-Infinity".into())), f64::NEG_INFINITY);
}
#[test]
fn test_number_to_string() {
assert_eq!(number_to_string(42.0), "42");
assert_eq!(number_to_string(-5.0), "-5");
assert_eq!(number_to_string(3.14), "3.14");
assert_eq!(number_to_string(0.0), "0");
assert_eq!(number_to_string(-0.0), "0");
assert_eq!(number_to_string(f64::NAN), "NaN");
assert_eq!(number_to_string(f64::INFINITY), "Infinity");
assert_eq!(number_to_string(f64::NEG_INFINITY), "-Infinity");
assert_eq!(number_to_string(1e15), "1000000000000000");
}
#[test]
fn test_to_string() {
assert_eq!(to_string(&JsValue::Number(42.0)), "42");
assert_eq!(to_string(&JsValue::Boolean(true)), "true");
assert_eq!(to_string(&JsValue::Null), "null");
assert_eq!(to_string(&JsValue::Undefined), "undefined");
assert_eq!(to_string(&JsValue::String("hello".into())), "hello");
}
#[test]
fn test_to_int32() {
assert_eq!(to_int32(&JsValue::Number(42.0)), 42);
assert_eq!(to_int32(&JsValue::Number(-1.0)), -1);
assert_eq!(to_int32(&JsValue::Number(4294967296.0)), 0); assert_eq!(to_int32(&JsValue::Number(f64::NAN)), 0);
assert_eq!(to_int32(&JsValue::Number(f64::INFINITY)), 0);
}
#[test]
fn test_to_uint32() {
assert_eq!(to_uint32(&JsValue::Number(42.0)), 42);
assert_eq!(to_uint32(&JsValue::Number(-1.0)), 4294967295); assert_eq!(to_uint32(&JsValue::Number(f64::NAN)), 0);
}
}