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, Unexpected},
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        // Now require a primitive string.
296        let s = if let Some(s) = self.value.as_string() {
297            s.to_string()
298                .unwrap_or_else(|e| to_string_lossy(self.value.ctx(), s, e))
299        } else {
300            return Err(Error::new("expected a string for enum unit variant"));
301        };
302
303        // Hand Serde an EnumAccess that only supports unit variants.
304        visitor.visit_enum(UnitEnumAccess { variant: s })
305    }
306
307    forward_to_deserialize_any! {
308        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
309        bytes byte_buf unit unit_struct seq tuple
310        tuple_struct map struct identifier ignored_any
311    }
312}
313
314/// A helper struct for deserializing objects.
315struct MapAccess<'a, 'de: 'a> {
316    /// The deserializer.
317    de: &'a mut Deserializer<'de>,
318    /// The object properties.
319    properties: ObjectIter<'de, Value<'de>, Value<'de>>,
320    /// The current object.
321    obj: Object<'de>,
322}
323
324impl<'a, 'de> MapAccess<'a, 'de> {
325    fn new(de: &'a mut Deserializer<'de>, obj: Object<'de>) -> Result<Self> {
326        let filter = Filter::new().enum_only().string();
327        let properties: ObjectIter<'_, _, Value<'_>> =
328            obj.own_props::<Value<'_>, Value<'_>>(filter);
329
330        let val = obj.clone().into_value();
331        de.stack.push(val.clone());
332
333        Ok(Self {
334            de,
335            properties,
336            obj,
337        })
338    }
339
340    /// Pops the top level value representing this sequence.
341    /// Errors if a different value is popped.
342    fn pop(&mut self) -> Result<()> {
343        let v = self.de.pop_visited()?;
344        if v != self.obj.clone().into_value() {
345            return Err(Error::new(
346                "Popped a mismatched value. Expected the top level sequence value",
347            ));
348        }
349
350        Ok(())
351    }
352}
353
354impl<'de> de::MapAccess<'de> for MapAccess<'_, 'de> {
355    type Error = Error;
356
357    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
358    where
359        K: de::DeserializeSeed<'de>,
360    {
361        loop {
362            if let Some(kv) = self.properties.next() {
363                let (k, v) = kv.map_err(Error::new)?;
364
365                let to_json = get_to_json(&v);
366                let v = if let Some(f) = to_json {
367                    f.call((This(v.clone()), k.clone())).map_err(Error::new)?
368                } else {
369                    v
370                };
371
372                // Entries with non-JSONable values are skipped to respect
373                // JSON.stringify's spec
374                if !ensure_supported(&v)? || k.is_symbol() {
375                    continue;
376                }
377
378                let class_id = get_class_id(&v);
379
380                if class_id == ClassId::Bool as u32 || class_id == ClassId::Number as u32 {
381                    let value_of = get_valueof(&v);
382                    if let Some(f) = value_of {
383                        let v = f.call((This(v.clone()),)).map_err(Error::new)?;
384                        self.de.current_kv = Some((k.clone(), v));
385                    }
386                } else if class_id == ClassId::String as u32 {
387                    let to_string = get_to_string(&v);
388                    if let Some(f) = to_string {
389                        let v = f.call((This(v.clone()),)).map_err(Error::new)?;
390                        self.de.current_kv = Some((k.clone(), v));
391                    }
392                } else {
393                    self.de.current_kv = Some((k.clone(), v));
394                }
395                self.de.value = k;
396                self.de.map_key = true;
397
398                return seed.deserialize(&mut *self.de).map(Some);
399            } else {
400                self.pop()?;
401                return Ok(None);
402            }
403        }
404    }
405
406    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
407    where
408        V: de::DeserializeSeed<'de>,
409    {
410        self.de.value = self.de.current_kv.clone().unwrap().1;
411        self.de.check_cycles()?;
412        seed.deserialize(&mut *self.de)
413    }
414}
415
416/// A helper struct for deserializing sequences.
417struct SeqAccess<'a, 'de: 'a> {
418    /// The deserializer.
419    de: &'a mut Deserializer<'de>,
420    /// The sequence, represented as a JavaScript object.
421    // Using Object instead of Array because `SeqAccess` needs to support
422    // proxies of arrays and a proxy Value cannot be converted into Array.
423    seq: Object<'de>,
424    /// The sequence length.
425    length: usize,
426    /// The current index.
427    index: usize,
428}
429
430impl<'a, 'de: 'a> SeqAccess<'a, 'de> {
431    /// Creates a new `SeqAccess` ensuring that the top-level value is added
432    /// to the `Deserializer` visitor stack.
433    fn new(de: &'a mut Deserializer<'de>, seq: Object<'de>) -> Result<Self> {
434        de.stack.push(seq.clone().into_value());
435
436        // Retrieve the `length` property from the object itself rather than
437        // using the bindings `Array::len` given that according to the spec
438        // it's fine to return any value, not just a number from the
439        // `length` property.
440        let value: Value = seq.get(PredefinedAtom::Length).map_err(Error::new)?;
441        let length: usize = if let Some(n) = value.as_number() {
442            n as usize
443        } else {
444            let value_of: Function = value
445                .as_object()
446                .expect("length to be an object")
447                .get(PredefinedAtom::ValueOf)
448                .map_err(Error::new)?;
449            value_of.call(()).map_err(Error::new)?
450        };
451
452        Ok(Self {
453            de,
454            seq,
455            length,
456            index: 0,
457        })
458    }
459
460    /// Pops the top level value representing this sequence.
461    /// Errors if a different value is popped.
462    fn pop(&mut self) -> Result<()> {
463        let v = self.de.pop_visited()?;
464        if v != self.seq.clone().into_value() {
465            return Err(Error::new(
466                "Popped a mismatched value. Expected the top level sequence value",
467            ));
468        }
469
470        Ok(())
471    }
472}
473
474impl<'de> de::SeqAccess<'de> for SeqAccess<'_, 'de> {
475    type Error = Error;
476
477    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
478    where
479        T: de::DeserializeSeed<'de>,
480    {
481        if self.index < self.length {
482            let el = get_index(&self.seq, self.index).map_err(Error::new)?;
483            let to_json = get_to_json(&el);
484
485            if let Some(f) = to_json {
486                let index_value = JSString::from_str(el.ctx().clone(), &self.index.to_string());
487                self.de.value = f
488                    .call((This(el.clone()), index_value))
489                    .map_err(Error::new)?;
490            } else if ensure_supported(&el)? {
491                self.de.value = el
492            } else {
493                self.de.value = Null.into_value(self.seq.ctx().clone())
494            }
495            self.index += 1;
496            // Check cycles right before starting the deserialization for the
497            // sequence elements.
498            self.de.check_cycles()?;
499            seed.deserialize(&mut *self.de).map(Some)
500        } else {
501            // Pop the sequence when there are no more elements.
502            self.pop()?;
503            Ok(None)
504        }
505    }
506}
507
508/// Checks if the value is an object and contains a single `toJSON` function.
509pub(crate) fn get_to_json<'a>(value: &Value<'a>) -> Option<Function<'a>> {
510    get_function(value, PredefinedAtom::ToJSON)
511}
512
513/// Checks if the value is an object and contains a `valueOf` function.
514fn get_valueof<'a>(value: &Value<'a>) -> Option<Function<'a>> {
515    get_function(value, PredefinedAtom::ValueOf)
516}
517
518/// Checks if the value is an object and contains a `toString` function.
519fn get_to_string<'a>(value: &Value<'a>) -> Option<Function<'a>> {
520    get_function(value, PredefinedAtom::ToString)
521}
522
523fn get_function<'a>(value: &Value<'a>, atom: PredefinedAtom) -> Option<Function<'a>> {
524    let f = unsafe { JS_GetProperty(value.ctx().as_raw().as_ptr(), value.as_raw(), atom as u32) };
525    let f = unsafe { Value::from_raw(value.ctx().clone(), f) };
526    if f.is_function()
527        && let Some(f) = f.into_function()
528    {
529        Some(f)
530    } else {
531        None
532    }
533}
534
535/// Gets the underlying class id of the value.
536fn get_class_id(v: &Value) -> u32 {
537    unsafe { JS_GetClassID(v.as_raw()) }
538}
539
540/// Ensures that the value can be stringified.
541fn ensure_supported(value: &Value<'_>) -> Result<bool> {
542    let class_id = get_class_id(value);
543    if class_id == (ClassId::Bool as u32) || class_id == (ClassId::Number as u32) {
544        return Ok(true);
545    }
546
547    if class_id == ClassId::BigInt as u32 {
548        return Err(Error::new(Exception::throw_type(
549            value.ctx(),
550            "BigInt not supported",
551        )));
552    }
553
554    Ok(!matches!(
555        value.type_of(),
556        rquickjs::Type::Undefined
557            | rquickjs::Type::Symbol
558            | rquickjs::Type::Function
559            | rquickjs::Type::Uninitialized
560            | rquickjs::Type::Constructor
561    ))
562}
563
564fn is_array_or_proxy_of_array(val: &Value) -> bool {
565    if val.is_array() {
566        return true;
567    }
568    let mut val = val.clone();
569    loop {
570        let Some(proxy) = val.into_proxy() else {
571            return false;
572        };
573        let Ok(target) = proxy.target() else {
574            return false;
575        };
576        val = target.into_value();
577        if val.is_array() {
578            return true;
579        }
580    }
581}
582
583fn get_index<'a>(obj: &Object<'a>, idx: usize) -> rquickjs::Result<Value<'a>> {
584    unsafe {
585        let ctx = obj.ctx();
586        let val = JS_GetPropertyUint32(ctx.as_raw().as_ptr(), obj.as_raw(), idx as _);
587        if JS_VALUE_GET_NORM_TAG(val) == JS_TAG_EXCEPTION {
588            return Err(rquickjs::Error::Exception);
589        }
590        Ok(Value::from_raw(ctx.clone(), val))
591    }
592}
593
594/// A helper struct for deserializing enums containing unit variants.
595struct UnitEnumAccess {
596    variant: String,
597}
598
599impl<'de> de::EnumAccess<'de> for UnitEnumAccess {
600    type Error = Error;
601    type Variant = UnitOnlyVariant;
602
603    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
604    where
605        V: de::DeserializeSeed<'de>,
606    {
607        let v = seed.deserialize(self.variant.into_deserializer())?;
608        Ok((v, UnitOnlyVariant))
609    }
610}
611
612struct UnitOnlyVariant;
613
614impl<'de> de::VariantAccess<'de> for UnitOnlyVariant {
615    type Error = Error;
616
617    fn unit_variant(self) -> Result<()> {
618        Ok(())
619    }
620
621    fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value>
622    where
623        T: de::DeserializeSeed<'de>,
624    {
625        Err(de::Error::invalid_type(
626            Unexpected::NewtypeVariant,
627            &"unit variant",
628        ))
629    }
630
631    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value>
632    where
633        V: de::Visitor<'de>,
634    {
635        Err(de::Error::invalid_type(
636            Unexpected::TupleVariant,
637            &"unit variant",
638        ))
639    }
640
641    fn struct_variant<V>(self, _fields: &'static [&'static str], _visitor: V) -> Result<V::Value>
642    where
643        V: de::Visitor<'de>,
644    {
645        Err(de::Error::invalid_type(
646            Unexpected::StructVariant,
647            &"unit variant",
648        ))
649    }
650}
651
652#[cfg(test)]
653mod tests {
654    use std::collections::BTreeMap;
655
656    use rquickjs::Value;
657    use serde::de::DeserializeOwned;
658    use serde::{Deserialize, Serialize};
659
660    use super::Deserializer as ValueDeserializer;
661    use crate::test::Runtime;
662    use crate::{MAX_SAFE_INTEGER, from_value, to_value};
663
664    fn deserialize_value<T>(v: Value<'_>) -> T
665    where
666        T: DeserializeOwned,
667    {
668        let ctx = v.ctx().clone();
669        let mut deserializer = ValueDeserializer::from(v);
670        match T::deserialize(&mut deserializer) {
671            Ok(val) => val,
672            Err(e) => panic!("{}", e.catch(&ctx)),
673        }
674    }
675
676    #[test]
677    fn test_null() {
678        let rt = Runtime::default();
679        rt.context().with(|cx| {
680            let val = Value::new_null(cx);
681            deserialize_value::<()>(val);
682        });
683    }
684
685    #[test]
686    fn test_undefined() {
687        let rt = Runtime::default();
688        rt.context().with(|cx| {
689            let val = Value::new_undefined(cx);
690            deserialize_value::<()>(val);
691        });
692    }
693
694    #[test]
695    fn test_nan() {
696        let rt = Runtime::default();
697        rt.context().with(|cx| {
698            let val = Value::new_float(cx, f64::NAN);
699            let actual = deserialize_value::<f64>(val);
700            assert!(actual.is_nan());
701        });
702    }
703
704    #[test]
705    fn test_infinity() {
706        let rt = Runtime::default();
707
708        rt.context().with(|cx| {
709            let val = Value::new_float(cx, f64::INFINITY);
710            let actual = deserialize_value::<f64>(val);
711            assert!(actual.is_infinite() && actual.is_sign_positive());
712        });
713    }
714
715    #[test]
716    fn test_negative_infinity() {
717        let rt = Runtime::default();
718        rt.context().with(|cx| {
719            let val = Value::new_float(cx, f64::NEG_INFINITY);
720            let actual = deserialize_value::<f64>(val);
721            assert!(actual.is_infinite() && actual.is_sign_negative());
722        })
723    }
724
725    #[test]
726    fn test_map_always_converts_keys_to_string() {
727        let rt = Runtime::default();
728        // Sanity check to make sure the quickjs VM always store object
729        // object keys as a string an not a numerical value.
730        rt.context().with(|c| {
731            c.eval::<Value<'_>, _>("var a = {1337: 42};").unwrap();
732            let val = c.globals().get("a").unwrap();
733            let actual = deserialize_value::<BTreeMap<String, i32>>(val);
734
735            assert_eq!(42, *actual.get("1337").unwrap())
736        });
737    }
738
739    #[test]
740    fn test_u64_bounds() {
741        let rt = Runtime::default();
742        rt.context().with(|c| {
743            let max = u64::MAX;
744            let val = Value::new_number(c.clone(), max as f64);
745            let actual = deserialize_value::<f64>(val);
746            assert_eq!(max as f64, actual);
747
748            let min = u64::MIN;
749            let val = Value::new_number(c.clone(), min as f64);
750            let actual = deserialize_value::<f64>(val);
751            assert_eq!(min as f64, actual);
752        });
753    }
754
755    #[test]
756    fn test_i64_bounds() {
757        let rt = Runtime::default();
758
759        rt.context().with(|c| {
760            let max = i64::MAX;
761            let val = Value::new_number(c.clone(), max as _);
762            let actual = deserialize_value::<f64>(val);
763            assert_eq!(max as f64, actual);
764
765            let min = i64::MIN;
766            let val = Value::new_number(c.clone(), min as _);
767            let actual = deserialize_value::<f64>(val);
768            assert_eq!(min as f64, actual);
769        });
770    }
771
772    #[test]
773    fn test_float_to_integer_conversion() {
774        let rt = Runtime::default();
775
776        rt.context().with(|c| {
777            let expected = MAX_SAFE_INTEGER - 1;
778            let val = Value::new_float(c.clone(), expected as _);
779            let actual = deserialize_value::<i64>(val);
780            assert_eq!(expected, actual);
781
782            let expected = MAX_SAFE_INTEGER + 1;
783            let val = Value::new_float(c.clone(), expected as _);
784            let actual = deserialize_value::<f64>(val);
785            assert_eq!(expected as f64, actual);
786        });
787    }
788
789    #[test]
790    fn test_u32_upper_bound() {
791        let rt = Runtime::default();
792
793        rt.context().with(|c| {
794            let expected = u32::MAX;
795            let val = Value::new_number(c, expected as _);
796            let actual = deserialize_value::<u32>(val);
797            assert_eq!(expected, actual);
798        });
799    }
800
801    #[test]
802    fn test_u32_lower_bound() {
803        let rt = Runtime::default();
804
805        rt.context().with(|cx| {
806            let expected = i32::MAX as u32 + 1;
807            let val = Value::new_number(cx, expected as _);
808            let actual = deserialize_value::<u32>(val);
809            assert_eq!(expected, actual);
810        });
811    }
812
813    #[test]
814    fn test_array() {
815        let rt = Runtime::default();
816        rt.context().with(|cx| {
817            cx.eval::<Value<'_>, _>("var a = [1, 2, 3];").unwrap();
818            let v = cx.globals().get("a").unwrap();
819
820            let val = deserialize_value::<Vec<u8>>(v);
821
822            assert_eq!(vec![1, 2, 3], val);
823        });
824    }
825
826    #[test]
827    fn test_array_proxy() {
828        let rt = Runtime::default();
829        rt.context().with(|cx| {
830            cx.eval::<Value<'_>, _>(
831                r#"
832                var arr = [1, 2, 3];
833                var a = new Proxy(arr, {});
834            "#,
835            )
836            .unwrap();
837            let v = cx.globals().get("a").unwrap();
838            let val = deserialize_value::<Vec<u8>>(v);
839            assert_eq!(vec![1, 2, 3], val);
840        });
841    }
842
843    #[test]
844    fn test_non_json_object_values_are_dropped() {
845        let rt = Runtime::default();
846        rt.context().with(|cx| {
847            cx.eval::<Value<'_>, _>(
848                r#"
849                var unitialized;
850                var a = {
851                    a: undefined,
852                    b: function() {},
853                    c: Symbol(),
854                    d: () => {},
855                    e: unitialized,
856                };"#,
857            )
858            .unwrap();
859            let v = cx.globals().get("a").unwrap();
860
861            let val = deserialize_value::<BTreeMap<String, ()>>(v);
862            assert_eq!(BTreeMap::new(), val);
863        });
864    }
865
866    #[test]
867    fn test_non_json_array_values_are_null() {
868        let rt = Runtime::default();
869        rt.context().with(|cx| {
870            cx.eval::<Value<'_>, _>(
871                r#"
872                var unitialized;
873                var a = [
874                    undefined,
875                    function() {},
876                    Symbol(),
877                    () => {},
878                    unitialized,
879                ];"#,
880            )
881            .unwrap();
882            let v = cx.globals().get("a").unwrap();
883
884            let val = deserialize_value::<Vec<Option<()>>>(v);
885            assert_eq!(vec![None; 5], val);
886        });
887    }
888
889    #[test]
890    fn test_enum() {
891        let rt = Runtime::default();
892
893        #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
894        enum Test {
895            One,
896            Two,
897            Three,
898        }
899
900        rt.context().with(|cx| {
901            let left = Test::Two;
902            let value = to_value(cx, left).unwrap();
903            let right: Test = from_value(value).unwrap();
904            assert_eq!(left, right);
905        });
906    }
907
908    #[test]
909    fn test_short_bigint() {
910        let rt = Runtime::default();
911        rt.context().with(|cx| {
912            cx.eval::<Value<'_>, _>("var a = BigInt(1);").unwrap();
913            let v = cx.globals().get("a").unwrap();
914            let val = deserialize_value::<String>(v);
915            assert_eq!(val, "1");
916        });
917    }
918
919    #[test]
920    fn test_bigint() {
921        let rt = Runtime::default();
922        rt.context().with(|cx| {
923            cx.eval::<Value<'_>, _>(
924                r#"
925                const left = 12345678901234567890n;
926                const right = 98765432109876543210n;
927                var a = left * right;
928            "#,
929            )
930            .unwrap();
931            let v = cx.globals().get("a").unwrap();
932            let val = deserialize_value::<String>(v);
933            assert_eq!(val, "1219326311370217952237463801111263526900");
934        });
935    }
936}