Skip to main content

mlua/serde/
ser.rs

1//! Serialize a Rust data structure into Lua value.
2
3use serde::{Serialize, ser};
4
5use super::LuaSerdeExt;
6use crate::error::{Error, Result};
7use crate::state::Lua;
8use crate::table::Table;
9use crate::traits::IntoLua;
10use crate::value::Value;
11
12/// A struct for serializing Rust values into Lua values.
13#[derive(Debug)]
14pub struct Serializer<'a> {
15    lua: &'a Lua,
16    options: Options,
17}
18
19/// A struct with options to change default serializer behavior.
20#[derive(Debug, Clone, Copy)]
21#[non_exhaustive]
22pub struct Options {
23    /// Maximum nesting depth for containers and newtype wrappers.
24    ///
25    /// Increasing this limit may require a larger thread stack. Zero rejects all nesting.
26    ///
27    /// Default: **128**
28    pub recursion_limit: usize,
29
30    /// If true, sequence serialization to a Lua table will create table
31    /// with the [`array_metatable`] attached.
32    ///
33    /// Default: **true**
34    ///
35    /// [`array_metatable`]: crate::LuaSerdeExt::array_metatable
36    pub set_array_metatable: bool,
37
38    /// If true, serialize `None` (part of the `Option` type) to [`null`].
39    /// Otherwise it will be set to Lua [`Nil`].
40    ///
41    /// Default: **true**
42    ///
43    /// [`null`]: crate::LuaSerdeExt::null
44    /// [`Nil`]: crate::Value::Nil
45    pub serialize_none_to_null: bool,
46
47    /// If true, serialize `Unit` (type of `()` in Rust) and Unit structs to [`null`].
48    /// Otherwise it will be set to Lua [`Nil`].
49    ///
50    /// Default: **true**
51    ///
52    /// [`null`]: crate::LuaSerdeExt::null
53    /// [`Nil`]: crate::Value::Nil
54    pub serialize_unit_to_null: bool,
55
56    /// If true, serialize `serde_json::Number` with arbitrary_precision to a Lua number.
57    /// Otherwise it will be serialized as an object (what serde does).
58    ///
59    /// Default: **false**
60    pub detect_serde_json_arbitrary_precision: bool,
61}
62
63impl Default for Options {
64    fn default() -> Self {
65        const { Self::new() }
66    }
67}
68
69impl Options {
70    /// Returns a new instance of [`Options`] with default parameters.
71    pub const fn new() -> Self {
72        Options {
73            recursion_limit: super::DEFAULT_RECURSION_LIMIT,
74            set_array_metatable: true,
75            serialize_none_to_null: true,
76            serialize_unit_to_null: true,
77            detect_serde_json_arbitrary_precision: false,
78        }
79    }
80
81    /// Sets [`recursion_limit`] option.
82    ///
83    /// [`recursion_limit`]: #structfield.recursion_limit
84    #[must_use]
85    pub const fn recursion_limit(mut self, limit: usize) -> Self {
86        self.recursion_limit = limit;
87        self
88    }
89
90    /// Sets [`set_array_metatable`] option.
91    ///
92    /// [`set_array_metatable`]: #structfield.set_array_metatable
93    #[must_use]
94    pub const fn set_array_metatable(mut self, enabled: bool) -> Self {
95        self.set_array_metatable = enabled;
96        self
97    }
98
99    /// Sets [`serialize_none_to_null`] option.
100    ///
101    /// [`serialize_none_to_null`]: #structfield.serialize_none_to_null
102    #[must_use]
103    pub const fn serialize_none_to_null(mut self, enabled: bool) -> Self {
104        self.serialize_none_to_null = enabled;
105        self
106    }
107
108    /// Sets [`serialize_unit_to_null`] option.
109    ///
110    /// [`serialize_unit_to_null`]: #structfield.serialize_unit_to_null
111    #[must_use]
112    pub const fn serialize_unit_to_null(mut self, enabled: bool) -> Self {
113        self.serialize_unit_to_null = enabled;
114        self
115    }
116
117    /// Sets [`detect_serde_json_arbitrary_precision`] option.
118    ///
119    /// This option is used to serialize `serde_json::Number` with arbitrary precision to a Lua
120    /// number. Otherwise it will be serialized as an object (what serde does).
121    ///
122    /// This option is disabled by default.
123    ///
124    /// [`detect_serde_json_arbitrary_precision`]: #structfield.detect_serde_json_arbitrary_precision
125    #[must_use]
126    pub const fn detect_serde_json_arbitrary_precision(mut self, enabled: bool) -> Self {
127        self.detect_serde_json_arbitrary_precision = enabled;
128        self
129    }
130}
131
132impl<'a> Serializer<'a> {
133    /// Creates a new Lua Serializer with default options.
134    pub fn new(lua: &'a Lua) -> Self {
135        Self::new_with_options(lua, Options::default())
136    }
137
138    /// Creates a new Lua Serializer with custom options.
139    pub fn new_with_options(lua: &'a Lua, options: Options) -> Self {
140        Serializer { lua, options }
141    }
142
143    #[inline]
144    fn descend(mut self) -> Result<Self> {
145        self.options.recursion_limit = (self.options)
146            .recursion_limit
147            .checked_sub(1)
148            .ok_or_else(|| Error::SerializeError("recursion limit exceeded".into()))?;
149        Ok(self)
150    }
151}
152
153macro_rules! lua_serialize_number {
154    ($name:ident, $t:ty) => {
155        #[inline]
156        fn $name(self, value: $t) -> Result<Value> {
157            value.into_lua(self.lua)
158        }
159    };
160}
161
162impl<'a> ser::Serializer for Serializer<'a> {
163    type Ok = Value;
164    type Error = Error;
165
166    // Associated types for keeping track of additional state while serializing
167    // compound data structures like sequences and maps.
168    type SerializeSeq = SerializeSeq<'a>;
169    type SerializeTuple = SerializeSeq<'a>;
170    type SerializeTupleStruct = SerializeSeq<'a>;
171    type SerializeTupleVariant = SerializeTupleVariant<'a>;
172    type SerializeMap = SerializeMap<'a>;
173    type SerializeStruct = SerializeStruct<'a>;
174    type SerializeStructVariant = SerializeStructVariant<'a>;
175
176    #[inline]
177    fn serialize_bool(self, value: bool) -> Result<Value> {
178        Ok(Value::Boolean(value))
179    }
180
181    lua_serialize_number!(serialize_i8, i8);
182    lua_serialize_number!(serialize_u8, u8);
183    lua_serialize_number!(serialize_i16, i16);
184    lua_serialize_number!(serialize_u16, u16);
185    lua_serialize_number!(serialize_i32, i32);
186    lua_serialize_number!(serialize_u32, u32);
187    lua_serialize_number!(serialize_i64, i64);
188    lua_serialize_number!(serialize_u64, u64);
189    lua_serialize_number!(serialize_i128, i128);
190    lua_serialize_number!(serialize_u128, u128);
191
192    lua_serialize_number!(serialize_f32, f32);
193    lua_serialize_number!(serialize_f64, f64);
194
195    #[inline]
196    fn serialize_char(self, value: char) -> Result<Value> {
197        self.serialize_str(value.encode_utf8(&mut [0; 4]))
198    }
199
200    #[inline]
201    fn serialize_str(self, value: &str) -> Result<Value> {
202        self.lua.create_string(value).map(Value::String)
203    }
204
205    #[inline]
206    fn serialize_bytes(self, value: &[u8]) -> Result<Value> {
207        self.lua.create_string(value).map(Value::String)
208    }
209
210    #[inline]
211    fn serialize_none(self) -> Result<Value> {
212        if self.options.serialize_none_to_null {
213            Ok(self.lua.null())
214        } else {
215            Ok(Value::Nil)
216        }
217    }
218
219    #[inline]
220    fn serialize_some<T>(self, value: &T) -> Result<Value>
221    where
222        T: Serialize + ?Sized,
223    {
224        value.serialize(self.descend()?)
225    }
226
227    #[inline]
228    fn serialize_unit(self) -> Result<Value> {
229        if self.options.serialize_unit_to_null {
230            Ok(self.lua.null())
231        } else {
232            Ok(Value::Nil)
233        }
234    }
235
236    #[inline]
237    fn serialize_unit_struct(self, _name: &'static str) -> Result<Value> {
238        if self.options.serialize_unit_to_null {
239            Ok(self.lua.null())
240        } else {
241            Ok(Value::Nil)
242        }
243    }
244
245    #[inline]
246    fn serialize_unit_variant(
247        self,
248        _name: &'static str,
249        _variant_index: u32,
250        variant: &'static str,
251    ) -> Result<Value> {
252        self.serialize_str(variant)
253    }
254
255    #[inline]
256    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Value>
257    where
258        T: Serialize + ?Sized,
259    {
260        value.serialize(self.descend()?)
261    }
262
263    #[inline]
264    fn serialize_newtype_variant<T>(
265        mut self,
266        _name: &'static str,
267        _variant_index: u32,
268        variant: &'static str,
269        value: &T,
270    ) -> Result<Value>
271    where
272        T: Serialize + ?Sized,
273    {
274        self = self.descend()?;
275        let variant = self.lua.create_string(variant)?;
276        let value = self.lua.to_value_with(value, self.options)?;
277        let table = (self.lua).create_table_with_capacity(0, usize::from(!value.is_nil()))?;
278        table.raw_set(variant, value)?;
279        Ok(Value::Table(table))
280    }
281
282    #[inline]
283    fn serialize_seq(mut self, len: Option<usize>) -> Result<Self::SerializeSeq> {
284        self = self.descend()?;
285        let table = self.lua.create_table_with_capacity(len.unwrap_or(0), 0)?;
286        if self.options.set_array_metatable {
287            let lua = self.lua.lock();
288            unsafe {
289                super::push_array_metatable(lua.ref_thread());
290                ffi::lua_setmetatable(lua.ref_thread(), table.0.index);
291            }
292        }
293        Ok(SerializeSeq::new(self.lua, table, self.options))
294    }
295
296    #[inline]
297    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
298        self.serialize_seq(Some(len))
299    }
300
301    #[inline]
302    fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeTupleStruct> {
303        #[cfg(feature = "luau")]
304        if name == "Vector" && len == crate::Vector::SIZE {
305            let this = self.descend()?;
306            return Ok(SerializeSeq::new_vector(this.lua, this.options));
307        }
308        _ = name;
309        self.serialize_seq(Some(len))
310    }
311
312    #[inline]
313    fn serialize_tuple_variant(
314        mut self,
315        _name: &'static str,
316        _variant_index: u32,
317        variant: &'static str,
318        len: usize,
319    ) -> Result<Self::SerializeTupleVariant> {
320        self = self.descend()?;
321        let capacity = if self.options.serialize_none_to_null && self.options.serialize_unit_to_null {
322            len
323        } else {
324            0
325        };
326        Ok(SerializeTupleVariant {
327            lua: self.lua,
328            variant,
329            table: self.lua.create_table_with_capacity(capacity, 0)?,
330            options: self.options,
331        })
332    }
333
334    #[inline]
335    fn serialize_map(mut self, len: Option<usize>) -> Result<Self::SerializeMap> {
336        self = self.descend()?;
337        Ok(SerializeMap {
338            lua: self.lua,
339            key: None,
340            table: self.lua.create_table_with_capacity(0, len.unwrap_or(0))?,
341            options: self.options,
342        })
343    }
344
345    #[inline]
346    fn serialize_struct(mut self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
347        self = self.descend()?;
348        if self.options.detect_serde_json_arbitrary_precision
349            && name == "$serde_json::private::Number"
350            && len == 1
351        {
352            return Ok(SerializeStruct {
353                lua: self.lua,
354                inner: None,
355                options: self.options,
356            });
357        }
358
359        Ok(SerializeStruct {
360            lua: self.lua,
361            inner: Some(Value::Table(self.lua.create_table_with_capacity(0, len)?)),
362            options: self.options,
363        })
364    }
365
366    #[inline]
367    fn serialize_struct_variant(
368        mut self,
369        _name: &'static str,
370        _variant_index: u32,
371        variant: &'static str,
372        len: usize,
373    ) -> Result<Self::SerializeStructVariant> {
374        self = self.descend()?;
375        Ok(SerializeStructVariant {
376            lua: self.lua,
377            variant,
378            table: self.lua.create_table_with_capacity(0, len)?,
379            options: self.options,
380        })
381    }
382}
383
384#[doc(hidden)]
385pub struct SerializeSeq<'a> {
386    lua: &'a Lua,
387    #[cfg(feature = "luau")]
388    vector: Option<crate::Vector>,
389    table: Option<Table>,
390    next: usize,
391    options: Options,
392}
393
394impl<'a> SerializeSeq<'a> {
395    fn new(lua: &'a Lua, table: Table, options: Options) -> Self {
396        Self {
397            lua,
398            #[cfg(feature = "luau")]
399            vector: None,
400            table: Some(table),
401            next: 0,
402            options,
403        }
404    }
405
406    #[cfg(feature = "luau")]
407    const fn new_vector(lua: &'a Lua, options: Options) -> Self {
408        Self {
409            lua,
410            vector: Some(crate::Vector::zero()),
411            table: None,
412            next: 0,
413            options,
414        }
415    }
416}
417
418impl ser::SerializeSeq for SerializeSeq<'_> {
419    type Ok = Value;
420    type Error = Error;
421
422    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
423    where
424        T: Serialize + ?Sized,
425    {
426        let value = self.lua.to_value_with(value, self.options)?;
427        let table = self.table.as_ref().unwrap();
428        table.raw_seti(self.next + 1, value)?;
429        self.next += 1;
430        Ok(())
431    }
432
433    fn end(self) -> Result<Value> {
434        Ok(Value::Table(self.table.unwrap()))
435    }
436}
437
438impl ser::SerializeTuple for SerializeSeq<'_> {
439    type Ok = Value;
440    type Error = Error;
441
442    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
443    where
444        T: Serialize + ?Sized,
445    {
446        ser::SerializeSeq::serialize_element(self, value)
447    }
448
449    fn end(self) -> Result<Value> {
450        ser::SerializeSeq::end(self)
451    }
452}
453
454impl ser::SerializeTupleStruct for SerializeSeq<'_> {
455    type Ok = Value;
456    type Error = Error;
457
458    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
459    where
460        T: Serialize + ?Sized,
461    {
462        #[cfg(feature = "luau")]
463        if let Some(vector) = self.vector.as_mut() {
464            let value = self.lua.to_value_with(value, self.options)?;
465            let value = self.lua.unpack(value)?;
466            vector.0[self.next] = value;
467            self.next += 1;
468            return Ok(());
469        }
470        ser::SerializeSeq::serialize_element(self, value)
471    }
472
473    fn end(self) -> Result<Value> {
474        #[cfg(feature = "luau")]
475        if let Some(vector) = self.vector {
476            return Ok(Value::Vector(vector));
477        }
478        ser::SerializeSeq::end(self)
479    }
480}
481
482#[doc(hidden)]
483pub struct SerializeTupleVariant<'a> {
484    lua: &'a Lua,
485    variant: &'static str,
486    table: Table,
487    options: Options,
488}
489
490impl ser::SerializeTupleVariant for SerializeTupleVariant<'_> {
491    type Ok = Value;
492    type Error = Error;
493
494    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
495    where
496        T: Serialize + ?Sized,
497    {
498        self.table.raw_push(self.lua.to_value_with(value, self.options)?)
499    }
500
501    fn end(self) -> Result<Value> {
502        let table = self.lua.create_table_with_capacity(0, 1)?;
503        table.raw_set(self.variant, self.table)?;
504        Ok(Value::Table(table))
505    }
506}
507
508#[doc(hidden)]
509pub struct SerializeMap<'a> {
510    lua: &'a Lua,
511    table: Table,
512    key: Option<Value>,
513    options: Options,
514}
515
516impl ser::SerializeMap for SerializeMap<'_> {
517    type Ok = Value;
518    type Error = Error;
519
520    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
521    where
522        T: Serialize + ?Sized,
523    {
524        self.key = Some(self.lua.to_value_with(key, self.options)?);
525        Ok(())
526    }
527
528    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
529    where
530        T: Serialize + ?Sized,
531    {
532        let key = mlua_expect!(self.key.take(), "serialize_value called before serialize_key");
533        let value = self.lua.to_value_with(value, self.options)?;
534        self.table.raw_set(key, value)
535    }
536
537    fn end(self) -> Result<Value> {
538        Ok(Value::Table(self.table))
539    }
540}
541
542#[doc(hidden)]
543pub struct SerializeStruct<'a> {
544    lua: &'a Lua,
545    inner: Option<Value>,
546    options: Options,
547}
548
549impl ser::SerializeStruct for SerializeStruct<'_> {
550    type Ok = Value;
551    type Error = Error;
552
553    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
554    where
555        T: Serialize + ?Sized,
556    {
557        match self.inner {
558            Some(Value::Table(ref table)) => {
559                table.raw_set(key, self.lua.to_value_with(value, self.options)?)?;
560            }
561            None if self.options.detect_serde_json_arbitrary_precision => {
562                // A special case for `serde_json::Number` with arbitrary precision.
563                assert_eq!(key, "$serde_json::private::Number");
564                self.inner = Some(self.lua.to_value_with(value, self.options)?);
565            }
566            _ => unreachable!(),
567        }
568        Ok(())
569    }
570
571    fn end(self) -> Result<Value> {
572        match self.inner {
573            Some(table @ Value::Table(_)) => Ok(table),
574            Some(value @ Value::String(_)) if self.options.detect_serde_json_arbitrary_precision => {
575                let number_s = value.to_string()?;
576                if number_s.contains(['.', 'e', 'E'])
577                    && let Ok(number) = number_s.parse().map(Value::Number)
578                {
579                    return Ok(number);
580                }
581                Ok(number_s
582                    .parse()
583                    .map(Value::Integer)
584                    .or_else(|_| number_s.parse().map(Value::Number))
585                    .unwrap_or(value))
586            }
587            _ => unreachable!(),
588        }
589    }
590}
591
592#[doc(hidden)]
593pub struct SerializeStructVariant<'a> {
594    lua: &'a Lua,
595    variant: &'static str,
596    table: Table,
597    options: Options,
598}
599
600impl ser::SerializeStructVariant for SerializeStructVariant<'_> {
601    type Ok = Value;
602    type Error = Error;
603
604    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
605    where
606        T: Serialize + ?Sized,
607    {
608        self.table
609            .raw_set(key, self.lua.to_value_with(value, self.options)?)?;
610        Ok(())
611    }
612
613    fn end(self) -> Result<Value> {
614        let table = self.lua.create_table_with_capacity(0, 1)?;
615        table.raw_set(self.variant, self.table)?;
616        Ok(Value::Table(table))
617    }
618}