serde_wasm_bindgen/
de.rs

1use js_sys::{Array, ArrayBuffer, JsString, Number, Object, Symbol, Uint8Array};
2use serde::de::value::{MapDeserializer, SeqDeserializer};
3use serde::de::{self, IntoDeserializer};
4use std::convert::TryFrom;
5use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt};
6
7use super::{static_str_to_js, Error, ObjectExt, Result};
8
9/// Provides [`de::SeqAccess`] from any JS iterator.
10struct SeqAccess {
11    iter: js_sys::IntoIter,
12}
13
14impl<'de> de::SeqAccess<'de> for SeqAccess {
15    type Error = Error;
16
17    fn next_element_seed<T: de::DeserializeSeed<'de>>(
18        &mut self,
19        seed: T,
20    ) -> Result<Option<T::Value>> {
21        Ok(match self.iter.next().transpose()? {
22            Some(value) => Some(seed.deserialize(Deserializer::from(value))?),
23            None => None,
24        })
25    }
26}
27
28/// Provides [`serde::de::MapAccess`] from any JS iterator that returns `[key, value]` pairs.
29struct MapAccess {
30    iter: js_sys::IntoIter,
31    next_value: Option<Deserializer>,
32}
33
34impl MapAccess {
35    const fn new(iter: js_sys::IntoIter) -> Self {
36        Self {
37            iter,
38            next_value: None,
39        }
40    }
41}
42
43impl<'de> de::MapAccess<'de> for MapAccess {
44    type Error = Error;
45
46    fn next_key_seed<K: de::DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
47        debug_assert!(self.next_value.is_none());
48
49        Ok(match self.iter.next().transpose()? {
50            Some(pair) => {
51                let (key, value) = convert_pair(pair);
52                self.next_value = Some(value);
53                Some(seed.deserialize(key)?)
54            }
55            None => None,
56        })
57    }
58
59    fn next_value_seed<V: de::DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value> {
60        seed.deserialize(self.next_value.take().unwrap_throw())
61    }
62}
63
64struct ObjectAccess {
65    obj: ObjectExt,
66    fields: std::slice::Iter<'static, &'static str>,
67    next_value: Option<Deserializer>,
68}
69
70impl ObjectAccess {
71    fn new(obj: ObjectExt, fields: &'static [&'static str]) -> Self {
72        Self {
73            obj,
74            fields: fields.iter(),
75            next_value: None,
76        }
77    }
78}
79
80fn str_deserializer(s: &str) -> de::value::StrDeserializer<Error> {
81    de::IntoDeserializer::into_deserializer(s)
82}
83
84impl<'de> de::MapAccess<'de> for ObjectAccess {
85    type Error = Error;
86
87    fn next_key_seed<K: de::DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
88        debug_assert!(self.next_value.is_none());
89
90        for field in &mut self.fields {
91            let js_field = static_str_to_js(field);
92            let next_value = self.obj.get_with_ref_key(&js_field);
93            // If this value is `undefined`, it might be actually a missing field;
94            // double-check with an `in` operator if so.
95            let is_missing_field = next_value.is_undefined() && !js_field.js_in(&self.obj);
96            if !is_missing_field {
97                self.next_value = Some(Deserializer::from(next_value));
98                return Ok(Some(seed.deserialize(str_deserializer(field))?));
99            }
100        }
101
102        Ok(None)
103    }
104
105    fn next_value_seed<V: de::DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value> {
106        seed.deserialize(self.next_value.take().unwrap_throw())
107    }
108}
109
110/// Provides [`serde::de::EnumAccess`] from given JS values for the `tag` and the `payload`.
111struct EnumAccess {
112    tag: Deserializer,
113    payload: Deserializer,
114}
115
116impl<'de> de::EnumAccess<'de> for EnumAccess {
117    type Error = Error;
118    type Variant = Deserializer;
119
120    fn variant_seed<V: de::DeserializeSeed<'de>>(
121        self,
122        seed: V,
123    ) -> Result<(V::Value, Self::Variant)> {
124        Ok((seed.deserialize(self.tag)?, self.payload))
125    }
126}
127
128/// A newtype that allows using any [`JsValue`] as a [`serde::Deserializer`].
129pub struct Deserializer {
130    value: JsValue,
131}
132
133impl From<JsValue> for Deserializer {
134    fn from(value: JsValue) -> Self {
135        Self { value }
136    }
137}
138
139// Ideally this would be implemented for `JsValue` instead, but we can't because
140// of the orphan rule.
141impl<'de> IntoDeserializer<'de, Error> for Deserializer {
142    type Deserializer = Self;
143
144    fn into_deserializer(self) -> Self::Deserializer {
145        self
146    }
147}
148
149/// Destructures a JS `[key, value]` pair into a tuple of [`Deserializer`]s.
150fn convert_pair(pair: JsValue) -> (Deserializer, Deserializer) {
151    let pair = pair.unchecked_into::<Array>();
152    (pair.get(0).into(), pair.get(1).into())
153}
154
155impl Deserializer {
156    /// Casts the internal value into an object, including support for prototype-less objects.
157    /// See https://github.com/rustwasm/wasm-bindgen/issues/1366 for why we don't use `dyn_ref`.
158    fn as_object_entries(&self) -> Option<Array> {
159        if self.value.is_object() {
160            Some(Object::entries(self.value.unchecked_ref()))
161        } else {
162            None
163        }
164    }
165
166    fn is_nullish(&self) -> bool {
167        self.value.loose_eq(&JsValue::NULL)
168    }
169
170    fn as_bytes(&self) -> Option<Vec<u8>> {
171        let temp;
172
173        let v = if let Some(v) = self.value.dyn_ref::<Uint8Array>() {
174            v
175        } else if let Some(v) = self.value.dyn_ref::<ArrayBuffer>() {
176            temp = Uint8Array::new(v);
177            &temp
178        } else {
179            return None;
180        };
181
182        Some(v.to_vec())
183    }
184
185    #[cold]
186    fn invalid_type_(&self, visitor: &dyn de::Expected) -> Error {
187        let string;
188        let bytes;
189
190        let unexpected = if self.is_nullish() {
191            de::Unexpected::Unit
192        } else if let Some(v) = self.value.as_bool() {
193            de::Unexpected::Bool(v)
194        } else if let Some(v) = self.value.as_f64() {
195            de::Unexpected::Float(v)
196        } else if let Some(v) = self.value.as_string() {
197            string = v;
198            de::Unexpected::Str(&string)
199        } else if let Some(v) = self.as_bytes() {
200            bytes = v;
201            de::Unexpected::Bytes(&bytes)
202        } else {
203            string = format!("{:?}", self.value);
204            de::Unexpected::Other(&string)
205        };
206
207        de::Error::invalid_type(unexpected, visitor)
208    }
209
210    fn invalid_type<'de, V: de::Visitor<'de>>(&self, visitor: V) -> Result<V::Value> {
211        Err(self.invalid_type_(&visitor))
212    }
213
214    fn as_safe_integer(&self) -> Option<i64> {
215        if let Some(v) = self.value.as_f64() {
216            if Number::is_safe_integer(&self.value) {
217                return Some(v as i64);
218            }
219        }
220        None
221    }
222
223    fn deserialize_from_js_number_signed<'de, V: de::Visitor<'de>>(
224        &self,
225        visitor: V,
226    ) -> Result<V::Value> {
227        match self.as_safe_integer() {
228            Some(v) => visitor.visit_i64(v),
229            _ => self.invalid_type(visitor),
230        }
231    }
232
233    fn deserialize_from_js_number_unsigned<'de, V: de::Visitor<'de>>(
234        &self,
235        visitor: V,
236    ) -> Result<V::Value> {
237        match self.as_safe_integer() {
238            Some(v) if v >= 0 => visitor.visit_u64(v as _),
239            _ => self.invalid_type(visitor),
240        }
241    }
242
243    fn deserialize_from_array<'de, V: de::Visitor<'de>>(
244        &self,
245        visitor: V,
246        array: &Array,
247    ) -> Result<V::Value> {
248        visitor.visit_seq(SeqDeserializer::new(array.iter().map(Deserializer::from)))
249    }
250}
251
252impl<'de> de::Deserializer<'de> for Deserializer {
253    type Error = Error;
254
255    fn deserialize_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
256        if self.is_nullish() {
257            // Ideally we would only treat `undefined` as `()` / `None` which would be semantically closer
258            // to JS definitions, but, unfortunately, WebIDL generates missing values as `null`
259            // and we probably want to support these as well.
260            visitor.visit_unit()
261        } else if let Some(v) = self.value.as_bool() {
262            visitor.visit_bool(v)
263        } else if self.value.is_bigint() {
264            match i64::try_from(self.value) {
265                Ok(v) => visitor.visit_i64(v),
266                Err(value) => match u64::try_from(value) {
267                    Ok(v) => visitor.visit_u64(v),
268                    Err(_) => Err(de::Error::custom("Couldn't deserialize i64 or u64 from a BigInt outside i64::MIN..u64::MAX bounds"))
269                }
270            }
271        } else if let Some(v) = self.value.as_f64() {
272            if Number::is_safe_integer(&self.value) {
273                visitor.visit_i64(v as i64)
274            } else {
275                visitor.visit_f64(v)
276            }
277        } else if let Some(v) = self.value.as_string() {
278            visitor.visit_string(v)
279        } else if Array::is_array(&self.value) {
280            self.deserialize_seq(visitor)
281        } else if self.value.is_object() &&
282            // The only reason we want to support objects here is because serde uses
283            // `deserialize_any` for internally tagged enums
284            // (see https://github.com/cloudflare/serde-wasm-bindgen/pull/4#discussion_r352245020).
285            //
286            // We expect such enums to be represented via plain JS objects, so let's explicitly
287            // exclude Sets, Maps and any other iterables. These should be deserialized via concrete
288            // `deserialize_*` methods instead of us trying to guess the right target type.
289            //
290            // Hopefully we can rid of these hacks altogether once
291            // https://github.com/serde-rs/serde/issues/1183 is implemented / fixed on serde side.
292            !Symbol::iterator().js_in(&self.value)
293        {
294            self.deserialize_map(visitor)
295        } else {
296            self.invalid_type(visitor)
297        }
298    }
299
300    fn deserialize_unit<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
301        if self.is_nullish() {
302            visitor.visit_unit()
303        } else {
304            self.invalid_type(visitor)
305        }
306    }
307
308    fn deserialize_unit_struct<V: de::Visitor<'de>>(
309        self,
310        _name: &'static str,
311        visitor: V,
312    ) -> Result<V::Value> {
313        self.deserialize_unit(visitor)
314    }
315
316    fn deserialize_bool<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
317        if let Some(v) = self.value.as_bool() {
318            visitor.visit_bool(v)
319        } else {
320            self.invalid_type(visitor)
321        }
322    }
323
324    // Serde happily converts `f64` to `f32` (with checks), so we can forward.
325    fn deserialize_f32<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
326        self.deserialize_f64(visitor)
327    }
328
329    fn deserialize_f64<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
330        if let Some(v) = self.value.as_f64() {
331            visitor.visit_f64(v)
332        } else {
333            self.invalid_type(visitor)
334        }
335    }
336
337    fn deserialize_identifier<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
338        self.deserialize_str(visitor)
339    }
340
341    fn deserialize_str<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
342        self.deserialize_string(visitor)
343    }
344
345    fn deserialize_string<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
346        if let Some(v) = self.value.as_string() {
347            visitor.visit_string(v)
348        } else {
349            self.invalid_type(visitor)
350        }
351    }
352
353    // Serde happily converts any integer to any integer (with checks), so let's forward all of
354    // these to 64-bit methods to save some space in the generated WASM.
355
356    fn deserialize_i8<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
357        self.deserialize_from_js_number_signed(visitor)
358    }
359
360    fn deserialize_i16<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
361        self.deserialize_from_js_number_signed(visitor)
362    }
363
364    fn deserialize_i32<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
365        self.deserialize_from_js_number_signed(visitor)
366    }
367
368    fn deserialize_u8<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
369        self.deserialize_from_js_number_unsigned(visitor)
370    }
371
372    fn deserialize_u16<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
373        self.deserialize_from_js_number_unsigned(visitor)
374    }
375
376    fn deserialize_u32<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
377        self.deserialize_from_js_number_unsigned(visitor)
378    }
379
380    fn deserialize_i64<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
381        if self.value.is_bigint() {
382            match i64::try_from(self.value) {
383                Ok(v) => visitor.visit_i64(v),
384                Err(_) => Err(de::Error::custom(
385                    "Couldn't deserialize i64 from a BigInt outside i64::MIN..i64::MAX bounds",
386                )),
387            }
388        } else {
389            self.deserialize_from_js_number_signed(visitor)
390        }
391    }
392
393    fn deserialize_u64<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
394        if self.value.is_bigint() {
395            match u64::try_from(self.value) {
396                Ok(v) => visitor.visit_u64(v),
397                Err(_) => Err(de::Error::custom(
398                    "Couldn't deserialize u64 from a BigInt outside u64::MIN..u64::MAX bounds",
399                )),
400            }
401        } else {
402            self.deserialize_from_js_number_unsigned(visitor)
403        }
404    }
405
406    fn deserialize_i128<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
407        if self.value.is_bigint() {
408            match i128::try_from(self.value) {
409                Ok(v) => visitor.visit_i128(v),
410                Err(_) => Err(de::Error::custom(
411                    "Couldn't deserialize i128 from a BigInt outside i128::MIN..i128::MAX bounds",
412                )),
413            }
414        } else {
415            self.invalid_type(visitor)
416        }
417    }
418
419    fn deserialize_u128<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
420        if self.value.is_bigint() {
421            match u128::try_from(self.value) {
422                Ok(v) => visitor.visit_u128(v),
423                Err(_) => Err(de::Error::custom(
424                    "Couldn't deserialize u128 from a BigInt outside u128::MIN..u128::MAX bounds",
425                )),
426            }
427        } else {
428            self.invalid_type(visitor)
429        }
430    }
431
432    /// Converts a JavaScript string to a Rust char.
433    ///
434    /// By default we don't perform detection of single chars because it's pretty complicated,
435    /// but if we get a hint that they're expected, this methods allows to avoid heap allocations
436    /// of an intermediate `String` by directly converting numeric codepoints instead.
437    fn deserialize_char<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
438        if let Some(s) = self.value.dyn_ref::<JsString>() {
439            if let Some(c) = s.as_char() {
440                return visitor.visit_char(c);
441            }
442        }
443        self.invalid_type(visitor)
444    }
445
446    // Serde can deserialize `visit_unit` into `None`, but can't deserialize arbitrary value
447    // as `Some`, so we need to provide own simple implementation.
448    fn deserialize_option<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
449        if !self.is_nullish() {
450            visitor.visit_some(self)
451        } else {
452            visitor.visit_none()
453        }
454    }
455
456    /// Simply calls `visit_newtype_struct`.
457    fn deserialize_newtype_struct<V: de::Visitor<'de>>(
458        self,
459        _name: &'static str,
460        visitor: V,
461    ) -> Result<V::Value> {
462        visitor.visit_newtype_struct(self)
463    }
464
465    /// Supported inputs:
466    ///  - JS iterable (an object with [`[Symbol.iterator]`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator)).
467    /// Supported outputs:
468    ///  - Any Rust sequence from Serde point of view ([`Vec`], [`HashSet`](std::collections::HashSet), etc.)
469    fn deserialize_seq<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
470        if let Some(arr) = self.value.dyn_ref::<Array>() {
471            self.deserialize_from_array(visitor, arr)
472        } else if let Some(iter) = js_sys::try_iter(&self.value)? {
473            visitor.visit_seq(SeqAccess { iter })
474        } else {
475            self.invalid_type(visitor)
476        }
477    }
478
479    /// Forwards to [`Self::deserialize_seq`](#method.deserialize_seq).
480    fn deserialize_tuple<V: de::Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value> {
481        self.deserialize_seq(visitor)
482    }
483
484    /// Forwards to [`Self::deserialize_tuple`](#method.deserialize_tuple).
485    fn deserialize_tuple_struct<V: de::Visitor<'de>>(
486        self,
487        _name: &'static str,
488        len: usize,
489        visitor: V,
490    ) -> Result<V::Value> {
491        self.deserialize_tuple(len, visitor)
492    }
493
494    /// Supported inputs:
495    ///  - A JS iterable that is expected to return `[key, value]` pairs.
496    ///  - A JS object, which will be iterated using [`Object.entries`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries).
497    /// Supported outputs:
498    ///  - A Rust key-value map ([`HashMap`](std::collections::HashMap), [`BTreeMap`](std::collections::BTreeMap), etc.).
499    ///  - A typed Rust structure with `#[derive(Deserialize)]`.
500    fn deserialize_map<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
501        match js_sys::try_iter(&self.value)? {
502            Some(iter) => visitor.visit_map(MapAccess::new(iter)),
503            None => match self.as_object_entries() {
504                Some(arr) => visitor.visit_map(MapDeserializer::new(arr.iter().map(convert_pair))),
505                None => self.invalid_type(visitor),
506            },
507        }
508    }
509
510    /// Supported inputs:
511    ///  - A plain JS object.
512    /// Supported outputs:
513    ///  - A typed Rust structure with `#[derive(Deserialize)]`.
514    fn deserialize_struct<V: de::Visitor<'de>>(
515        self,
516        _name: &'static str,
517        fields: &'static [&'static str],
518        visitor: V,
519    ) -> Result<V::Value> {
520        let obj = if self.value.is_object() {
521            self.value.unchecked_into::<ObjectExt>()
522        } else {
523            return self.invalid_type(visitor);
524        };
525        visitor.visit_map(ObjectAccess::new(obj, fields))
526    }
527
528    /// Here we try to be compatible with `serde-json`, which means supporting:
529    ///  - `"Variant"` - gets converted to a unit variant `MyEnum::Variant`
530    ///  - `{ Variant: ...payload... }` - gets converted to a `MyEnum::Variant { ...payload... }`.
531    fn deserialize_enum<V: de::Visitor<'de>>(
532        self,
533        _name: &'static str,
534        _variants: &'static [&'static str],
535        visitor: V,
536    ) -> Result<V::Value> {
537        let access = if self.value.is_string() {
538            EnumAccess {
539                tag: self.value.into(),
540                payload: JsValue::UNDEFINED.into(),
541            }
542        } else if let Some(entries) = self.as_object_entries() {
543            if entries.length() != 1 {
544                return Err(de::Error::invalid_length(entries.length() as _, &"1"));
545            }
546            let entry = entries.get(0);
547            let (tag, payload) = convert_pair(entry);
548            EnumAccess { tag, payload }
549        } else {
550            return self.invalid_type(visitor);
551        };
552        visitor.visit_enum(access)
553    }
554
555    /// Ignores any value without calling to the JS side even to check its type.
556    fn deserialize_ignored_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
557        visitor.visit_unit()
558    }
559
560    /// We can't take references to JS memory, so forwards to an owned [`Self::deserialize_byte_buf`](#method.deserialize_byte_buf).
561    fn deserialize_bytes<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
562        self.deserialize_byte_buf(visitor)
563    }
564
565    /// Serde expects `visit_byte_buf` to be called only in response to an explicit `deserialize_bytes`,
566    /// so we provide conversions here.
567    ///
568    /// Supported inputs:
569    ///  - `ArrayBuffer` - converted to an `Uint8Array` view first.
570    ///  - `Uint8Array`, `Array` - copied to a newly created `Vec<u8>` on the Rust side.
571    fn deserialize_byte_buf<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
572        if let Some(bytes) = self.as_bytes() {
573            visitor.visit_byte_buf(bytes)
574        } else if let Some(arr) = self.value.dyn_ref::<Array>() {
575            self.deserialize_from_array(visitor, arr)
576        } else {
577            self.invalid_type(visitor)
578        }
579    }
580
581    fn is_human_readable(&self) -> bool {
582        true
583    }
584}
585
586impl<'de> de::VariantAccess<'de> for Deserializer {
587    type Error = Error;
588
589    fn unit_variant(self) -> Result<()> {
590        de::Deserialize::deserialize(self)
591    }
592
593    fn newtype_variant_seed<T: de::DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value> {
594        seed.deserialize(self)
595    }
596
597    fn tuple_variant<V: de::Visitor<'de>>(self, len: usize, visitor: V) -> Result<V::Value> {
598        de::Deserializer::deserialize_tuple(self, len, visitor)
599    }
600
601    fn struct_variant<V: de::Visitor<'de>>(
602        self,
603        fields: &'static [&'static str],
604        visitor: V,
605    ) -> Result<V::Value> {
606        de::Deserializer::deserialize_struct(self, "", fields, visitor)
607    }
608}