From 37f1cc04d06af3760d2717e582edd314a842d258 Mon Sep 17 00:00:00 2001 From: Paul K Date: Fri, 14 Jun 2024 14:50:30 -0400 Subject: [PATCH] fix: handle fractional numbers properly (#2) --- js-sandbox/Cargo.toml | 3 ++- js-sandbox/src/script.rs | 55 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/js-sandbox/Cargo.toml b/js-sandbox/Cargo.toml index 3e07ad8..47a8e96 100644 --- a/js-sandbox/Cargo.toml +++ b/js-sandbox/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "js-sandbox-ios" -version = "0.1.0" +version = "0.1.1" description = "Execute JavaScript code from Rust in a secure sandbox, and transport data to/from JS plug-ins." repository = "https://github.com/Bromeon/js-sandbox" documentation = "https://docs.rs/js-sandbox/0.2.0-rc.1" @@ -16,3 +16,4 @@ js-sandbox-macros = { path = "../js-sandbox-macros", version = "=0.2.0-rc.1" } deno_core = "0.238.0" serde_json = "1.0.106" serde = { version = "1.0.188", features = ["derive"] } +tracing = "0.1.40" diff --git a/js-sandbox/src/script.rs b/js-sandbox/src/script.rs index 984db06..80a8b0c 100644 --- a/js-sandbox/src/script.rs +++ b/js-sandbox/src/script.rs @@ -200,13 +200,66 @@ impl Script { }; let deserialized_value = serde_v8::from_v8::(scope, func_res) .with_context(|| "Could not serialize func res")?; - let result: CallResult = serde_json::from_value(deserialized_value)?; + let sanitized_value = Self::sanitize_number(deserialized_value)?; + let result: CallResult = serde_json::from_value(sanitized_value)?; match result { CallResult::Error { error } => Err(JsError::Runtime(AnyError::msg(error))), CallResult::Result(r) => Ok(r), } } + fn sanitize_number(value: serde_json::Value) -> Result { + match value { + serde_json::Value::Number(number) => { + if number.is_f64() { + let f = number.as_f64().ok_or_else(|| { + JsError::Runtime(AnyError::msg("Failed to convert number to f64")) + })?; + + if f.fract() == 0.0 { + return Ok(serde_json::Value::Number(serde_json::Number::from( + f as i64, + ))); + } + + Ok(serde_json::Value::Number( + serde_json::Number::from_f64(f).ok_or_else(|| { + JsError::Runtime(AnyError::msg("Failed to convert f64 to number")) + })?, + )) + } else if number.is_u64() { + Ok(serde_json::Value::Number( + number + .as_i64() + .ok_or_else(|| { + JsError::Runtime(AnyError::msg("Failed to convert number to i64")) + })? + .into(), + )) + } else if number.is_i64() { + Ok(serde_json::Value::Number(number)) + } else { + Err(JsError::Runtime(AnyError::msg("Failed to convert number"))) + } + } + serde_json::Value::Object(map) => { + let mut new_map = serde_json::Map::new(); + for (key, value) in map { + new_map.insert(key, Self::sanitize_number(value)?); + } + Ok(serde_json::Value::Object(new_map)) + } + serde_json::Value::Array(vec) => { + let mut new_vec = Vec::new(); + for value in vec { + new_vec.push(Self::sanitize_number(value)?); + } + Ok(serde_json::Value::Array(new_vec)) + } + _ => Ok(value), + } + } + pub fn bind_api<'a, A>(&'a mut self) -> A where A: JsApi<'a>,