Skip to main content

mlua/serde/
de.rs

1//! Deserialize Lua values to a Rust data structure.
2
3use std::cell::RefCell;
4use std::os::raw::c_void;
5use std::rc::Rc;
6use std::result::Result as StdResult;
7
8use rustc_hash::FxHashSet;
9use serde::de::{self, IntoDeserializer};
10
11use crate::error::{Error, Result};
12use crate::table::{Table, TablePairs, TableSequence};
13use crate::userdata::AnyUserData;
14use crate::value::Value;
15
16/// A struct for deserializing Lua values into Rust values.
17#[derive(Debug, Default)]
18pub struct Deserializer {
19    value: Value,
20    options: Options,
21    visited: Rc<RefCell<FxHashSet<*const c_void>>>,
22    len: Option<usize>, // A length hint for sequences
23}
24
25/// A struct with options to change default deserializer behavior.
26#[derive(Debug, Clone, Copy)]
27#[non_exhaustive]
28pub struct Options {
29    /// Maximum nesting depth for tables.
30    ///
31    /// Increasing this limit may require a larger thread stack. Zero rejects all tables.
32    ///
33    /// Default: **128**
34    pub recursion_limit: usize,
35
36    /// If true, an attempt to serialize types such as [`Function`], [`Thread`], [`LightUserData`]
37    /// and [`Error`] will cause an error.
38    /// Otherwise these types skipped when iterating or serialized as unit type.
39    ///
40    /// Default: **true**
41    ///
42    /// [`Function`]: crate::Function
43    /// [`Thread`]: crate::Thread
44    /// [`LightUserData`]: crate::LightUserData
45    /// [`Error`]: crate::Error
46    pub deny_unsupported_types: bool,
47
48    /// If true, an attempt to serialize a recursive table (table that refers to itself)
49    /// will cause an error.
50    /// Otherwise subsequent attempts to serialize the same table will be ignored.
51    ///
52    /// Default: **true**
53    pub deny_recursive_tables: bool,
54
55    /// If true, keys in tables will be iterated in sorted order.
56    ///
57    /// Default: **false**
58    pub sort_keys: bool,
59
60    /// If true, empty Lua tables will be encoded as array, instead of map.
61    ///
62    /// Default: **false**
63    pub encode_empty_tables_as_array: bool,
64
65    /// If true, enable detection of mixed tables.
66    ///
67    /// A mixed table is a table that has both array-like and map-like entries or several borders.
68    /// See [`The Length Operator`] documentation for details about borders.
69    ///
70    /// When this option is disabled, a table with a non-zero length (with one or more borders) will
71    /// be always encoded as an array.
72    ///
73    /// Default: **false**
74    ///
75    /// [`The Length Operator`]: https://www.lua.org/manual/5.4/manual.html#3.4.7
76    pub detect_mixed_tables: bool,
77}
78
79impl Default for Options {
80    fn default() -> Self {
81        const { Self::new() }
82    }
83}
84
85impl Options {
86    /// Returns a new instance of `Options` with default parameters.
87    pub const fn new() -> Self {
88        Options {
89            recursion_limit: super::DEFAULT_RECURSION_LIMIT,
90            deny_unsupported_types: true,
91            deny_recursive_tables: true,
92            sort_keys: false,
93            encode_empty_tables_as_array: false,
94            detect_mixed_tables: false,
95        }
96    }
97
98    /// Sets [`recursion_limit`](Self::recursion_limit).
99    #[must_use]
100    pub const fn recursion_limit(mut self, limit: usize) -> Self {
101        self.recursion_limit = limit;
102        self
103    }
104
105    /// Sets [`deny_unsupported_types`] option.
106    ///
107    /// [`deny_unsupported_types`]: #structfield.deny_unsupported_types
108    #[must_use]
109    pub const fn deny_unsupported_types(mut self, enabled: bool) -> Self {
110        self.deny_unsupported_types = enabled;
111        self
112    }
113
114    /// Sets [`deny_recursive_tables`] option.
115    ///
116    /// [`deny_recursive_tables`]: #structfield.deny_recursive_tables
117    #[must_use]
118    pub const fn deny_recursive_tables(mut self, enabled: bool) -> Self {
119        self.deny_recursive_tables = enabled;
120        self
121    }
122
123    /// Sets [`sort_keys`] option.
124    ///
125    /// [`sort_keys`]: #structfield.sort_keys
126    #[must_use]
127    pub const fn sort_keys(mut self, enabled: bool) -> Self {
128        self.sort_keys = enabled;
129        self
130    }
131
132    /// Sets [`encode_empty_tables_as_array`] option.
133    ///
134    /// [`encode_empty_tables_as_array`]: #structfield.encode_empty_tables_as_array
135    #[must_use]
136    pub const fn encode_empty_tables_as_array(mut self, enabled: bool) -> Self {
137        self.encode_empty_tables_as_array = enabled;
138        self
139    }
140
141    /// Sets [`detect_mixed_tables`] option.
142    ///
143    /// [`detect_mixed_tables`]: #structfield.detect_mixed_tables
144    #[must_use]
145    pub const fn detect_mixed_tables(mut self, enable: bool) -> Self {
146        self.detect_mixed_tables = enable;
147        self
148    }
149}
150
151impl Deserializer {
152    /// Creates a new Lua Deserializer for the [`Value`].
153    pub fn new(value: Value) -> Self {
154        Self::new_with_options(value, Options::default())
155    }
156
157    /// Creates a new Lua Deserializer for the [`Value`] with custom options.
158    pub fn new_with_options(value: Value, options: Options) -> Self {
159        Deserializer {
160            value,
161            options,
162            ..Default::default()
163        }
164    }
165
166    fn from_parts(value: Value, options: Options, visited: Rc<RefCell<FxHashSet<*const c_void>>>) -> Self {
167        Deserializer {
168            value,
169            options,
170            visited,
171            len: None,
172        }
173    }
174
175    fn with_len(mut self, len: usize) -> Self {
176        self.len = Some(len);
177        self
178    }
179}
180
181impl<'de> serde::Deserializer<'de> for Deserializer {
182    type Error = Error;
183
184    #[inline]
185    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
186    where
187        V: de::Visitor<'de>,
188    {
189        match self.value {
190            Value::Nil => visitor.visit_unit(),
191            Value::Boolean(b) => visitor.visit_bool(b),
192            #[allow(clippy::useless_conversion)]
193            Value::Integer(i) => visitor.visit_i64(i.into()),
194            #[allow(clippy::useless_conversion)]
195            Value::Number(n) => visitor.visit_f64(n.into()),
196            #[cfg(feature = "luau")]
197            Value::Vector(_) => self.deserialize_seq(visitor),
198            Value::String(s) => match s.to_str() {
199                Ok(s) => visitor.visit_str(&s),
200                Err(_) => visitor.visit_bytes(&s.as_bytes()),
201            },
202            Value::Table(ref t) => {
203                if let Some(len) = t.encode_as_array(self.options) {
204                    self.with_len(len).deserialize_seq(visitor)
205                } else {
206                    self.deserialize_map(visitor)
207                }
208            }
209            Value::LightUserData(ud) if ud.0.is_null() => visitor.visit_none(),
210            Value::UserData(ud) if ud.is_serializable() => {
211                serde_userdata(ud, |value| value.deserialize_any(visitor))
212            }
213            #[cfg(feature = "luau")]
214            Value::Buffer(buf) => {
215                let lua = buf.0.lua.lock();
216                visitor.visit_bytes(buf.as_slice(&lua))
217            }
218            Value::Function(_)
219            | Value::Thread(_)
220            | Value::UserData(_)
221            | Value::LightUserData(_)
222            | Value::Error(_)
223            | Value::Other(_) => {
224                if self.options.deny_unsupported_types {
225                    let msg = format!("unsupported value type `{}`", self.value.type_name());
226                    Err(de::Error::custom(msg))
227                } else {
228                    visitor.visit_unit()
229                }
230            }
231        }
232    }
233
234    #[inline]
235    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
236    where
237        V: de::Visitor<'de>,
238    {
239        match self.value {
240            Value::Nil => visitor.visit_none(),
241            Value::LightUserData(ud) if ud.0.is_null() => visitor.visit_none(),
242            _ => visitor.visit_some(self),
243        }
244    }
245
246    #[inline]
247    fn deserialize_enum<V>(
248        self,
249        name: &'static str,
250        variants: &'static [&'static str],
251        visitor: V,
252    ) -> Result<V::Value>
253    where
254        V: de::Visitor<'de>,
255    {
256        let (variant, value, _guard) = match self.value {
257            Value::Table(table) => {
258                let _guard = RecursionGuard::new(&table, &self.visited, self.options.recursion_limit)
259                    .map_err(|err| Error::DeserializeError(err.to_string()))?;
260
261                let mut iter = table.pairs::<String, Value>();
262                let (variant, value) = match iter.next() {
263                    Some(v) => v?,
264                    None => {
265                        return Err(de::Error::invalid_value(
266                            de::Unexpected::Map,
267                            &"map with a single key",
268                        ));
269                    }
270                };
271
272                if iter.next().is_some() {
273                    return Err(de::Error::invalid_value(
274                        de::Unexpected::Map,
275                        &"map with a single key",
276                    ));
277                }
278                let skip = check_value_for_skip(&value, self.options, &self.visited)
279                    .map_err(|err| Error::DeserializeError(err.to_string()))?;
280                if skip {
281                    return Err(de::Error::custom("bad enum value"));
282                }
283
284                (variant, Some(value), Some(_guard))
285            }
286            Value::String(variant) => (variant.to_str()?.to_owned(), None, None),
287            Value::UserData(ud) if ud.is_serializable() => {
288                return serde_userdata(ud, |value| value.deserialize_enum(name, variants, visitor));
289            }
290            _ => return Err(de::Error::custom("bad enum value")),
291        };
292
293        visitor.visit_enum(EnumDeserializer {
294            variant,
295            value,
296            options: self.options,
297            visited: self.visited,
298        })
299    }
300
301    #[inline]
302    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
303    where
304        V: de::Visitor<'de>,
305    {
306        match self.value {
307            #[cfg(feature = "luau")]
308            Value::Vector(vec) => {
309                let mut deserializer = VecDeserializer {
310                    vec,
311                    next: 0,
312                    options: self.options,
313                    visited: self.visited,
314                };
315                let seq = visitor.visit_seq(&mut deserializer)?;
316                if deserializer.next == crate::Vector::SIZE {
317                    Ok(seq)
318                } else {
319                    Err(de::Error::invalid_length(
320                        crate::Vector::SIZE,
321                        &"fewer elements in the vector",
322                    ))
323                }
324            }
325            Value::Table(t) => {
326                let _guard = RecursionGuard::new(&t, &self.visited, self.options.recursion_limit)
327                    .map_err(|err| Error::DeserializeError(err.to_string()))?;
328
329                let len = self.len.unwrap_or_else(|| t.raw_len());
330                let mut deserializer = SeqDeserializer {
331                    seq: t.sequence_values().with_len(len),
332                    options: self.options,
333                    visited: self.visited,
334                };
335                let seq = visitor.visit_seq(&mut deserializer)?;
336                if deserializer.seq.next().is_none() {
337                    Ok(seq)
338                } else {
339                    Err(de::Error::invalid_length(len, &"fewer elements in the table"))
340                }
341            }
342            Value::UserData(ud) if ud.is_serializable() => {
343                serde_userdata(ud, |value| value.deserialize_seq(visitor))
344            }
345            value => Err(de::Error::invalid_type(
346                de::Unexpected::Other(value.type_name()),
347                &"table",
348            )),
349        }
350    }
351
352    #[inline]
353    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
354    where
355        V: de::Visitor<'de>,
356    {
357        self.deserialize_seq(visitor)
358    }
359
360    #[inline]
361    fn deserialize_tuple_struct<V>(self, _name: &'static str, _len: usize, visitor: V) -> Result<V::Value>
362    where
363        V: de::Visitor<'de>,
364    {
365        self.deserialize_seq(visitor)
366    }
367
368    #[inline]
369    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
370    where
371        V: de::Visitor<'de>,
372    {
373        match self.value {
374            Value::Table(t) => {
375                let _guard = RecursionGuard::new(&t, &self.visited, self.options.recursion_limit)
376                    .map_err(|err| Error::DeserializeError(err.to_string()))?;
377
378                let mut deserializer = MapDeserializer {
379                    pairs: MapPairs::new(&t, self.options.sort_keys)?,
380                    value: None,
381                    options: self.options,
382                    visited: self.visited,
383                    processed: 0,
384                };
385                let map = visitor.visit_map(&mut deserializer)?;
386                let count = deserializer.pairs.count();
387                if count == 0 {
388                    Ok(map)
389                } else {
390                    Err(de::Error::invalid_length(
391                        deserializer.processed + count,
392                        &"fewer elements in the table",
393                    ))
394                }
395            }
396            Value::UserData(ud) if ud.is_serializable() => {
397                serde_userdata(ud, |value| value.deserialize_map(visitor))
398            }
399            value => Err(de::Error::invalid_type(
400                de::Unexpected::Other(value.type_name()),
401                &"table",
402            )),
403        }
404    }
405
406    #[inline]
407    fn deserialize_struct<V>(
408        self,
409        _name: &'static str,
410        _fields: &'static [&'static str],
411        visitor: V,
412    ) -> Result<V::Value>
413    where
414        V: de::Visitor<'de>,
415    {
416        self.deserialize_map(visitor)
417    }
418
419    #[inline]
420    fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
421    where
422        V: de::Visitor<'de>,
423    {
424        match self.value {
425            Value::UserData(ud) if ud.is_serializable() => {
426                serde_userdata(ud, |value| value.deserialize_newtype_struct(name, visitor))
427            }
428            _ => visitor.visit_newtype_struct(self),
429        }
430    }
431
432    #[inline]
433    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
434    where
435        V: de::Visitor<'de>,
436    {
437        match self.value {
438            Value::LightUserData(ud) if ud.0.is_null() => visitor.visit_unit(),
439            _ => self.deserialize_any(visitor),
440        }
441    }
442
443    #[inline]
444    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
445    where
446        V: de::Visitor<'de>,
447    {
448        match self.value {
449            Value::LightUserData(ud) if ud.0.is_null() => visitor.visit_unit(),
450            _ => self.deserialize_any(visitor),
451        }
452    }
453
454    serde::forward_to_deserialize_any! {
455        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes
456        byte_buf identifier ignored_any
457    }
458}
459
460struct SeqDeserializer<'a> {
461    seq: TableSequence<'a, Value>,
462    options: Options,
463    visited: Rc<RefCell<FxHashSet<*const c_void>>>,
464}
465
466impl<'de> de::SeqAccess<'de> for SeqDeserializer<'_> {
467    type Error = Error;
468
469    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
470    where
471        T: de::DeserializeSeed<'de>,
472    {
473        loop {
474            match self.seq.next() {
475                Some(value) => {
476                    let value = value?;
477                    let skip = check_value_for_skip(&value, self.options, &self.visited)
478                        .map_err(|err| Error::DeserializeError(err.to_string()))?;
479                    if skip {
480                        continue;
481                    }
482                    let visited = Rc::clone(&self.visited);
483                    let deserializer = Deserializer::from_parts(value, self.options, visited);
484                    return seed.deserialize(deserializer).map(Some);
485                }
486                None => return Ok(None),
487            }
488        }
489    }
490
491    fn size_hint(&self) -> Option<usize> {
492        match self.seq.size_hint() {
493            (lower, Some(upper)) if lower == upper => Some(upper),
494            _ => None,
495        }
496    }
497}
498
499#[cfg(feature = "luau")]
500struct VecDeserializer {
501    vec: crate::Vector,
502    next: usize,
503    options: Options,
504    visited: Rc<RefCell<FxHashSet<*const c_void>>>,
505}
506
507#[cfg(feature = "luau")]
508impl<'de> de::SeqAccess<'de> for VecDeserializer {
509    type Error = Error;
510
511    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
512    where
513        T: de::DeserializeSeed<'de>,
514    {
515        match self.vec.0.get(self.next) {
516            Some(&n) => {
517                self.next += 1;
518                let visited = Rc::clone(&self.visited);
519                let deserializer = Deserializer::from_parts(Value::Number(n as _), self.options, visited);
520                seed.deserialize(deserializer).map(Some)
521            }
522            None => Ok(None),
523        }
524    }
525
526    fn size_hint(&self) -> Option<usize> {
527        Some(crate::Vector::SIZE)
528    }
529}
530
531pub(crate) enum MapPairs<'a> {
532    Iter(TablePairs<'a, Value, Value>),
533    Vec(Vec<(Value, Value)>),
534}
535
536impl<'a> MapPairs<'a> {
537    pub(crate) fn new(t: &'a Table, sort_keys: bool) -> Result<Self> {
538        if sort_keys {
539            let mut pairs = t.collect_pairs()?;
540            pairs.sort_by(|(a, _), (b, _)| b.sort_cmp(a)); // reverse order as we pop values from the end
541            Ok(MapPairs::Vec(pairs))
542        } else {
543            Ok(MapPairs::Iter(t.pairs::<Value, Value>()))
544        }
545    }
546
547    pub(crate) fn count(self) -> usize {
548        match self {
549            MapPairs::Iter(iter) => iter.count(),
550            MapPairs::Vec(vec) => vec.len(),
551        }
552    }
553
554    pub(crate) fn size_hint(&self) -> (usize, Option<usize>) {
555        match self {
556            MapPairs::Iter(iter) => iter.size_hint(),
557            MapPairs::Vec(vec) => (vec.len(), Some(vec.len())),
558        }
559    }
560}
561
562impl Iterator for MapPairs<'_> {
563    type Item = Result<(Value, Value)>;
564
565    fn next(&mut self) -> Option<Self::Item> {
566        match self {
567            MapPairs::Iter(iter) => iter.next(),
568            MapPairs::Vec(vec) => vec.pop().map(Ok),
569        }
570    }
571}
572
573struct MapDeserializer<'a> {
574    pairs: MapPairs<'a>,
575    value: Option<Value>,
576    options: Options,
577    visited: Rc<RefCell<FxHashSet<*const c_void>>>,
578    processed: usize,
579}
580
581impl MapDeserializer<'_> {
582    fn next_key_deserializer(&mut self) -> Result<Option<Deserializer>> {
583        loop {
584            match self.pairs.next() {
585                Some(item) => {
586                    let (key, value) = item?;
587                    let skip_key = check_key_for_skip(&key, self.options, &self.visited)
588                        .map_err(|err| Error::DeserializeError(err.to_string()))?;
589                    let skip_value = check_value_for_skip(&value, self.options, &self.visited)
590                        .map_err(|err| Error::DeserializeError(err.to_string()))?;
591                    if skip_key || skip_value {
592                        continue;
593                    }
594                    self.processed += 1;
595                    self.value = Some(value);
596                    let visited = Rc::clone(&self.visited);
597                    let key_de = Deserializer::from_parts(key, self.options, visited);
598                    return Ok(Some(key_de));
599                }
600                None => return Ok(None),
601            }
602        }
603    }
604
605    fn next_value_deserializer(&mut self) -> Result<Deserializer> {
606        match self.value.take() {
607            Some(value) => {
608                let visited = Rc::clone(&self.visited);
609                Ok(Deserializer::from_parts(value, self.options, visited))
610            }
611            None => Err(de::Error::custom("value is missing")),
612        }
613    }
614}
615
616impl<'de> de::MapAccess<'de> for MapDeserializer<'_> {
617    type Error = Error;
618
619    fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
620    where
621        T: de::DeserializeSeed<'de>,
622    {
623        match self.next_key_deserializer() {
624            Ok(Some(key_de)) => seed.deserialize(key_de).map(Some),
625            Ok(None) => Ok(None),
626            Err(error) => Err(error),
627        }
628    }
629
630    fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value>
631    where
632        T: de::DeserializeSeed<'de>,
633    {
634        match self.next_value_deserializer() {
635            Ok(value_de) => seed.deserialize(value_de),
636            Err(error) => Err(error),
637        }
638    }
639
640    fn size_hint(&self) -> Option<usize> {
641        match self.pairs.size_hint() {
642            (lower, Some(upper)) if lower == upper => Some(upper),
643            _ => None,
644        }
645    }
646}
647
648struct EnumDeserializer {
649    variant: String,
650    value: Option<Value>,
651    options: Options,
652    visited: Rc<RefCell<FxHashSet<*const c_void>>>,
653}
654
655impl<'de> de::EnumAccess<'de> for EnumDeserializer {
656    type Error = Error;
657    type Variant = VariantDeserializer;
658
659    fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant)>
660    where
661        T: de::DeserializeSeed<'de>,
662    {
663        let variant = self.variant.into_deserializer();
664        let variant_access = VariantDeserializer {
665            value: self.value,
666            options: self.options,
667            visited: self.visited,
668        };
669        seed.deserialize(variant).map(|v| (v, variant_access))
670    }
671}
672
673struct VariantDeserializer {
674    value: Option<Value>,
675    options: Options,
676    visited: Rc<RefCell<FxHashSet<*const c_void>>>,
677}
678
679impl<'de> de::VariantAccess<'de> for VariantDeserializer {
680    type Error = Error;
681
682    fn unit_variant(self) -> Result<()> {
683        match self.value {
684            Some(_) => Err(de::Error::invalid_type(
685                de::Unexpected::NewtypeVariant,
686                &"unit variant",
687            )),
688            None => Ok(()),
689        }
690    }
691
692    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
693    where
694        T: de::DeserializeSeed<'de>,
695    {
696        match self.value {
697            Some(value) => seed.deserialize(Deserializer::from_parts(value, self.options, self.visited)),
698            None => Err(de::Error::invalid_type(
699                de::Unexpected::UnitVariant,
700                &"newtype variant",
701            )),
702        }
703    }
704
705    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
706    where
707        V: de::Visitor<'de>,
708    {
709        match self.value {
710            Some(value) => serde::Deserializer::deserialize_seq(
711                Deserializer::from_parts(value, self.options, self.visited),
712                visitor,
713            ),
714            None => Err(de::Error::invalid_type(
715                de::Unexpected::UnitVariant,
716                &"tuple variant",
717            )),
718        }
719    }
720
721    fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
722    where
723        V: de::Visitor<'de>,
724    {
725        match self.value {
726            Some(value) => serde::Deserializer::deserialize_map(
727                Deserializer::from_parts(value, self.options, self.visited),
728                visitor,
729            ),
730            None => Err(de::Error::invalid_type(
731                de::Unexpected::UnitVariant,
732                &"struct variant",
733            )),
734        }
735    }
736}
737
738// Adds `ptr` to the `visited` map and removes on drop
739// Used to track recursive tables but allow to traverse same tables multiple times
740pub(crate) struct RecursionGuard {
741    ptr: *const c_void,
742    visited: Rc<RefCell<FxHashSet<*const c_void>>>,
743}
744
745impl RecursionGuard {
746    #[inline]
747    pub(crate) fn new(
748        table: &Table,
749        visited: &Rc<RefCell<FxHashSet<*const c_void>>>,
750        limit: usize,
751    ) -> StdResult<Self, &'static str> {
752        if visited.borrow().len() >= limit {
753            return Err("recursion limit exceeded");
754        }
755        let visited = Rc::clone(visited);
756        let ptr = table.to_pointer();
757        visited.borrow_mut().insert(ptr);
758        Ok(RecursionGuard { ptr, visited })
759    }
760}
761
762impl Drop for RecursionGuard {
763    fn drop(&mut self) {
764        self.visited.borrow_mut().remove(&self.ptr);
765    }
766}
767
768pub(crate) fn check_key_for_skip(
769    key: &Value,
770    options: Options,
771    visited: &RefCell<FxHashSet<*const c_void>>,
772) -> StdResult<bool, &'static str> {
773    if key.is_null() && !options.deny_unsupported_types {
774        return Ok(true);
775    }
776    check_value_for_skip(key, options, visited)
777}
778
779// Checks `options` and decides should we emit an error or skip next element
780pub(crate) fn check_value_for_skip(
781    value: &Value,
782    options: Options,
783    visited: &RefCell<FxHashSet<*const c_void>>,
784) -> StdResult<bool, &'static str> {
785    match value {
786        Value::Table(table) => {
787            let ptr = table.to_pointer();
788            if visited.borrow().contains(&ptr) {
789                if options.deny_recursive_tables {
790                    return Err("recursive table detected");
791                }
792                return Ok(true); // skip
793            }
794        }
795        Value::LightUserData(ud) if ud.0.is_null() => {}
796        Value::UserData(ud) if ud.is_serializable() => {}
797        Value::Function(_)
798        | Value::Thread(_)
799        | Value::UserData(_)
800        | Value::LightUserData(_)
801        | Value::Error(_)
802            if !options.deny_unsupported_types =>
803        {
804            return Ok(true); // skip
805        }
806        _ => {}
807    }
808    Ok(false) // do not skip
809}
810
811fn serde_userdata<V>(
812    ud: AnyUserData,
813    f: impl FnOnce(serde_value::Value) -> std::result::Result<V, serde_value::DeserializerError>,
814) -> Result<V> {
815    match serde_value::to_value(ud) {
816        Ok(value) => match f(value) {
817            Ok(r) => Ok(r),
818            Err(error) => Err(Error::DeserializeError(error.to_string())),
819        },
820        Err(error) => Err(Error::SerializeError(error.to_string())),
821    }
822}