Skip to content

Commit d662de7

Browse files
committed
Improve BigInt support
Now fallback to toString if toJSON is missing
1 parent 73f3512 commit d662de7

File tree

1 file changed

+84
-40
lines changed

1 file changed

+84
-40
lines changed

src/de.rs

Lines changed: 84 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,18 @@ impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
213213
return result;
214214
}
215215

216-
// FIXME: Replace type_of when https://github.com/DelSkayn/rquickjs/pull/458 is merged.
217-
if (get_class_id(&self.value) == ClassId::BigInt as u32
218-
|| self.value.type_of() == rquickjs::Type::BigInt)
219-
&& let Some(f) = get_to_json(&self.value)
220-
{
221-
let v: Value = f.call((This(self.value.clone()),)).map_err(Error::new)?;
222-
self.value = v;
223-
return self.deserialize_any(visitor);
216+
if get_class_id(&self.value) == ClassId::BigInt as u32 || self.value.is_big_int() {
217+
if let Some(f) = get_to_json(&self.value) {
218+
let v: Value = f.call((This(self.value.clone()),)).map_err(Error::new)?;
219+
self.value = v;
220+
return self.deserialize_any(visitor);
221+
}
222+
223+
if let Some(f) = get_to_string(&self.value) {
224+
let v: Value = f.call((This(self.value.clone()),)).map_err(Error::new)?;
225+
self.value = v;
226+
return self.deserialize_any(visitor);
227+
}
224228
}
225229

226230
Err(Error::new(Exception::throw_type(
@@ -482,39 +486,26 @@ impl<'de> de::SeqAccess<'de> for SeqAccess<'_, 'de> {
482486

483487
/// Checks if the value is an object and contains a single `toJSON` function.
484488
pub(crate) fn get_to_json<'a>(value: &Value<'a>) -> Option<Function<'a>> {
485-
let f = unsafe {
486-
JS_GetProperty(
487-
value.ctx().as_raw().as_ptr(),
488-
value.as_raw(),
489-
PredefinedAtom::ToJSON as u32,
490-
)
491-
};
492-
let f = unsafe { Value::from_raw(value.ctx().clone(), f) };
493-
494-
if f.is_function()
495-
&& let Some(f) = f.into_function()
496-
{
497-
Some(f)
498-
} else {
499-
None
500-
}
489+
get_function(value, PredefinedAtom::ToJSON)
501490
}
502491

503492
/// Checks if the value is an object and contains a `valueOf` function.
504493
fn get_valueof<'a>(value: &Value<'a>) -> Option<Function<'a>> {
505-
if let Some(o) = value.as_object() {
506-
let value_of = o.get("valueOf").ok();
507-
value_of.clone()
508-
} else {
509-
None
510-
}
494+
get_function(value, PredefinedAtom::ValueOf)
511495
}
512496

513-
/// Checks if the value is an object and contains a `valueOf` function.
497+
/// Checks if the value is an object and contains a `toString` function.
514498
fn get_to_string<'a>(value: &Value<'a>) -> Option<Function<'a>> {
515-
if let Some(o) = value.as_object() {
516-
let value_of = o.get("toString").ok();
517-
value_of.clone()
499+
get_function(value, PredefinedAtom::ToString)
500+
}
501+
502+
fn get_function<'a>(value: &Value<'a>, atom: PredefinedAtom) -> Option<Function<'a>> {
503+
let f = unsafe { JS_GetProperty(value.ctx().as_raw().as_ptr(), value.as_raw(), atom as u32) };
504+
let f = unsafe { Value::from_raw(value.ctx().clone(), f) };
505+
if f.is_function()
506+
&& let Some(f) = f.into_function()
507+
{
508+
Some(f)
518509
} else {
519510
None
520511
}
@@ -553,15 +544,18 @@ fn is_array_or_proxy_of_array(val: &Value) -> bool {
553544
if val.is_array() {
554545
return true;
555546
}
556-
let ctx = val.ctx().as_raw().as_ptr();
557-
let mut val = val.as_raw();
547+
let ctx = val.ctx().clone();
548+
let mut val = val.clone();
558549
loop {
559-
let is_proxy = unsafe { JS_IsProxy(val) };
550+
let is_proxy = unsafe { JS_IsProxy(val.as_raw()) };
560551
if !is_proxy {
561552
return false;
562553
}
563-
val = unsafe { JS_GetProxyTarget(ctx, val) };
564-
if unsafe { JS_IsArray(val) } {
554+
val = unsafe {
555+
let target = JS_GetProxyTarget(ctx.as_raw().as_ptr(), val.as_raw());
556+
Value::from_raw(ctx.clone(), target)
557+
};
558+
if unsafe { JS_IsArray(val.as_raw()) } {
565559
return true;
566560
}
567561
}
@@ -652,8 +646,12 @@ mod tests {
652646
where
653647
T: DeserializeOwned,
654648
{
649+
let ctx = v.ctx().clone();
655650
let mut deserializer = ValueDeserializer::from(v);
656-
T::deserialize(&mut deserializer).unwrap()
651+
match T::deserialize(&mut deserializer) {
652+
Ok(val) => val,
653+
Err(e) => panic!("{}", e.catch(&ctx)),
654+
}
657655
}
658656

659657
#[test]
@@ -806,6 +804,23 @@ mod tests {
806804
});
807805
}
808806

807+
#[test]
808+
fn test_array_proxy() {
809+
let rt = Runtime::default();
810+
rt.context().with(|cx| {
811+
cx.eval::<Value<'_>, _>(
812+
r#"
813+
var arr = [1, 2, 3];
814+
var a = new Proxy(arr, {});
815+
"#,
816+
)
817+
.unwrap();
818+
let v = cx.globals().get("a").unwrap();
819+
let val = deserialize_value::<Vec<u8>>(v);
820+
assert_eq!(vec![1, 2, 3], val);
821+
});
822+
}
823+
809824
#[test]
810825
fn test_non_json_object_values_are_dropped() {
811826
let rt = Runtime::default();
@@ -870,4 +885,33 @@ mod tests {
870885
assert_eq!(left, right);
871886
});
872887
}
888+
889+
#[test]
890+
fn test_short_bigint() {
891+
let rt = Runtime::default();
892+
rt.context().with(|cx| {
893+
cx.eval::<Value<'_>, _>("var a = BigInt(1);").unwrap();
894+
let v = cx.globals().get("a").unwrap();
895+
let val = deserialize_value::<String>(v);
896+
assert_eq!(val, "1");
897+
});
898+
}
899+
900+
#[test]
901+
fn test_bigint() {
902+
let rt = Runtime::default();
903+
rt.context().with(|cx| {
904+
cx.eval::<Value<'_>, _>(
905+
r#"
906+
const left = 12345678901234567890n;
907+
const right = 98765432109876543210n;
908+
var a = left * right;
909+
"#,
910+
)
911+
.unwrap();
912+
let v = cx.globals().get("a").unwrap();
913+
let val = deserialize_value::<String>(v);
914+
assert_eq!(val, "1219326311370217952237463801111263526900");
915+
});
916+
}
873917
}

0 commit comments

Comments
 (0)