mlua_codemp_patch/serde/
ser.rs

1use serde::{ser, Serialize};
2
3use super::LuaSerdeExt;
4use crate::error::{Error, Result};
5use crate::state::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<'a> {
12    lua: &'a 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        const { 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
100    /// number. 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<'a> Serializer<'a> {
113    /// Creates a new Lua Serializer with default options.
114    pub fn new(lua: &'a 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: &'a 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> {
128            value.into_lua(self.lua)
129        }
130    };
131}
132
133impl<'a> ser::Serializer for Serializer<'a> {
134    type Ok = Value;
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<'a>;
140    type SerializeTuple = SerializeSeq<'a>;
141    type SerializeTupleStruct = SerializeSeq<'a>;
142    type SerializeTupleVariant = SerializeTupleVariant<'a>;
143    type SerializeMap = SerializeMap<'a>;
144    type SerializeStruct = SerializeStruct<'a>;
145    type SerializeStructVariant = SerializeStructVariant<'a>;
146
147    #[inline]
148    fn serialize_bool(self, value: bool) -> Result<Value> {
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> {
168        self.serialize_str(&value.to_string())
169    }
170
171    #[inline]
172    fn serialize_str(self, value: &str) -> Result<Value> {
173        self.lua.create_string(value).map(Value::String)
174    }
175
176    #[inline]
177    fn serialize_bytes(self, value: &[u8]) -> Result<Value> {
178        self.lua.create_string(value).map(Value::String)
179    }
180
181    #[inline]
182    fn serialize_none(self) -> Result<Value> {
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>
192    where
193        T: Serialize + ?Sized,
194    {
195        value.serialize(self)
196    }
197
198    #[inline]
199    fn serialize_unit(self) -> Result<Value> {
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> {
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> {
223        self.serialize_str(variant)
224    }
225
226    #[inline]
227    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Value>
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>
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(self.lua, 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(self, name: &'static str, len: usize) -> Result<Self::SerializeTupleStruct> {
268        #[cfg(feature = "luau")]
269        if name == "Vector" && len == crate::types::Vector::SIZE {
270            return Ok(SerializeSeq::new_vector(self.lua, self.options));
271        }
272        _ = name;
273        self.serialize_seq(Some(len))
274    }
275
276    #[inline]
277    fn serialize_tuple_variant(
278        self,
279        _name: &'static str,
280        _variant_index: u32,
281        variant: &'static str,
282        _len: usize,
283    ) -> Result<Self::SerializeTupleVariant> {
284        Ok(SerializeTupleVariant {
285            lua: self.lua,
286            variant,
287            table: self.lua.create_table()?,
288            options: self.options,
289        })
290    }
291
292    #[inline]
293    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
294        Ok(SerializeMap {
295            lua: self.lua,
296            key: None,
297            table: self.lua.create_table_with_capacity(0, len.unwrap_or(0))?,
298            options: self.options,
299        })
300    }
301
302    #[inline]
303    fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
304        if self.options.detect_serde_json_arbitrary_precision
305            && name == "$serde_json::private::Number"
306            && len == 1
307        {
308            return Ok(SerializeStruct {
309                lua: self.lua,
310                inner: None,
311                options: self.options,
312            });
313        }
314
315        Ok(SerializeStruct {
316            lua: self.lua,
317            inner: Some(Value::Table(self.lua.create_table_with_capacity(0, len)?)),
318            options: self.options,
319        })
320    }
321
322    #[inline]
323    fn serialize_struct_variant(
324        self,
325        _name: &'static str,
326        _variant_index: u32,
327        variant: &'static str,
328        len: usize,
329    ) -> Result<Self::SerializeStructVariant> {
330        Ok(SerializeStructVariant {
331            lua: self.lua,
332            variant,
333            table: self.lua.create_table_with_capacity(0, len)?,
334            options: self.options,
335        })
336    }
337}
338
339#[doc(hidden)]
340pub struct SerializeSeq<'a> {
341    lua: &'a Lua,
342    #[cfg(feature = "luau")]
343    vector: Option<crate::types::Vector>,
344    table: Option<Table>,
345    next: usize,
346    options: Options,
347}
348
349impl<'a> SerializeSeq<'a> {
350    fn new(lua: &'a Lua, table: Table, options: Options) -> Self {
351        Self {
352            lua,
353            #[cfg(feature = "luau")]
354            vector: None,
355            table: Some(table),
356            next: 0,
357            options,
358        }
359    }
360
361    #[cfg(feature = "luau")]
362    const fn new_vector(lua: &'a Lua, options: Options) -> Self {
363        Self {
364            lua,
365            vector: Some(crate::types::Vector::zero()),
366            table: None,
367            next: 0,
368            options,
369        }
370    }
371}
372
373impl ser::SerializeSeq for SerializeSeq<'_> {
374    type Ok = Value;
375    type Error = Error;
376
377    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
378    where
379        T: Serialize + ?Sized,
380    {
381        let value = self.lua.to_value_with(value, self.options)?;
382        let table = self.table.as_ref().unwrap();
383        table.raw_seti(self.next + 1, value)?;
384        self.next += 1;
385        Ok(())
386    }
387
388    fn end(self) -> Result<Value> {
389        Ok(Value::Table(self.table.unwrap()))
390    }
391}
392
393impl ser::SerializeTuple for SerializeSeq<'_> {
394    type Ok = Value;
395    type Error = Error;
396
397    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
398    where
399        T: Serialize + ?Sized,
400    {
401        ser::SerializeSeq::serialize_element(self, value)
402    }
403
404    fn end(self) -> Result<Value> {
405        ser::SerializeSeq::end(self)
406    }
407}
408
409impl ser::SerializeTupleStruct for SerializeSeq<'_> {
410    type Ok = Value;
411    type Error = Error;
412
413    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
414    where
415        T: Serialize + ?Sized,
416    {
417        #[cfg(feature = "luau")]
418        if let Some(vector) = self.vector.as_mut() {
419            let value = self.lua.to_value_with(value, self.options)?;
420            let value = self.lua.unpack(value)?;
421            vector.0[self.next] = value;
422            self.next += 1;
423            return Ok(());
424        }
425        ser::SerializeSeq::serialize_element(self, value)
426    }
427
428    fn end(self) -> Result<Value> {
429        #[cfg(feature = "luau")]
430        if let Some(vector) = self.vector {
431            return Ok(Value::Vector(vector));
432        }
433        ser::SerializeSeq::end(self)
434    }
435}
436
437#[doc(hidden)]
438pub struct SerializeTupleVariant<'a> {
439    lua: &'a Lua,
440    variant: &'static str,
441    table: Table,
442    options: Options,
443}
444
445impl ser::SerializeTupleVariant for SerializeTupleVariant<'_> {
446    type Ok = Value;
447    type Error = Error;
448
449    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
450    where
451        T: Serialize + ?Sized,
452    {
453        self.table.raw_push(self.lua.to_value_with(value, self.options)?)
454    }
455
456    fn end(self) -> Result<Value> {
457        let table = self.lua.create_table()?;
458        table.raw_set(self.variant, self.table)?;
459        Ok(Value::Table(table))
460    }
461}
462
463#[doc(hidden)]
464pub struct SerializeMap<'a> {
465    lua: &'a Lua,
466    table: Table,
467    key: Option<Value>,
468    options: Options,
469}
470
471impl ser::SerializeMap for SerializeMap<'_> {
472    type Ok = Value;
473    type Error = Error;
474
475    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
476    where
477        T: Serialize + ?Sized,
478    {
479        self.key = Some(self.lua.to_value_with(key, self.options)?);
480        Ok(())
481    }
482
483    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
484    where
485        T: Serialize + ?Sized,
486    {
487        let key = mlua_expect!(self.key.take(), "serialize_value called before serialize_key");
488        let value = self.lua.to_value_with(value, self.options)?;
489        self.table.raw_set(key, value)
490    }
491
492    fn end(self) -> Result<Value> {
493        Ok(Value::Table(self.table))
494    }
495}
496
497#[doc(hidden)]
498pub struct SerializeStruct<'a> {
499    lua: &'a Lua,
500    inner: Option<Value>,
501    options: Options,
502}
503
504impl ser::SerializeStruct for SerializeStruct<'_> {
505    type Ok = Value;
506    type Error = Error;
507
508    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
509    where
510        T: Serialize + ?Sized,
511    {
512        match self.inner {
513            Some(Value::Table(ref table)) => {
514                table.raw_set(key, self.lua.to_value_with(value, self.options)?)?;
515            }
516            None if self.options.detect_serde_json_arbitrary_precision => {
517                // A special case for `serde_json::Number` with arbitrary precision.
518                assert_eq!(key, "$serde_json::private::Number");
519                self.inner = Some(self.lua.to_value_with(value, self.options)?);
520            }
521            _ => unreachable!(),
522        }
523        Ok(())
524    }
525
526    fn end(self) -> Result<Value> {
527        match self.inner {
528            Some(table @ Value::Table(_)) => Ok(table),
529            Some(value) if self.options.detect_serde_json_arbitrary_precision => {
530                let number_s = value.as_str().expect("not an arbitrary precision number");
531                if number_s.contains(['.', 'e', 'E']) {
532                    if let Ok(number) = number_s.parse().map(Value::Number) {
533                        return Ok(number);
534                    }
535                }
536                Ok(number_s
537                    .parse()
538                    .map(Value::Integer)
539                    .or_else(|_| number_s.parse().map(Value::Number))
540                    .unwrap_or(value))
541            }
542            _ => unreachable!(),
543        }
544    }
545}
546
547#[doc(hidden)]
548pub struct SerializeStructVariant<'a> {
549    lua: &'a Lua,
550    variant: &'static str,
551    table: Table,
552    options: Options,
553}
554
555impl ser::SerializeStructVariant for SerializeStructVariant<'_> {
556    type Ok = Value;
557    type Error = Error;
558
559    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
560    where
561        T: Serialize + ?Sized,
562    {
563        self.table
564            .raw_set(key, self.lua.to_value_with(value, self.options)?)?;
565        Ok(())
566    }
567
568    fn end(self) -> Result<Value> {
569        let table = self.lua.create_table_with_capacity(0, 1)?;
570        table.raw_set(self.variant, self.table)?;
571        Ok(Value::Table(table))
572    }
573}