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