rquickjs_serde/
de.rs

1use rquickjs::{
2    Exception, Filter, Function, Null, Object, String as JSString, Value,
3    atom::PredefinedAtom,
4    function::This,
5    object::ObjectIter,
6    qjs::{
7        JS_GetClassID, JS_GetProperty, JS_GetPropertyUint32, JS_GetProxyTarget, JS_IsArray,
8        JS_IsProxy, JS_TAG_EXCEPTION, JS_VALUE_GET_NORM_TAG,
9    },
10};
11use serde::{
12    de::{self, IntoDeserializer, Unexpected},
13    forward_to_deserialize_any,
14};
15
16use crate::err::{Error, Result};
17use crate::utils::{as_key, to_string_lossy};
18use crate::{MAX_SAFE_INTEGER, MIN_SAFE_INTEGER};
19
20// Class IDs, for internal, deserialization purposes only.
21// FIXME: This can change since the ABI is not stable.
22// See https://github.com/quickjs-ng/quickjs/issues/758
23enum ClassId {
24    Number = 4,
25    String = 5,
26    Bool = 6,
27    BigInt = 34,
28}
29
30/// `Deserializer` is a deserializer for [Value] values, implementing the `serde::Deserializer` trait.
31///
32/// This struct is responsible for converting [Value], into Rust types using the Serde deserialization framework.
33///
34/// # Example
35///
36/// ```
37/// # use rquickjs::{Runtime, Context, Value};
38/// # use rquickjs_serde::Deserializer;
39/// # use serde::Deserializer as _;
40/// #
41/// let rt = Runtime::new().unwrap();
42/// let ctx = Context::full(&rt).unwrap();
43/// ctx.with(|ctx| {
44///     let value = ctx.eval::<Value<'_>, _>("42").unwrap();
45///     let mut deserializer = Deserializer::from(value);
46///     let number: i32 = serde::Deserialize::deserialize(&mut deserializer).unwrap();
47///     assert_eq!(number, 42);
48/// });
49/// ```
50pub struct Deserializer<'js> {
51    pub value: Value<'js>,
52    map_key: bool,
53    current_kv: Option<(Value<'js>, Value<'js>)>,
54    /// Stack to track circular dependencies.
55    stack: Vec<Value<'js>>,
56}
57
58impl<'de> From<Value<'de>> for Deserializer<'de> {
59    fn from(value: Value<'de>) -> Self {
60        Self {
61            value,
62            map_key: false,
63            current_kv: None,
64            // We are probaby over allocating here. But it's probably fine to
65            // over allocate to avoid paying the cost of subsequent allocations.
66            stack: Vec::with_capacity(100),
67        }
68    }
69}
70
71impl<'js> Deserializer<'js> {
72    fn deserialize_number<'de, V>(&mut self, visitor: V) -> Result<V::Value>
73    where
74        V: de::Visitor<'de>,
75    {
76        if let Some(i) = self.value.as_int() {
77            return visitor.visit_i32(i);
78        }
79
80        if let Some(f64_representation) = self.value.as_float() {
81            let is_positive = f64_representation.is_sign_positive();
82            let safe_integer_range = (MIN_SAFE_INTEGER as f64)..=(MAX_SAFE_INTEGER as f64);
83            let whole = f64_representation.fract() == 0.0;
84
85            if whole && is_positive && f64_representation <= u32::MAX as f64 {
86                return visitor.visit_u32(f64_representation as u32);
87            }
88
89            if whole && safe_integer_range.contains(&f64_representation) {
90                let x = f64_representation as i64;
91                return visitor.visit_i64(x);
92            }
93
94            return visitor.visit_f64(f64_representation);
95        }
96
97        Err(Error::new(Exception::throw_type(
98            self.value.ctx(),
99            "Unsupported number type",
100        )))
101    }
102
103    /// Pops the last visited value present in the stack.
104    fn pop_visited(&mut self) -> Result<Value<'js>> {
105        let v = self
106            .stack
107            .pop()
108            .ok_or_else(|| Error::new("No entries found in the deserializer stack"))?;
109        Ok(v)
110    }
111
112    /// When stringifying, circular dependencies are not allowed. This function
113    /// checks the current value stack to ensure that if the same value (tag and
114    /// bits) is found again a proper error is raised.
115    fn check_cycles(&self) -> Result<()> {
116        for val in self.stack.iter().rev() {
117            if self.value.eq(val) {
118                return Err(Error::new(Exception::throw_type(
119                    val.ctx(),
120                    "circular dependency",
121                )));
122            }
123        }
124        Ok(())
125    }
126}
127
128impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
129    type Error = Error;
130
131    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
132    where
133        V: de::Visitor<'de>,
134    {
135        if self.value.is_number() {
136            return self.deserialize_number(visitor);
137        }
138
139        if get_class_id(&self.value) == ClassId::Number as u32 {
140            let value_of = get_valueof(&self.value);
141            if let Some(f) = value_of {
142                let v = f.call((This(self.value.clone()),)).map_err(Error::new)?;
143                self.value = v;
144                return self.deserialize_number(visitor);
145            }
146        }
147
148        if let Some(b) = self.value.as_bool() {
149            return visitor.visit_bool(b);
150        }
151
152        if get_class_id(&self.value) == ClassId::Bool as u32 {
153            let value_of = get_valueof(&self.value);
154            if let Some(f) = value_of {
155                let v = f.call((This(self.value.clone()),)).map_err(Error::new)?;
156                return visitor.visit_bool(v);
157            }
158        }
159
160        if self.value.is_null() || self.value.is_undefined() {
161            return visitor.visit_unit();
162        }
163
164        if get_class_id(&self.value) == ClassId::String as u32 {
165            let value_of = get_to_string(&self.value);
166            if let Some(f) = value_of {
167                let v = f.call(((This(self.value.clone())),)).map_err(Error::new)?;
168                self.value = v;
169            }
170        }
171
172        if self.value.is_string() {
173            if self.map_key {
174                self.map_key = false;
175                let key = as_key(&self.value)?;
176                return visitor.visit_str(&key);
177            } else {
178                let val = self
179                    .value
180                    .as_string()
181                    .map(|s| {
182                        s.to_string()
183                            .unwrap_or_else(|e| to_string_lossy(self.value.ctx(), s, e))
184                    })
185                    .unwrap();
186                return visitor.visit_str(&val);
187            }
188        }
189
190        if is_array_or_proxy_of_array(&self.value)
191            && let Some(seq) = self.value.as_object()
192        {
193            let seq_access = SeqAccess::new(self, seq.clone())?;
194            return visitor.visit_seq(seq_access);
195        }
196
197        if self.value.is_object() {
198            ensure_supported(&self.value)?;
199
200            if let Some(f) = get_to_json(&self.value) {
201                let v: Value = f.call((This(self.value.clone()),)).map_err(Error::new)?;
202
203                if v.is_undefined() {
204                    self.value = Value::new_undefined(v.ctx().clone());
205                } else {
206                    self.value = v;
207                }
208                return self.deserialize_any(visitor);
209            }
210
211            let map_access = MapAccess::new(self, self.value.clone().into_object().unwrap())?;
212            let result = visitor.visit_map(map_access);
213            return result;
214        }
215
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            }
228        }
229
230        Err(Error::new(Exception::throw_type(
231            self.value.ctx(),
232            "Unsupported type",
233        )))
234    }
235
236    fn is_human_readable(&self) -> bool {
237        false
238    }
239
240    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
241    where
242        V: de::Visitor<'de>,
243    {
244        if self.value.is_null() || self.value.is_undefined() {
245            visitor.visit_none()
246        } else {
247            visitor.visit_some(self)
248        }
249    }
250
251    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
252    where
253        V: de::Visitor<'de>,
254    {
255        visitor.visit_newtype_struct(self)
256    }
257
258    fn deserialize_enum<V>(
259        self,
260        _name: &'static str,
261        _variants: &'static [&'static str],
262        visitor: V,
263    ) -> Result<V::Value>
264    where
265        V: de::Visitor<'de>,
266    {
267        if get_class_id(&self.value) == ClassId::String as u32
268            && let Some(f) = get_to_string(&self.value)
269        {
270            let v = f.call((This(self.value.clone()),)).map_err(Error::new)?;
271            self.value = v;
272        }
273
274        // Now require a primitive string.
275        let s = if let Some(s) = self.value.as_string() {
276            s.to_string()
277                .unwrap_or_else(|e| to_string_lossy(self.value.ctx(), s, e))
278        } else {
279            return Err(Error::new("expected a string for enum unit variant"));
280        };
281
282        // Hand Serde an EnumAccess that only supports unit variants.
283        visitor.visit_enum(UnitEnumAccess { variant: s })
284    }
285
286    forward_to_deserialize_any! {
287        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
288        bytes byte_buf unit unit_struct seq tuple
289        tuple_struct map struct identifier ignored_any
290    }
291}
292
293/// A helper struct for deserializing objects.
294struct MapAccess<'a, 'de: 'a> {
295    /// The deserializer.
296    de: &'a mut Deserializer<'de>,
297    /// The object properties.
298    properties: ObjectIter<'de, Value<'de>, Value<'de>>,
299    /// The current object.
300    obj: Object<'de>,
301}
302
303impl<'a, 'de> MapAccess<'a, 'de> {
304    fn new(de: &'a mut Deserializer<'de>, obj: Object<'de>) -> Result<Self> {
305        let filter = Filter::new().enum_only().string();
306        let properties: ObjectIter<'_, _, Value<'_>> =
307            obj.own_props::<Value<'_>, Value<'_>>(filter);
308
309        let val = obj.clone().into_value();
310        de.stack.push(val.clone());
311
312        Ok(Self {
313            de,
314            properties,
315            obj,
316        })
317    }
318
319    /// Pops the top level value representing this sequence.
320    /// Errors if a different value is popped.
321    fn pop(&mut self) -> Result<()> {
322        let v = self.de.pop_visited()?;
323        if v != self.obj.clone().into_value() {
324            return Err(Error::new(
325                "Popped a mismatched value. Expected the top level sequence value",
326            ));
327        }
328
329        Ok(())
330    }
331}
332
333impl<'de> de::MapAccess<'de> for MapAccess<'_, 'de> {
334    type Error = Error;
335
336    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
337    where
338        K: de::DeserializeSeed<'de>,
339    {
340        loop {
341            if let Some(kv) = self.properties.next() {
342                let (k, v) = kv.map_err(Error::new)?;
343
344                let to_json = get_to_json(&v);
345                let v = if let Some(f) = to_json {
346                    f.call((This(v.clone()), k.clone())).map_err(Error::new)?
347                } else {
348                    v
349                };
350
351                // Entries with non-JSONable values are skipped to respect
352                // JSON.stringify's spec
353                if !ensure_supported(&v)? || k.is_symbol() {
354                    continue;
355                }
356
357                let class_id = get_class_id(&v);
358
359                if class_id == ClassId::Bool as u32 || class_id == ClassId::Number as u32 {
360                    let value_of = get_valueof(&v);
361                    if let Some(f) = value_of {
362                        let v = f.call((This(v.clone()),)).map_err(Error::new)?;
363                        self.de.current_kv = Some((k.clone(), v));
364                    }
365                } else if class_id == ClassId::String as u32 {
366                    let to_string = get_to_string(&v);
367                    if let Some(f) = to_string {
368                        let v = f.call((This(v.clone()),)).map_err(Error::new)?;
369                        self.de.current_kv = Some((k.clone(), v));
370                    }
371                } else {
372                    self.de.current_kv = Some((k.clone(), v));
373                }
374                self.de.value = k;
375                self.de.map_key = true;
376
377                return seed.deserialize(&mut *self.de).map(Some);
378            } else {
379                self.pop()?;
380                return Ok(None);
381            }
382        }
383    }
384
385    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
386    where
387        V: de::DeserializeSeed<'de>,
388    {
389        self.de.value = self.de.current_kv.clone().unwrap().1;
390        self.de.check_cycles()?;
391        seed.deserialize(&mut *self.de)
392    }
393}
394
395/// A helper struct for deserializing sequences.
396struct SeqAccess<'a, 'de: 'a> {
397    /// The deserializer.
398    de: &'a mut Deserializer<'de>,
399    /// The sequence, represented as a JavaScript object.
400    // Using Object instead of Array because `SeqAccess` needs to support
401    // proxies of arrays and a proxy Value cannot be converted into Array.
402    seq: Object<'de>,
403    /// The sequence length.
404    length: usize,
405    /// The current index.
406    index: usize,
407}
408
409impl<'a, 'de: 'a> SeqAccess<'a, 'de> {
410    /// Creates a new `SeqAccess` ensuring that the top-level value is added
411    /// to the `Deserializer` visitor stack.
412    fn new(de: &'a mut Deserializer<'de>, seq: Object<'de>) -> Result<Self> {
413        de.stack.push(seq.clone().into_value());
414
415        // Retrieve the `length` property from the object itself rather than
416        // using the bindings `Array::len` given that according to the spec
417        // it's fine to return any value, not just a number from the
418        // `length` property.
419        let value: Value = seq.get(PredefinedAtom::Length).map_err(Error::new)?;
420        let length: usize = if let Some(n) = value.as_number() {
421            n as usize
422        } else {
423            let value_of: Function = value
424                .as_object()
425                .expect("length to be an object")
426                .get(PredefinedAtom::ValueOf)
427                .map_err(Error::new)?;
428            value_of.call(()).map_err(Error::new)?
429        };
430
431        Ok(Self {
432            de,
433            seq,
434            length,
435            index: 0,
436        })
437    }
438
439    /// Pops the top level value representing this sequence.
440    /// Errors if a different value is popped.
441    fn pop(&mut self) -> Result<()> {
442        let v = self.de.pop_visited()?;
443        if v != self.seq.clone().into_value() {
444            return Err(Error::new(
445                "Popped a mismatched value. Expected the top level sequence value",
446            ));
447        }
448
449        Ok(())
450    }
451}
452
453impl<'de> de::SeqAccess<'de> for SeqAccess<'_, 'de> {
454    type Error = Error;
455
456    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
457    where
458        T: de::DeserializeSeed<'de>,
459    {
460        if self.index < self.length {
461            let el = get_index(&self.seq, self.index).map_err(Error::new)?;
462            let to_json = get_to_json(&el);
463
464            if let Some(f) = to_json {
465                let index_value = JSString::from_str(el.ctx().clone(), &self.index.to_string());
466                self.de.value = f
467                    .call((This(el.clone()), index_value))
468                    .map_err(Error::new)?;
469            } else if ensure_supported(&el)? {
470                self.de.value = el
471            } else {
472                self.de.value = Null.into_value(self.seq.ctx().clone())
473            }
474            self.index += 1;
475            // Check cycles right before starting the deserialization for the
476            // sequence elements.
477            self.de.check_cycles()?;
478            seed.deserialize(&mut *self.de).map(Some)
479        } else {
480            // Pop the sequence when there are no more elements.
481            self.pop()?;
482            Ok(None)
483        }
484    }
485}
486
487/// Checks if the value is an object and contains a single `toJSON` function.
488pub(crate) fn get_to_json<'a>(value: &Value<'a>) -> Option<Function<'a>> {
489    get_function(value, PredefinedAtom::ToJSON)
490}
491
492/// Checks if the value is an object and contains a `valueOf` function.
493fn get_valueof<'a>(value: &Value<'a>) -> Option<Function<'a>> {
494    get_function(value, PredefinedAtom::ValueOf)
495}
496
497/// Checks if the value is an object and contains a `toString` function.
498fn get_to_string<'a>(value: &Value<'a>) -> Option<Function<'a>> {
499    get_function(value, PredefinedAtom::ToString)
500}
501
502fn 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)
509    } else {
510        None
511    }
512}
513
514/// Gets the underlying class id of the value.
515fn get_class_id(v: &Value) -> u32 {
516    unsafe { JS_GetClassID(v.as_raw()) }
517}
518
519/// Ensures that the value can be stringified.
520fn ensure_supported(value: &Value<'_>) -> Result<bool> {
521    let class_id = get_class_id(value);
522    if class_id == (ClassId::Bool as u32) || class_id == (ClassId::Number as u32) {
523        return Ok(true);
524    }
525
526    if class_id == ClassId::BigInt as u32 {
527        return Err(Error::new(Exception::throw_type(
528            value.ctx(),
529            "BigInt not supported",
530        )));
531    }
532
533    Ok(!matches!(
534        value.type_of(),
535        rquickjs::Type::Undefined
536            | rquickjs::Type::Symbol
537            | rquickjs::Type::Function
538            | rquickjs::Type::Uninitialized
539            | rquickjs::Type::Constructor
540    ))
541}
542
543fn is_array_or_proxy_of_array(val: &Value) -> bool {
544    if val.is_array() {
545        return true;
546    }
547    let ctx = val.ctx().clone();
548    let mut val = val.clone();
549    loop {
550        let is_proxy = unsafe { JS_IsProxy(val.as_raw()) };
551        if !is_proxy {
552            return false;
553        }
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()) } {
559            return true;
560        }
561    }
562}
563
564fn get_index<'a>(obj: &Object<'a>, idx: usize) -> rquickjs::Result<Value<'a>> {
565    unsafe {
566        let ctx = obj.ctx();
567        let val = JS_GetPropertyUint32(ctx.as_raw().as_ptr(), obj.as_raw(), idx as _);
568        if JS_VALUE_GET_NORM_TAG(val) == JS_TAG_EXCEPTION {
569            return Err(rquickjs::Error::Exception);
570        }
571        Ok(Value::from_raw(ctx.clone(), val))
572    }
573}
574
575/// A helper struct for deserializing enums containing unit variants.
576struct UnitEnumAccess {
577    variant: String,
578}
579
580impl<'de> de::EnumAccess<'de> for UnitEnumAccess {
581    type Error = Error;
582    type Variant = UnitOnlyVariant;
583
584    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
585    where
586        V: de::DeserializeSeed<'de>,
587    {
588        let v = seed.deserialize(self.variant.into_deserializer())?;
589        Ok((v, UnitOnlyVariant))
590    }
591}
592
593struct UnitOnlyVariant;
594
595impl<'de> de::VariantAccess<'de> for UnitOnlyVariant {
596    type Error = Error;
597
598    fn unit_variant(self) -> Result<()> {
599        Ok(())
600    }
601
602    fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value>
603    where
604        T: de::DeserializeSeed<'de>,
605    {
606        Err(de::Error::invalid_type(
607            Unexpected::NewtypeVariant,
608            &"unit variant",
609        ))
610    }
611
612    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value>
613    where
614        V: de::Visitor<'de>,
615    {
616        Err(de::Error::invalid_type(
617            Unexpected::TupleVariant,
618            &"unit variant",
619        ))
620    }
621
622    fn struct_variant<V>(self, _fields: &'static [&'static str], _visitor: V) -> Result<V::Value>
623    where
624        V: de::Visitor<'de>,
625    {
626        Err(de::Error::invalid_type(
627            Unexpected::StructVariant,
628            &"unit variant",
629        ))
630    }
631}
632
633#[cfg(test)]
634mod tests {
635    use std::collections::BTreeMap;
636
637    use rquickjs::Value;
638    use serde::de::DeserializeOwned;
639    use serde::{Deserialize, Serialize};
640
641    use super::Deserializer as ValueDeserializer;
642    use crate::test::Runtime;
643    use crate::{MAX_SAFE_INTEGER, from_value, to_value};
644
645    fn deserialize_value<T>(v: Value<'_>) -> T
646    where
647        T: DeserializeOwned,
648    {
649        let ctx = v.ctx().clone();
650        let mut deserializer = ValueDeserializer::from(v);
651        match T::deserialize(&mut deserializer) {
652            Ok(val) => val,
653            Err(e) => panic!("{}", e.catch(&ctx)),
654        }
655    }
656
657    #[test]
658    fn test_null() {
659        let rt = Runtime::default();
660        rt.context().with(|cx| {
661            let val = Value::new_null(cx);
662            deserialize_value::<()>(val);
663        });
664    }
665
666    #[test]
667    fn test_undefined() {
668        let rt = Runtime::default();
669        rt.context().with(|cx| {
670            let val = Value::new_undefined(cx);
671            deserialize_value::<()>(val);
672        });
673    }
674
675    #[test]
676    fn test_nan() {
677        let rt = Runtime::default();
678        rt.context().with(|cx| {
679            let val = Value::new_float(cx, f64::NAN);
680            let actual = deserialize_value::<f64>(val);
681            assert!(actual.is_nan());
682        });
683    }
684
685    #[test]
686    fn test_infinity() {
687        let rt = Runtime::default();
688
689        rt.context().with(|cx| {
690            let val = Value::new_float(cx, f64::INFINITY);
691            let actual = deserialize_value::<f64>(val);
692            assert!(actual.is_infinite() && actual.is_sign_positive());
693        });
694    }
695
696    #[test]
697    fn test_negative_infinity() {
698        let rt = Runtime::default();
699        rt.context().with(|cx| {
700            let val = Value::new_float(cx, f64::NEG_INFINITY);
701            let actual = deserialize_value::<f64>(val);
702            assert!(actual.is_infinite() && actual.is_sign_negative());
703        })
704    }
705
706    #[test]
707    fn test_map_always_converts_keys_to_string() {
708        let rt = Runtime::default();
709        // Sanity check to make sure the quickjs VM always store object
710        // object keys as a string an not a numerical value.
711        rt.context().with(|c| {
712            c.eval::<Value<'_>, _>("var a = {1337: 42};").unwrap();
713            let val = c.globals().get("a").unwrap();
714            let actual = deserialize_value::<BTreeMap<String, i32>>(val);
715
716            assert_eq!(42, *actual.get("1337").unwrap())
717        });
718    }
719
720    #[test]
721    fn test_u64_bounds() {
722        let rt = Runtime::default();
723        rt.context().with(|c| {
724            let max = u64::MAX;
725            let val = Value::new_number(c.clone(), max as f64);
726            let actual = deserialize_value::<f64>(val);
727            assert_eq!(max as f64, actual);
728
729            let min = u64::MIN;
730            let val = Value::new_number(c.clone(), min as f64);
731            let actual = deserialize_value::<f64>(val);
732            assert_eq!(min as f64, actual);
733        });
734    }
735
736    #[test]
737    fn test_i64_bounds() {
738        let rt = Runtime::default();
739
740        rt.context().with(|c| {
741            let max = i64::MAX;
742            let val = Value::new_number(c.clone(), max as _);
743            let actual = deserialize_value::<f64>(val);
744            assert_eq!(max as f64, actual);
745
746            let min = i64::MIN;
747            let val = Value::new_number(c.clone(), min as _);
748            let actual = deserialize_value::<f64>(val);
749            assert_eq!(min as f64, actual);
750        });
751    }
752
753    #[test]
754    fn test_float_to_integer_conversion() {
755        let rt = Runtime::default();
756
757        rt.context().with(|c| {
758            let expected = MAX_SAFE_INTEGER - 1;
759            let val = Value::new_float(c.clone(), expected as _);
760            let actual = deserialize_value::<i64>(val);
761            assert_eq!(expected, actual);
762
763            let expected = MAX_SAFE_INTEGER + 1;
764            let val = Value::new_float(c.clone(), expected as _);
765            let actual = deserialize_value::<f64>(val);
766            assert_eq!(expected as f64, actual);
767        });
768    }
769
770    #[test]
771    fn test_u32_upper_bound() {
772        let rt = Runtime::default();
773
774        rt.context().with(|c| {
775            let expected = u32::MAX;
776            let val = Value::new_number(c, expected as _);
777            let actual = deserialize_value::<u32>(val);
778            assert_eq!(expected, actual);
779        });
780    }
781
782    #[test]
783    fn test_u32_lower_bound() {
784        let rt = Runtime::default();
785
786        rt.context().with(|cx| {
787            let expected = i32::MAX as u32 + 1;
788            let val = Value::new_number(cx, expected as _);
789            let actual = deserialize_value::<u32>(val);
790            assert_eq!(expected, actual);
791        });
792    }
793
794    #[test]
795    fn test_array() {
796        let rt = Runtime::default();
797        rt.context().with(|cx| {
798            cx.eval::<Value<'_>, _>("var a = [1, 2, 3];").unwrap();
799            let v = cx.globals().get("a").unwrap();
800
801            let val = deserialize_value::<Vec<u8>>(v);
802
803            assert_eq!(vec![1, 2, 3], val);
804        });
805    }
806
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
824    #[test]
825    fn test_non_json_object_values_are_dropped() {
826        let rt = Runtime::default();
827        rt.context().with(|cx| {
828            cx.eval::<Value<'_>, _>(
829                r#"
830                var unitialized;
831                var a = {
832                    a: undefined,
833                    b: function() {},
834                    c: Symbol(),
835                    d: () => {},
836                    e: unitialized,
837                };"#,
838            )
839            .unwrap();
840            let v = cx.globals().get("a").unwrap();
841
842            let val = deserialize_value::<BTreeMap<String, ()>>(v);
843            assert_eq!(BTreeMap::new(), val);
844        });
845    }
846
847    #[test]
848    fn test_non_json_array_values_are_null() {
849        let rt = Runtime::default();
850        rt.context().with(|cx| {
851            cx.eval::<Value<'_>, _>(
852                r#"
853                var unitialized;
854                var a = [
855                    undefined,
856                    function() {},
857                    Symbol(),
858                    () => {},
859                    unitialized,
860                ];"#,
861            )
862            .unwrap();
863            let v = cx.globals().get("a").unwrap();
864
865            let val = deserialize_value::<Vec<Option<()>>>(v);
866            assert_eq!(vec![None; 5], val);
867        });
868    }
869
870    #[test]
871    fn test_enum() {
872        let rt = Runtime::default();
873
874        #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
875        enum Test {
876            One,
877            Two,
878            Three,
879        }
880
881        rt.context().with(|cx| {
882            let left = Test::Two;
883            let value = to_value(cx, left).unwrap();
884            let right: Test = from_value(value).unwrap();
885            assert_eq!(left, right);
886        });
887    }
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    }
917}