factorio_mlua/serde/
ser.rs

1use std::os::raw::c_int;
2
3use serde::{ser, Serialize};
4
5use super::LuaSerdeExt;
6use crate::error::{Error, Result};
7use crate::ffi;
8use crate::lua::Lua;
9use crate::string::String;
10use crate::table::Table;
11use crate::types::Integer;
12use crate::util::{check_stack, StackGuard};
13use crate::value::{ToLua, Value};
14
15/// A struct for serializing Rust values into Lua values.
16#[derive(Debug)]
17pub struct Serializer<'lua> {
18    lua: &'lua Lua,
19    options: Options,
20}
21
22/// A struct with options to change default serializer behavior.
23#[derive(Debug, Clone, Copy)]
24#[non_exhaustive]
25pub struct Options {
26    /// If true, sequence serialization to a Lua table will create table
27    /// with the [`array_metatable`] attached.
28    ///
29    /// Default: **true**
30    ///
31    /// [`array_metatable`]: crate::LuaSerdeExt::array_metatable
32    pub set_array_metatable: bool,
33
34    /// If true, serialize `None` (part of the `Option` type) to [`null`].
35    /// Otherwise it will be set to Lua [`Nil`].
36    ///
37    /// Default: **true**
38    ///
39    /// [`null`]: crate::LuaSerdeExt::null
40    /// [`Nil`]: crate::Value::Nil
41    pub serialize_none_to_null: bool,
42
43    /// If true, serialize `Unit` (type of `()` in Rust) and Unit structs to [`null`].
44    /// Otherwise it will be set to Lua [`Nil`].
45    ///
46    /// Default: **true**
47    ///
48    /// [`null`]: crate::LuaSerdeExt::null
49    /// [`Nil`]: crate::Value::Nil
50    pub serialize_unit_to_null: 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        }
67    }
68
69    /// Sets [`set_array_metatable`] option.
70    ///
71    /// [`set_array_metatable`]: #structfield.set_array_metatable
72    #[must_use]
73    pub const fn set_array_metatable(mut self, enabled: bool) -> Self {
74        self.set_array_metatable = enabled;
75        self
76    }
77
78    /// Sets [`serialize_none_to_null`] option.
79    ///
80    /// [`serialize_none_to_null`]: #structfield.serialize_none_to_null
81    #[must_use]
82    pub const fn serialize_none_to_null(mut self, enabled: bool) -> Self {
83        self.serialize_none_to_null = enabled;
84        self
85    }
86
87    /// Sets [`serialize_unit_to_null`] option.
88    ///
89    /// [`serialize_unit_to_null`]: #structfield.serialize_unit_to_null
90    #[must_use]
91    pub const fn serialize_unit_to_null(mut self, enabled: bool) -> Self {
92        self.serialize_unit_to_null = enabled;
93        self
94    }
95}
96
97impl<'lua> Serializer<'lua> {
98    /// Creates a new Lua Serializer with default options.
99    pub fn new(lua: &'lua Lua) -> Self {
100        Self::new_with_options(lua, Options::default())
101    }
102
103    /// Creates a new Lua Serializer with custom options.
104    pub fn new_with_options(lua: &'lua Lua, options: Options) -> Self {
105        Serializer { lua, options }
106    }
107}
108
109macro_rules! lua_serialize_number {
110    ($name:ident, $t:ty) => {
111        #[inline]
112        fn $name(self, value: $t) -> Result<Value<'lua>> {
113            value.to_lua(self.lua)
114        }
115    };
116}
117
118impl<'lua> ser::Serializer for Serializer<'lua> {
119    type Ok = Value<'lua>;
120    type Error = Error;
121
122    // Associated types for keeping track of additional state while serializing
123    // compound data structures like sequences and maps.
124    type SerializeSeq = SerializeVec<'lua>;
125    type SerializeTuple = SerializeVec<'lua>;
126    type SerializeTupleStruct = SerializeVec<'lua>;
127    type SerializeTupleVariant = SerializeTupleVariant<'lua>;
128    type SerializeMap = SerializeMap<'lua>;
129    type SerializeStruct = SerializeMap<'lua>;
130    type SerializeStructVariant = SerializeStructVariant<'lua>;
131
132    #[inline]
133    fn serialize_bool(self, value: bool) -> Result<Value<'lua>> {
134        Ok(Value::Boolean(value))
135    }
136
137    lua_serialize_number!(serialize_i8, i8);
138    lua_serialize_number!(serialize_u8, u8);
139    lua_serialize_number!(serialize_i16, i16);
140    lua_serialize_number!(serialize_u16, u16);
141    lua_serialize_number!(serialize_i32, i32);
142    lua_serialize_number!(serialize_u32, u32);
143    lua_serialize_number!(serialize_i64, i64);
144    lua_serialize_number!(serialize_u64, u64);
145    lua_serialize_number!(serialize_i128, i128);
146    lua_serialize_number!(serialize_u128, u128);
147
148    lua_serialize_number!(serialize_f32, f32);
149    lua_serialize_number!(serialize_f64, f64);
150
151    #[inline]
152    fn serialize_char(self, value: char) -> Result<Value<'lua>> {
153        self.serialize_str(&value.to_string())
154    }
155
156    #[inline]
157    fn serialize_str(self, value: &str) -> Result<Value<'lua>> {
158        self.lua.create_string(value).map(Value::String)
159    }
160
161    #[inline]
162    fn serialize_bytes(self, value: &[u8]) -> Result<Value<'lua>> {
163        self.lua.create_string(value).map(Value::String)
164    }
165
166    #[inline]
167    fn serialize_none(self) -> Result<Value<'lua>> {
168        if self.options.serialize_none_to_null {
169            Ok(self.lua.null())
170        } else {
171            Ok(Value::Nil)
172        }
173    }
174
175    #[inline]
176    fn serialize_some<T>(self, value: &T) -> Result<Value<'lua>>
177    where
178        T: Serialize + ?Sized,
179    {
180        value.serialize(self)
181    }
182
183    #[inline]
184    fn serialize_unit(self) -> Result<Value<'lua>> {
185        if self.options.serialize_unit_to_null {
186            Ok(self.lua.null())
187        } else {
188            Ok(Value::Nil)
189        }
190    }
191
192    #[inline]
193    fn serialize_unit_struct(self, _name: &'static str) -> Result<Value<'lua>> {
194        if self.options.serialize_unit_to_null {
195            Ok(self.lua.null())
196        } else {
197            Ok(Value::Nil)
198        }
199    }
200
201    #[inline]
202    fn serialize_unit_variant(
203        self,
204        _name: &'static str,
205        _variant_index: u32,
206        variant: &'static str,
207    ) -> Result<Value<'lua>> {
208        self.serialize_str(variant)
209    }
210
211    #[inline]
212    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Value<'lua>>
213    where
214        T: Serialize + ?Sized,
215    {
216        value.serialize(self)
217    }
218
219    #[inline]
220    fn serialize_newtype_variant<T>(
221        self,
222        _name: &'static str,
223        _variant_index: u32,
224        variant: &'static str,
225        value: &T,
226    ) -> Result<Value<'lua>>
227    where
228        T: Serialize + ?Sized,
229    {
230        let table = self.lua.create_table()?;
231        let variant = self.lua.create_string(variant)?;
232        let value = self.lua.to_value_with(value, self.options)?;
233        table.raw_set(variant, value)?;
234        Ok(Value::Table(table))
235    }
236
237    #[inline]
238    fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
239        let len = len.unwrap_or(0) as c_int;
240        let table = self.lua.create_table_with_capacity(len, 0)?;
241        if self.options.set_array_metatable {
242            table.set_metatable(Some(self.lua.array_metatable()));
243        }
244        let options = self.options;
245        Ok(SerializeVec { table, options })
246    }
247
248    #[inline]
249    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
250        self.serialize_seq(Some(len))
251    }
252
253    #[inline]
254    fn serialize_tuple_struct(
255        self,
256        _name: &'static str,
257        len: usize,
258    ) -> Result<Self::SerializeTupleStruct> {
259        self.serialize_seq(Some(len))
260    }
261
262    #[inline]
263    fn serialize_tuple_variant(
264        self,
265        _name: &'static str,
266        _variant_index: u32,
267        variant: &'static str,
268        _len: usize,
269    ) -> Result<Self::SerializeTupleVariant> {
270        Ok(SerializeTupleVariant {
271            name: self.lua.create_string(variant)?,
272            table: self.lua.create_table()?,
273            options: self.options,
274        })
275    }
276
277    #[inline]
278    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
279        let len = len.unwrap_or(0) as c_int;
280        Ok(SerializeMap {
281            key: None,
282            table: self.lua.create_table_with_capacity(0, len)?,
283            options: self.options,
284        })
285    }
286
287    #[inline]
288    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
289        self.serialize_map(Some(len))
290    }
291
292    #[inline]
293    fn serialize_struct_variant(
294        self,
295        _name: &'static str,
296        _variant_index: u32,
297        variant: &'static str,
298        len: usize,
299    ) -> Result<Self::SerializeStructVariant> {
300        Ok(SerializeStructVariant {
301            name: self.lua.create_string(variant)?,
302            table: self.lua.create_table_with_capacity(0, len as c_int)?,
303            options: self.options,
304        })
305    }
306}
307
308#[doc(hidden)]
309pub struct SerializeVec<'lua> {
310    table: Table<'lua>,
311    options: Options,
312}
313
314impl<'lua> ser::SerializeSeq for SerializeVec<'lua> {
315    type Ok = Value<'lua>;
316    type Error = Error;
317
318    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
319    where
320        T: Serialize + ?Sized,
321    {
322        let lua = self.table.0.lua;
323        let value = lua.to_value_with(value, self.options)?;
324        unsafe {
325            let _sg = StackGuard::new(lua.state);
326            check_stack(lua.state, 4)?;
327
328            lua.push_ref(&self.table.0);
329            lua.push_value(value)?;
330            if lua.unlikely_memory_error() {
331                let len = ffi::lua_rawlen(lua.state, -2) as Integer;
332                ffi::lua_rawseti(lua.state, -2, len + 1);
333                ffi::lua_pop(lua.state, 1);
334                Ok(())
335            } else {
336                protect_lua!(lua.state, 2, 0, fn(state) {
337                    let len = ffi::lua_rawlen(state, -2) as Integer;
338                    ffi::lua_rawseti(state, -2, len + 1);
339                })
340            }
341        }
342    }
343
344    fn end(self) -> Result<Value<'lua>> {
345        Ok(Value::Table(self.table))
346    }
347}
348
349impl<'lua> ser::SerializeTuple for SerializeVec<'lua> {
350    type Ok = Value<'lua>;
351    type Error = Error;
352
353    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
354    where
355        T: Serialize + ?Sized,
356    {
357        ser::SerializeSeq::serialize_element(self, value)
358    }
359
360    fn end(self) -> Result<Value<'lua>> {
361        ser::SerializeSeq::end(self)
362    }
363}
364
365impl<'lua> ser::SerializeTupleStruct for SerializeVec<'lua> {
366    type Ok = Value<'lua>;
367    type Error = Error;
368
369    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
370    where
371        T: Serialize + ?Sized,
372    {
373        ser::SerializeSeq::serialize_element(self, value)
374    }
375
376    fn end(self) -> Result<Value<'lua>> {
377        ser::SerializeSeq::end(self)
378    }
379}
380
381#[doc(hidden)]
382pub struct SerializeTupleVariant<'lua> {
383    name: String<'lua>,
384    table: Table<'lua>,
385    options: Options,
386}
387
388impl<'lua> ser::SerializeTupleVariant for SerializeTupleVariant<'lua> {
389    type Ok = Value<'lua>;
390    type Error = Error;
391
392    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
393    where
394        T: Serialize + ?Sized,
395    {
396        let lua = self.table.0.lua;
397        let idx = self.table.raw_len() + 1;
398        self.table
399            .raw_insert(idx, lua.to_value_with(value, self.options)?)
400    }
401
402    fn end(self) -> Result<Value<'lua>> {
403        let lua = self.table.0.lua;
404        let table = lua.create_table()?;
405        table.raw_set(self.name, self.table)?;
406        Ok(Value::Table(table))
407    }
408}
409
410#[doc(hidden)]
411pub struct SerializeMap<'lua> {
412    table: Table<'lua>,
413    key: Option<Value<'lua>>,
414    options: Options,
415}
416
417impl<'lua> ser::SerializeMap for SerializeMap<'lua> {
418    type Ok = Value<'lua>;
419    type Error = Error;
420
421    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
422    where
423        T: Serialize + ?Sized,
424    {
425        let lua = self.table.0.lua;
426        self.key = Some(lua.to_value_with(key, self.options)?);
427        Ok(())
428    }
429
430    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
431    where
432        T: Serialize + ?Sized,
433    {
434        let lua = self.table.0.lua;
435        let key = mlua_expect!(
436            self.key.take(),
437            "serialize_value called before serialize_key"
438        );
439        let value = lua.to_value_with(value, self.options)?;
440        self.table.raw_set(key, value)
441    }
442
443    fn end(self) -> Result<Value<'lua>> {
444        Ok(Value::Table(self.table))
445    }
446}
447
448impl<'lua> ser::SerializeStruct for SerializeMap<'lua> {
449    type Ok = Value<'lua>;
450    type Error = Error;
451
452    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
453    where
454        T: Serialize + ?Sized,
455    {
456        ser::SerializeMap::serialize_key(self, key)?;
457        ser::SerializeMap::serialize_value(self, value)
458    }
459
460    fn end(self) -> Result<Value<'lua>> {
461        ser::SerializeMap::end(self)
462    }
463}
464
465#[doc(hidden)]
466pub struct SerializeStructVariant<'lua> {
467    name: String<'lua>,
468    table: Table<'lua>,
469    options: Options,
470}
471
472impl<'lua> ser::SerializeStructVariant for SerializeStructVariant<'lua> {
473    type Ok = Value<'lua>;
474    type Error = Error;
475
476    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
477    where
478        T: Serialize + ?Sized,
479    {
480        let lua = self.table.0.lua;
481        self.table
482            .raw_set(key, lua.to_value_with(value, self.options)?)?;
483        Ok(())
484    }
485
486    fn end(self) -> Result<Value<'lua>> {
487        let lua = self.table.0.lua;
488        let table = lua.create_table()?;
489        table.raw_set(self.name, self.table)?;
490        Ok(Value::Table(table))
491    }
492}