Skip to main content

rquickjs_serde/
de.rs

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