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