rquickjs_serde/
de.rs

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