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