mlua/serde/
ser.rs

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