use ax_core::Value;
pub fn infer_scalar(raw: &str) -> Value {
if raw.is_empty() {
return Value::Null;
}
if let Ok(i) = raw.parse::<i64>() {
return Value::Int(i);
}
if let Ok(f) = raw.parse::<f64>() {
if f.is_finite() {
return Value::Float(f);
}
}
match raw {
"true" | "TRUE" | "True" => return Value::Bool(true),
"false" | "FALSE" | "False" => return Value::Bool(false),
_ => {}
}
Value::Str(raw.to_string())
}
pub fn json_to_value(j: &serde_json::Value) -> Value {
use serde_json::Value as J;
match j {
J::Null => Value::Null,
J::Bool(b) => Value::Bool(*b),
J::Number(n) => {
if let Some(i) = n.as_i64() {
Value::Int(i)
} else if let Some(f) = n.as_f64() {
if f.is_finite() {
Value::Float(f)
} else {
Value::Null
}
} else {
Value::Str(n.to_string())
}
}
J::String(s) => Value::Str(s.clone()),
J::Array(_) | J::Object(_) => Value::Str(j.to_string()),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scalar_inference_precedence() {
assert!(matches!(infer_scalar(""), Value::Null));
assert!(matches!(infer_scalar("42"), Value::Int(42)));
assert!(matches!(infer_scalar("3.14"), Value::Float(_)));
assert!(matches!(infer_scalar("true"), Value::Bool(true)));
assert!(matches!(infer_scalar("false"), Value::Bool(false)));
assert!(matches!(infer_scalar("False"), Value::Bool(false)));
assert!(matches!(infer_scalar("hello"), Value::Str(_)));
assert!(matches!(infer_scalar("inf"), Value::Str(_)));
assert!(matches!(infer_scalar("nan"), Value::Str(_)));
}
#[test]
fn json_scalar_conversion() {
assert!(matches!(
json_to_value(&serde_json::json!(null)),
Value::Null
));
assert!(matches!(
json_to_value(&serde_json::json!(7)),
Value::Int(7)
));
assert!(matches!(
json_to_value(&serde_json::json!(1.5)),
Value::Float(_)
));
assert!(matches!(
json_to_value(&serde_json::json!(true)),
Value::Bool(true)
));
assert!(matches!(
json_to_value(&serde_json::json!("s")),
Value::Str(_)
));
assert!(matches!(
json_to_value(&serde_json::json!({"k": 1})),
Value::Str(_)
));
}
}