feat: impl FromNapiValue
for serde_json::Number
, fix it for Null
, throw for impossible types (#1052)
fix #1013 Co-authored-by: zeroslope <jsx55242@foxmail.com>
This commit is contained in:
parent
c001038852
commit
ed12bd76bd
6 changed files with 117 additions and 22 deletions
crates/napi/src/bindgen_runtime/js_values
|
@ -1,4 +1,4 @@
|
|||
use serde_json::{Map, Value};
|
||||
use serde_json::{Map, Number, Value};
|
||||
|
||||
use crate::{
|
||||
bindgen_runtime::Null, check_status, sys, type_of, Error, JsObject, Result, Status, ValueType,
|
||||
|
@ -11,20 +11,7 @@ impl ToNapiValue for Value {
|
|||
match val {
|
||||
Value::Null => unsafe { Null::to_napi_value(env, Null) },
|
||||
Value::Bool(b) => unsafe { bool::to_napi_value(env, b) },
|
||||
Value::Number(n) => {
|
||||
if n.is_i64() {
|
||||
unsafe { i64::to_napi_value(env, n.as_i64().unwrap()) }
|
||||
} else if n.is_f64() {
|
||||
unsafe { f64::to_napi_value(env, n.as_f64().unwrap()) }
|
||||
} else {
|
||||
let n = n.as_u64().unwrap();
|
||||
if n > u32::MAX as u64 {
|
||||
todo!("impl BigInt")
|
||||
} else {
|
||||
unsafe { u32::to_napi_value(env, n as u32) }
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Number(n) => unsafe { Number::to_napi_value(env, n) },
|
||||
Value::String(s) => unsafe { String::to_napi_value(env, s) },
|
||||
Value::Array(arr) => unsafe { Vec::<Value>::to_napi_value(env, arr) },
|
||||
Value::Object(obj) => unsafe { Map::to_napi_value(env, obj) },
|
||||
|
@ -37,12 +24,7 @@ impl FromNapiValue for Value {
|
|||
let ty = type_of!(env, napi_val)?;
|
||||
let val = match ty {
|
||||
ValueType::Boolean => Value::Bool(unsafe { bool::from_napi_value(env, napi_val)? }),
|
||||
ValueType::Number => {
|
||||
return Err(Error::new(
|
||||
Status::InvalidArg,
|
||||
"Js Number is not be able to convert to rust.".to_owned(),
|
||||
));
|
||||
}
|
||||
ValueType::Number => Value::Number(unsafe { Number::from_napi_value(env, napi_val)? }),
|
||||
ValueType::String => Value::String(unsafe { String::from_napi_value(env, napi_val)? }),
|
||||
ValueType::Object => {
|
||||
let mut is_arr = false;
|
||||
|
@ -59,7 +41,37 @@ impl FromNapiValue for Value {
|
|||
}
|
||||
#[cfg(feature = "napi6")]
|
||||
ValueType::BigInt => todo!(),
|
||||
_ => Value::Null,
|
||||
ValueType::Null => Value::Null,
|
||||
ValueType::Function => {
|
||||
return Err(Error::new(
|
||||
Status::InvalidArg,
|
||||
"JS functions cannot be represented as a serde_json::Value".to_owned(),
|
||||
))
|
||||
}
|
||||
ValueType::Undefined => {
|
||||
return Err(Error::new(
|
||||
Status::InvalidArg,
|
||||
"undefined cannot be represented as a serde_json::Value".to_owned(),
|
||||
))
|
||||
}
|
||||
ValueType::Symbol => {
|
||||
return Err(Error::new(
|
||||
Status::InvalidArg,
|
||||
"JS symbols cannot be represented as a serde_json::Value".to_owned(),
|
||||
))
|
||||
}
|
||||
ValueType::External => {
|
||||
return Err(Error::new(
|
||||
Status::InvalidArg,
|
||||
"External JS objects cannot be represented as a serde_json::Value".to_owned(),
|
||||
))
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
Status::InvalidArg,
|
||||
"Unknown JS variables cannot be represented as a serde_json::Value".to_owned(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(val)
|
||||
|
@ -96,3 +108,50 @@ impl FromNapiValue for Map<String, Value> {
|
|||
Ok(map)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToNapiValue for Number {
|
||||
unsafe fn to_napi_value(env: sys::napi_env, n: Self) -> Result<sys::napi_value> {
|
||||
if n.is_i64() {
|
||||
unsafe { i64::to_napi_value(env, n.as_i64().unwrap()) }
|
||||
} else if n.is_f64() {
|
||||
unsafe { f64::to_napi_value(env, n.as_f64().unwrap()) }
|
||||
} else {
|
||||
let n = n.as_u64().unwrap();
|
||||
if n > u32::MAX as u64 {
|
||||
todo!("impl BigInt")
|
||||
} else {
|
||||
unsafe { u32::to_napi_value(env, n as u32) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromNapiValue for Number {
|
||||
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
||||
let n = unsafe { f64::from_napi_value(env, napi_val)? };
|
||||
// Try to auto-convert to integers
|
||||
let n = if n.trunc() == n {
|
||||
if n >= 0.0f64 && n <= u32::MAX as f64 {
|
||||
// This can be represented as u32
|
||||
Some(Number::from(n as u32))
|
||||
} else if n < 0.0f64 && n >= i32::MIN as f64 {
|
||||
Some(Number::from(n as i32))
|
||||
} else {
|
||||
// must be a float
|
||||
Number::from_f64(n)
|
||||
}
|
||||
} else {
|
||||
// must be a float
|
||||
Number::from_f64(n)
|
||||
};
|
||||
|
||||
let n = n.ok_or_else(|| {
|
||||
Error::new(
|
||||
Status::InvalidArg,
|
||||
"Failed to convert js number to serde_json::Number".to_owned(),
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(n)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue