spo_rhai/serde/
de.rs

1//! Implement deserialization support of [`Dynamic`][crate::Dynamic] for [`serde`].
2
3use crate::api::formatting::map_std_type_name;
4use crate::types::dynamic::Union;
5use crate::{Dynamic, ImmutableString, LexError, Position, RhaiError, RhaiResultOf, ERR};
6use serde::de::{Error, IntoDeserializer, Visitor};
7use serde::{Deserialize, Deserializer};
8#[cfg(feature = "no_std")]
9use std::prelude::v1::*;
10use std::{any::type_name, fmt};
11
12/// Deserializer for [`Dynamic`][crate::Dynamic].
13pub struct DynamicDeserializer<'de>(&'de Dynamic);
14
15impl<'de> IntoDeserializer<'de, RhaiError> for &'de Dynamic {
16    type Deserializer = DynamicDeserializer<'de>;
17
18    #[inline(always)]
19    #[must_use]
20    fn into_deserializer(self) -> Self::Deserializer {
21        DynamicDeserializer(self)
22    }
23}
24
25impl<'de> DynamicDeserializer<'de> {
26    /// Create a [`DynamicDeserializer`] from a reference to a [`Dynamic`][crate::Dynamic] value.
27    ///
28    /// The reference is necessary because the deserialized type may hold references
29    /// (especially `&str`) to the source [`Dynamic`][crate::Dynamic].
30    #[inline(always)]
31    #[must_use]
32    pub const fn new(value: &'de Dynamic) -> Self {
33        Self(value)
34    }
35    /// Shortcut for a type conversion error.
36    #[cold]
37    #[inline(always)]
38    fn type_error<T>(&self) -> RhaiResultOf<T> {
39        self.type_error_str(map_std_type_name(type_name::<T>(), false))
40    }
41    /// Shortcut for a type conversion error.
42    #[cold]
43    #[inline(never)]
44    fn type_error_str<T>(&self, actual: &str) -> RhaiResultOf<T> {
45        let expected = map_std_type_name(self.0.type_name(), false).into();
46        Err(ERR::ErrorMismatchOutputType(actual.into(), expected, Position::NONE).into())
47    }
48    #[inline(always)]
49    fn deserialize_int<V: Visitor<'de>>(v: crate::INT, visitor: V) -> RhaiResultOf<V::Value> {
50        #[cfg(not(feature = "only_i32"))]
51        return visitor.visit_i64(v);
52        #[cfg(feature = "only_i32")]
53        return visitor.visit_i32(v);
54    }
55}
56
57/// Deserialize a [`Dynamic`][crate::Dynamic] value into a Rust type that implements [`serde::Deserialize`].
58///
59/// # Example
60///
61/// ```
62/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
63/// # #[cfg(not(feature = "no_index"))]
64/// # #[cfg(not(feature = "no_object"))]
65/// # {
66/// use rhai::{Dynamic, Array, Map, INT};
67/// use rhai::serde::from_dynamic;
68/// use serde::Deserialize;
69///
70/// #[derive(Debug, Deserialize, PartialEq)]
71/// struct Hello {
72///     a: INT,
73///     b: bool,
74/// }
75///
76/// #[derive(Debug, Deserialize, PartialEq)]
77/// struct Test {
78///     int: u32,
79///     seq: Vec<String>,
80///     obj: Hello,
81/// }
82///
83/// let mut map = Map::new();
84/// map.insert("int".into(), Dynamic::from(42_u32));
85///
86/// let mut map2 = Map::new();
87/// map2.insert("a".into(), (123 as INT).into());
88/// map2.insert("b".into(), true.into());
89///
90/// map.insert("obj".into(), map2.into());
91///
92/// let arr: Array = vec!["foo".into(), "bar".into(), "baz".into()];
93/// map.insert("seq".into(), arr.into());
94///
95/// let value: Test = from_dynamic(&map.into())?;
96///
97/// let expected = Test {
98///     int: 42,
99///     seq: vec!["foo".into(), "bar".into(), "baz".into()],
100///     obj: Hello { a: 123, b: true },
101/// };
102///
103/// assert_eq!(value, expected);
104/// # }
105/// # Ok(())
106/// # }
107/// ```
108pub fn from_dynamic<'de, T: Deserialize<'de>>(value: &'de Dynamic) -> RhaiResultOf<T> {
109    T::deserialize(DynamicDeserializer::new(value))
110}
111
112impl Error for RhaiError {
113    #[cold]
114    #[inline(never)]
115    fn custom<T: fmt::Display>(err: T) -> Self {
116        LexError::ImproperSymbol(String::new(), err.to_string())
117            .into_err(Position::NONE)
118            .into()
119    }
120}
121
122impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
123    type Error = RhaiError;
124
125    fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
126        if type_name::<V::Value>() == type_name::<Dynamic>() {
127            return Ok(reify! { self.0.clone() => !!! V::Value });
128        }
129
130        match self.0 .0 {
131            Union::Unit(..) => self.deserialize_unit(visitor),
132            Union::Bool(..) => self.deserialize_bool(visitor),
133            Union::Str(..) => self.deserialize_str(visitor),
134            Union::Char(..) => self.deserialize_char(visitor),
135
136            #[cfg(not(feature = "only_i32"))]
137            Union::Int(..) => self.deserialize_i64(visitor),
138            #[cfg(feature = "only_i32")]
139            Union::Int(..) => self.deserialize_i32(visitor),
140
141            #[cfg(not(feature = "no_float"))]
142            #[cfg(not(feature = "f32_float"))]
143            Union::Float(..) => self.deserialize_f64(visitor),
144            #[cfg(not(feature = "no_float"))]
145            #[cfg(feature = "f32_float")]
146            Union::Float(..) => self.deserialize_f32(visitor),
147
148            #[cfg(feature = "decimal")]
149            #[cfg(not(feature = "f32_float"))]
150            Union::Decimal(..) => self.deserialize_f64(visitor),
151            #[cfg(feature = "decimal")]
152            #[cfg(feature = "f32_float")]
153            Union::Decimal(..) => self.deserialize_f32(visitor),
154
155            #[cfg(not(feature = "no_index"))]
156            Union::Array(..) => self.deserialize_seq(visitor),
157            #[cfg(not(feature = "no_index"))]
158            Union::Blob(..) => self.deserialize_bytes(visitor),
159            #[cfg(not(feature = "no_object"))]
160            Union::Map(..) => self.deserialize_map(visitor),
161            Union::FnPtr(..) => self.type_error(),
162            #[cfg(not(feature = "no_time"))]
163            Union::TimeStamp(..) => self.type_error(),
164
165            Union::Variant(ref value, ..) if value.is::<i8>() => self.deserialize_i8(visitor),
166            Union::Variant(ref value, ..) if value.is::<i16>() => self.deserialize_i16(visitor),
167            Union::Variant(ref value, ..) if value.is::<i32>() => self.deserialize_i32(visitor),
168            Union::Variant(ref value, ..) if value.is::<i64>() => self.deserialize_i64(visitor),
169            Union::Variant(ref value, ..) if value.is::<i128>() => self.deserialize_i128(visitor),
170            Union::Variant(ref value, ..) if value.is::<u8>() => self.deserialize_u8(visitor),
171            Union::Variant(ref value, ..) if value.is::<u16>() => self.deserialize_u16(visitor),
172            Union::Variant(ref value, ..) if value.is::<u32>() => self.deserialize_u32(visitor),
173            Union::Variant(ref value, ..) if value.is::<u64>() => self.deserialize_u64(visitor),
174            Union::Variant(ref value, ..) if value.is::<u128>() => self.deserialize_u128(visitor),
175
176            Union::Variant(..) => self.type_error(),
177
178            #[cfg(not(feature = "no_closure"))]
179            Union::Shared(..) => self.type_error(),
180        }
181    }
182
183    fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
184        visitor.visit_bool(self.0.as_bool().or_else(|_| self.type_error())?)
185    }
186
187    fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
188        match self.0.as_int() {
189            Ok(v) => Self::deserialize_int(v, visitor),
190            Err(_) => self
191                .0
192                .downcast_ref::<i8>()
193                .map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x)),
194        }
195    }
196
197    fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
198        match self.0.as_int() {
199            Ok(v) => Self::deserialize_int(v, visitor),
200            Err(_) => self
201                .0
202                .downcast_ref::<i16>()
203                .map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x)),
204        }
205    }
206
207    fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
208        match self.0.as_int() {
209            Ok(v) => Self::deserialize_int(v, visitor),
210            _ if cfg!(feature = "only_i32") => self.type_error(),
211            _ => self
212                .0
213                .downcast_ref::<i32>()
214                .map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x)),
215        }
216    }
217
218    fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
219        match self.0.as_int() {
220            Ok(v) => Self::deserialize_int(v, visitor),
221            _ if cfg!(not(feature = "only_i32")) => self.type_error(),
222            _ => self
223                .0
224                .downcast_ref::<i64>()
225                .map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x)),
226        }
227    }
228
229    fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
230        match self.0.as_int() {
231            Ok(v) => Self::deserialize_int(v, visitor),
232            _ if cfg!(not(feature = "only_i32")) => self.type_error(),
233            _ => self
234                .0
235                .downcast_ref::<i128>()
236                .map_or_else(|| self.type_error(), |&x| visitor.visit_i128(x)),
237        }
238    }
239
240    fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
241        match self.0.as_int() {
242            Ok(v) => Self::deserialize_int(v, visitor),
243            Err(_) => self
244                .0
245                .downcast_ref::<u8>()
246                .map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x)),
247        }
248    }
249
250    fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
251        match self.0.as_int() {
252            Ok(v) => Self::deserialize_int(v, visitor),
253            Err(_) => self
254                .0
255                .downcast_ref::<u16>()
256                .map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x)),
257        }
258    }
259
260    fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
261        match self.0.as_int() {
262            Ok(v) => Self::deserialize_int(v, visitor),
263            Err(_) => self
264                .0
265                .downcast_ref::<u32>()
266                .map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x)),
267        }
268    }
269
270    fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
271        match self.0.as_int() {
272            Ok(v) => Self::deserialize_int(v, visitor),
273            Err(_) => self
274                .0
275                .downcast_ref::<u64>()
276                .map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x)),
277        }
278    }
279
280    fn deserialize_u128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
281        match self.0.as_int() {
282            Ok(v) => Self::deserialize_int(v, visitor),
283            Err(_) => self
284                .0
285                .downcast_ref::<u128>()
286                .map_or_else(|| self.type_error(), |&x| visitor.visit_u128(x)),
287        }
288    }
289
290    fn deserialize_f32<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
291        #[cfg(not(feature = "no_float"))]
292        return self
293            .0
294            .downcast_ref::<f32>()
295            .map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
296
297        #[allow(unreachable_code)]
298        {
299            #[cfg(feature = "decimal")]
300            {
301                use rust_decimal::prelude::ToPrimitive;
302
303                return self
304                    .0
305                    .downcast_ref::<rust_decimal::Decimal>()
306                    .and_then(|&x| x.to_f32())
307                    .map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
308            }
309
310            self.type_error_str("f32")
311        }
312    }
313
314    fn deserialize_f64<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
315        #[cfg(not(feature = "no_float"))]
316        return self
317            .0
318            .downcast_ref::<f64>()
319            .map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
320
321        #[allow(unreachable_code)]
322        {
323            #[cfg(feature = "decimal")]
324            {
325                use rust_decimal::prelude::ToPrimitive;
326
327                return self
328                    .0
329                    .downcast_ref::<rust_decimal::Decimal>()
330                    .and_then(|&x| x.to_f64())
331                    .map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
332            }
333
334            self.type_error_str("f64")
335        }
336    }
337
338    fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
339        self.0
340            .downcast_ref::<char>()
341            .map_or_else(|| self.type_error(), |&x| visitor.visit_char(x))
342    }
343
344    fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
345        self.0
346            .downcast_ref::<ImmutableString>()
347            .map_or_else(|| self.type_error(), |x| visitor.visit_borrowed_str(x))
348    }
349
350    fn deserialize_string<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
351        self.deserialize_str(visitor)
352    }
353
354    fn deserialize_bytes<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
355        #[cfg(not(feature = "no_index"))]
356        return self
357            .0
358            .downcast_ref::<crate::Blob>()
359            .map_or_else(|| self.type_error(), |x| _visitor.visit_bytes(x));
360
361        #[cfg(feature = "no_index")]
362        return self.type_error();
363    }
364
365    fn deserialize_byte_buf<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
366        self.deserialize_bytes(visitor)
367    }
368
369    fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
370        if self.0.is_unit() {
371            visitor.visit_none()
372        } else {
373            visitor.visit_some(self)
374        }
375    }
376
377    fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
378        self.0
379            .downcast_ref::<()>()
380            .map_or_else(|| self.type_error(), |()| visitor.visit_unit())
381    }
382
383    fn deserialize_unit_struct<V: Visitor<'de>>(
384        self,
385        _name: &'static str,
386        visitor: V,
387    ) -> RhaiResultOf<V::Value> {
388        self.deserialize_unit(visitor)
389    }
390
391    fn deserialize_newtype_struct<V: Visitor<'de>>(
392        self,
393        _name: &'static str,
394        visitor: V,
395    ) -> RhaiResultOf<V::Value> {
396        visitor.visit_newtype_struct(self)
397    }
398
399    fn deserialize_seq<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
400        #[cfg(not(feature = "no_index"))]
401        return self.0.downcast_ref::<crate::Array>().map_or_else(
402            || self.type_error(),
403            |arr| _visitor.visit_seq(IterateDynamicArray::new(arr.iter())),
404        );
405
406        #[cfg(feature = "no_index")]
407        return self.type_error();
408    }
409
410    fn deserialize_tuple<V: Visitor<'de>>(self, _len: usize, visitor: V) -> RhaiResultOf<V::Value> {
411        self.deserialize_seq(visitor)
412    }
413
414    fn deserialize_tuple_struct<V: Visitor<'de>>(
415        self,
416        _name: &'static str,
417        _len: usize,
418        visitor: V,
419    ) -> RhaiResultOf<V::Value> {
420        self.deserialize_seq(visitor)
421    }
422
423    fn deserialize_map<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
424        #[cfg(not(feature = "no_object"))]
425        return self.0.downcast_ref::<crate::Map>().map_or_else(
426            || self.type_error(),
427            |map| {
428                _visitor.visit_map(IterateMap::new(
429                    map.keys().map(crate::SmartString::as_str),
430                    map.values(),
431                ))
432            },
433        );
434
435        #[cfg(feature = "no_object")]
436        return self.type_error();
437    }
438
439    fn deserialize_struct<V: Visitor<'de>>(
440        self,
441        _name: &'static str,
442        _fields: &'static [&'static str],
443        _visitor: V,
444    ) -> RhaiResultOf<V::Value> {
445        #[cfg(not(feature = "no_object"))]
446        return self.0.downcast_ref::<crate::Map>().map_or_else(
447            || {
448                Err(ERR::ErrorMismatchOutputType(
449                    map_std_type_name(type_name::<crate::Map>(), false).into(),
450                    map_std_type_name(self.0.type_name(), false).into(),
451                    Position::NONE,
452                )
453                .into())
454            },
455            |map| {
456                _visitor.visit_map(IterateMap::new(
457                    map.keys().map(crate::SmartString::as_str),
458                    map.values(),
459                ))
460            },
461        );
462
463        #[cfg(feature = "no_object")]
464        return self.type_error();
465    }
466
467    fn deserialize_enum<V: Visitor<'de>>(
468        self,
469        _name: &'static str,
470        _variants: &'static [&'static str],
471        visitor: V,
472    ) -> RhaiResultOf<V::Value> {
473        match self.0.read_lock::<ImmutableString>() {
474            Some(s) => visitor.visit_enum(s.into_deserializer()),
475            None => {
476                #[cfg(not(feature = "no_object"))]
477                return self.0.downcast_ref::<crate::Map>().map_or_else(
478                    || self.type_error(),
479                    |map| {
480                        let mut iter = map.iter();
481                        let first = iter.next();
482                        let second = iter.next();
483                        match (first, second) {
484                            (Some((key, value)), None) => visitor.visit_enum(EnumDeserializer {
485                                tag: key,
486                                content: DynamicDeserializer::new(value),
487                            }),
488                            _ => self.type_error(),
489                        }
490                    },
491                );
492                #[cfg(feature = "no_object")]
493                return self.type_error();
494            }
495        }
496    }
497
498    #[inline(always)]
499    fn deserialize_identifier<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
500        self.deserialize_str(visitor)
501    }
502
503    #[inline(always)]
504    fn deserialize_ignored_any<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
505        self.deserialize_any(visitor)
506    }
507}
508
509/// `SeqAccess` implementation for arrays.
510#[cfg(not(feature = "no_index"))]
511struct IterateDynamicArray<'de, ITER: Iterator<Item = &'de Dynamic>> {
512    /// Iterator for a stream of [`Dynamic`][crate::Dynamic] values.
513    iter: ITER,
514}
515
516#[cfg(not(feature = "no_index"))]
517impl<'de, ITER: Iterator<Item = &'de Dynamic>> IterateDynamicArray<'de, ITER> {
518    #[inline(always)]
519    #[must_use]
520    pub const fn new(iter: ITER) -> Self {
521        Self { iter }
522    }
523}
524
525#[cfg(not(feature = "no_index"))]
526impl<'de, ITER: Iterator<Item = &'de Dynamic>> serde::de::SeqAccess<'de>
527    for IterateDynamicArray<'de, ITER>
528{
529    type Error = RhaiError;
530
531    fn next_element_seed<T: serde::de::DeserializeSeed<'de>>(
532        &mut self,
533        seed: T,
534    ) -> RhaiResultOf<Option<T::Value>> {
535        // Deserialize each item coming out of the iterator.
536        self.iter.next().map_or(Ok(None), |item| {
537            seed.deserialize(item.into_deserializer()).map(Some)
538        })
539    }
540}
541
542/// `MapAccess` implementation for maps.
543#[cfg(not(feature = "no_object"))]
544struct IterateMap<'de, K: Iterator<Item = &'de str>, V: Iterator<Item = &'de Dynamic>> {
545    // Iterator for a stream of [`Dynamic`][crate::Dynamic] keys.
546    keys: K,
547    // Iterator for a stream of [`Dynamic`][crate::Dynamic] values.
548    values: V,
549}
550
551#[cfg(not(feature = "no_object"))]
552impl<'de, K: Iterator<Item = &'de str>, V: Iterator<Item = &'de Dynamic>> IterateMap<'de, K, V> {
553    #[inline(always)]
554    #[must_use]
555    pub const fn new(keys: K, values: V) -> Self {
556        Self { keys, values }
557    }
558}
559
560#[cfg(not(feature = "no_object"))]
561impl<'de, K: Iterator<Item = &'de str>, V: Iterator<Item = &'de Dynamic>> serde::de::MapAccess<'de>
562    for IterateMap<'de, K, V>
563{
564    type Error = RhaiError;
565
566    fn next_key_seed<S: serde::de::DeserializeSeed<'de>>(
567        &mut self,
568        seed: S,
569    ) -> RhaiResultOf<Option<S::Value>> {
570        // Deserialize each `Identifier` key coming out of the keys iterator.
571        self.keys
572            .next()
573            .map(<_>::into_deserializer)
574            .map_or(Ok(None), |d| seed.deserialize(d).map(Some))
575    }
576
577    fn next_value_seed<S: serde::de::DeserializeSeed<'de>>(
578        &mut self,
579        seed: S,
580    ) -> RhaiResultOf<S::Value> {
581        // Deserialize each value item coming out of the iterator.
582        seed.deserialize(self.values.next().unwrap().into_deserializer())
583    }
584}
585
586#[cfg(not(feature = "no_object"))]
587struct EnumDeserializer<'de> {
588    tag: &'de str,
589    content: DynamicDeserializer<'de>,
590}
591
592#[cfg(not(feature = "no_object"))]
593impl<'de> serde::de::EnumAccess<'de> for EnumDeserializer<'de> {
594    type Error = RhaiError;
595    type Variant = Self;
596
597    fn variant_seed<V: serde::de::DeserializeSeed<'de>>(
598        self,
599        seed: V,
600    ) -> RhaiResultOf<(V::Value, Self::Variant)> {
601        seed.deserialize(self.tag.into_deserializer())
602            .map(|v| (v, self))
603    }
604}
605
606#[cfg(not(feature = "no_object"))]
607impl<'de> serde::de::VariantAccess<'de> for EnumDeserializer<'de> {
608    type Error = RhaiError;
609
610    #[inline(always)]
611    fn unit_variant(self) -> RhaiResultOf<()> {
612        Deserialize::deserialize(self.content)
613    }
614
615    #[inline(always)]
616    fn newtype_variant_seed<T: serde::de::DeserializeSeed<'de>>(
617        self,
618        seed: T,
619    ) -> RhaiResultOf<T::Value> {
620        seed.deserialize(self.content)
621    }
622
623    #[inline(always)]
624    fn tuple_variant<V: Visitor<'de>>(self, len: usize, visitor: V) -> RhaiResultOf<V::Value> {
625        self.content.deserialize_tuple(len, visitor)
626    }
627
628    #[inline(always)]
629    fn struct_variant<V: Visitor<'de>>(
630        self,
631        fields: &'static [&'static str],
632        visitor: V,
633    ) -> RhaiResultOf<V::Value> {
634        self.content.deserialize_struct("", fields, visitor)
635    }
636}