rquickjs_serde/
de.rs

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