Skip to content

Commit

Permalink
fix: serde-v8 conversion functions don't work well with `serde_json…
Browse files Browse the repository at this point in the history
…::Value`
  • Loading branch information
chubei committed Nov 27, 2023
1 parent 34381ad commit 34e3e39
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 7 deletions.
84 changes: 84 additions & 0 deletions dozer-deno/src/runtime/conversion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use deno_runtime::{
deno_core::{
anyhow::{bail, Context as _},
error::AnyError,
},
deno_napi::v8::{self, HandleScope, Local},
};
use dozer_types::serde_json::{self, Number};

pub fn to_v8<'s>(
scope: &mut HandleScope<'s>,
value: serde_json::Value,
) -> Result<Local<'s, v8::Value>, AnyError> {
match value {
serde_json::Value::Null => Ok(v8::null(scope).into()),
serde_json::Value::Bool(value) => Ok(v8::Boolean::new(scope, value).into()),
serde_json::Value::Number(value) => {
let value = value.as_f64().context("number is not a f64")?;
Ok(v8::Number::new(scope, value).into())
}
serde_json::Value::String(value) => Ok(v8::String::new(scope, &value)
.context(format!("failed to create string {}", value))?
.into()),
serde_json::Value::Array(values) => {
let array = v8::Array::new(scope, values.len() as i32);
for (index, value) in values.into_iter().enumerate() {
let value = to_v8(scope, value)?;
array.set_index(scope, index as u32, value);
}
Ok(array.into())
}
serde_json::Value::Object(map) => {
let object = v8::Object::new(scope);
for (key, value) in map.into_iter() {
let key = v8::String::new(scope, &key)
.context(format!("failed to create key {}", key))?;
let value = to_v8(scope, value)?;
object.set(scope, key.into(), value);
}
Ok(object.into())
}
}
}

pub fn from_v8<'s>(
scope: &mut HandleScope<'s>,
value: Local<'s, v8::Value>,
) -> Result<serde_json::Value, AnyError> {
if value.is_null_or_undefined() {
Ok(serde_json::Value::Null)
} else if value.is_boolean() {
Ok(serde_json::Value::Bool(value.boolean_value(scope)))
} else if value.is_number() {
Ok(serde_json::Value::Number(
Number::from_f64(value.number_value(scope).context("number is not a f64")?)
.context("f64 number cannot be represented in JSON")?,
))
} else if let Ok(value) = TryInto::<Local<v8::String>>::try_into(value) {
Ok(serde_json::Value::String(value.to_rust_string_lossy(scope)))
} else if let Ok(value) = TryInto::<Local<v8::Array>>::try_into(value) {
let mut values = Vec::new();
for index in 0..value.length() {
let value = value.get_index(scope, index).unwrap();
let value = from_v8(scope, value)?;
values.push(value);
}
Ok(serde_json::Value::Array(values))
} else if let Ok(value) = TryInto::<Local<v8::Object>>::try_into(value) {
let mut map = serde_json::Map::new();
let Some(keys) = value.get_own_property_names(scope, Default::default()) else {
return Ok(serde_json::Value::Object(map));
};
for index in 0..keys.length() {
let key = keys.get_index(scope, index).unwrap();
let value = value.get(scope, key).unwrap();
let key = key.to_rust_string_lossy(scope);
let value = from_v8(scope, value)?;
map.insert(key, value);
}
Ok(serde_json::Value::Object(map))
} else {
bail!("cannot convert v8 value to JSON because its type is not supported")
}
}
12 changes: 5 additions & 7 deletions dozer-deno/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@ use std::{
};

use deno_runtime::{
deno_core::{
anyhow::Context as _,
error::AnyError,
serde_v8::{from_v8, to_v8},
JsRuntime, ModuleSpecifier,
},
deno_core::{anyhow::Context as _, error::AnyError, JsRuntime, ModuleSpecifier},
deno_napi::v8::{self, undefined, Function, Global, Local},
};
use dozer_types::{
Expand All @@ -34,6 +29,8 @@ use tokio::{
task::{JoinHandle, LocalSet},
};

use self::conversion::{from_v8, to_v8};

#[derive(Debug)]
pub struct Runtime {
work_sender: mpsc::Sender<Work>,
Expand Down Expand Up @@ -270,8 +267,9 @@ fn call_function(
.collect::<Result<Vec<_>, _>>()?;
let result = Local::new(scope, function).call(scope, recv.into(), &args);
result
.map(|value| from_v8(scope, value).map_err(Into::into))
.map(|value| from_v8(scope, value))
.unwrap_or(Ok(Value::Null))
}

mod conversion;
mod js_runtime;

0 comments on commit 34e3e39

Please sign in to comment.