Skip to main content

mlua/serde/
mod.rs

1//! (De)Serialization support using serde.
2
3use std::os::raw::c_void;
4
5use serde::de::DeserializeOwned;
6use serde::ser::Serialize;
7
8use crate::error::Result;
9use crate::private::Sealed;
10use crate::state::Lua;
11use crate::table::Table;
12use crate::util::check_stack;
13use crate::value::Value;
14
15/// Trait for serializing/deserializing Lua values using Serde.
16#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
17pub trait LuaSerdeExt: Sealed {
18    /// A special value (lightuserdata) to encode/decode optional (none) values.
19    ///
20    /// # Example
21    ///
22    /// ```
23    /// use std::collections::HashMap;
24    /// use mlua::{Lua, Result, LuaSerdeExt};
25    ///
26    /// fn main() -> Result<()> {
27    ///     let lua = Lua::new();
28    ///     lua.globals().set("null", lua.null())?;
29    ///
30    ///     let val = lua.load(r#"{a = null}"#).eval()?;
31    ///     let map: HashMap<String, Option<String>> = lua.from_value(val)?;
32    ///     assert_eq!(map["a"], None);
33    ///
34    ///     Ok(())
35    /// }
36    /// ```
37    fn null(&self) -> Value;
38
39    /// A metatable attachable to a Lua table to systematically encode it as Array (instead of Map).
40    /// As a result, encoded Array will contain only sequence part of the table, with the same
41    /// length as the `#` operator on that table.
42    ///
43    /// # Example
44    ///
45    /// ```
46    /// use mlua::{Lua, Result, LuaSerdeExt};
47    /// use serde_json::Value as JsonValue;
48    ///
49    /// fn main() -> Result<()> {
50    ///     let lua = Lua::new();
51    ///     lua.globals().set("array_mt", lua.array_metatable())?;
52    ///
53    ///     // Encode as an empty array (no sequence part in the lua table)
54    ///     let val = lua.load("setmetatable({a = 5}, array_mt)").eval()?;
55    ///     let j: JsonValue = lua.from_value(val)?;
56    ///     assert_eq!(j.to_string(), "[]");
57    ///
58    ///     // Encode as object
59    ///     let val = lua.load("{a = 5}").eval()?;
60    ///     let j: JsonValue = lua.from_value(val)?;
61    ///     assert_eq!(j.to_string(), r#"{"a":5}"#);
62    ///
63    ///     Ok(())
64    /// }
65    /// ```
66    fn array_metatable(&self) -> Table;
67
68    /// Converts `T` into a [`Value`] instance.
69    ///
70    /// [`Value`]: crate::Value
71    ///
72    /// # Example
73    ///
74    /// ```
75    /// use mlua::{Lua, Result, LuaSerdeExt};
76    /// use serde::Serialize;
77    ///
78    /// #[derive(Serialize)]
79    /// struct User {
80    ///     name: String,
81    ///     age: u8,
82    /// }
83    ///
84    /// fn main() -> Result<()> {
85    ///     let lua = Lua::new();
86    ///     let u = User {
87    ///         name: "John Smith".into(),
88    ///         age: 20,
89    ///     };
90    ///     lua.globals().set("user", lua.to_value(&u)?)?;
91    ///     lua.load(r#"
92    ///         assert(user["name"] == "John Smith")
93    ///         assert(user["age"] == 20)
94    ///     "#).exec()
95    /// }
96    /// ```
97    fn to_value<T: Serialize + ?Sized>(&self, t: &T) -> Result<Value>;
98
99    /// Converts `T` into a [`Value`] instance with options.
100    ///
101    /// # Example
102    ///
103    /// ```
104    /// use mlua::serde::SerializeOptions;
105    /// use mlua::{Lua, Result, LuaSerdeExt};
106    ///
107    /// fn main() -> Result<()> {
108    ///     let lua = Lua::new();
109    ///     let v = vec![1, 2, 3];
110    ///     let options = SerializeOptions::new().set_array_metatable(false);
111    ///     lua.globals().set("v", lua.to_value_with(&v, options)?)?;
112    ///
113    ///     lua.load(r#"
114    ///         assert(#v == 3 and v[1] == 1 and v[2] == 2 and v[3] == 3)
115    ///         assert(getmetatable(v) == nil)
116    ///     "#).exec()
117    /// }
118    /// ```
119    fn to_value_with<T>(&self, t: &T, options: ser::Options) -> Result<Value>
120    where
121        T: Serialize + ?Sized;
122
123    /// Deserializes a [`Value`] into any serde deserializable object.
124    ///
125    /// # Example
126    ///
127    /// ```
128    /// use mlua::{Lua, Result, LuaSerdeExt};
129    /// use serde::Deserialize;
130    ///
131    /// #[derive(Deserialize, Debug, PartialEq)]
132    /// struct User {
133    ///     name: String,
134    ///     age: u8,
135    /// }
136    ///
137    /// fn main() -> Result<()> {
138    ///     let lua = Lua::new();
139    ///     let val = lua.load(r#"{name = "John Smith", age = 20}"#).eval()?;
140    ///     let u: User = lua.from_value(val)?;
141    ///
142    ///     assert_eq!(u, User { name: "John Smith".into(), age: 20 });
143    ///
144    ///     Ok(())
145    /// }
146    /// ```
147    #[allow(clippy::wrong_self_convention)]
148    fn from_value<T: DeserializeOwned>(&self, value: Value) -> Result<T>;
149
150    /// Deserializes a [`Value`] into any serde deserializable object with options.
151    ///
152    /// # Example
153    ///
154    /// ```
155    /// use mlua::serde::DeserializeOptions;
156    /// use mlua::{Lua, Result, LuaSerdeExt};
157    /// use serde::Deserialize;
158    ///
159    /// #[derive(Deserialize, Debug, PartialEq)]
160    /// struct User {
161    ///     name: String,
162    ///     age: u8,
163    /// }
164    ///
165    /// fn main() -> Result<()> {
166    ///     let lua = Lua::new();
167    ///     let val = lua.load(r#"{name = "John Smith", age = 20, f = function() end}"#).eval()?;
168    ///     let options = DeserializeOptions::new().deny_unsupported_types(false);
169    ///     let u: User = lua.from_value_with(val, options)?;
170    ///
171    ///     assert_eq!(u, User { name: "John Smith".into(), age: 20 });
172    ///
173    ///     Ok(())
174    /// }
175    /// ```
176    #[allow(clippy::wrong_self_convention)]
177    fn from_value_with<T: DeserializeOwned>(&self, value: Value, options: de::Options) -> Result<T>;
178}
179
180impl LuaSerdeExt for Lua {
181    fn null(&self) -> Value {
182        Value::NULL
183    }
184
185    fn array_metatable(&self) -> Table {
186        let lua = self.lock();
187        unsafe {
188            push_array_metatable(lua.ref_thread());
189            Table(lua.pop_ref_thread())
190        }
191    }
192
193    fn to_value<T>(&self, t: &T) -> Result<Value>
194    where
195        T: Serialize + ?Sized,
196    {
197        t.serialize(ser::Serializer::new(self))
198    }
199
200    fn to_value_with<T>(&self, t: &T, options: ser::Options) -> Result<Value>
201    where
202        T: Serialize + ?Sized,
203    {
204        t.serialize(ser::Serializer::new_with_options(self, options))
205    }
206
207    fn from_value<T>(&self, value: Value) -> Result<T>
208    where
209        T: DeserializeOwned,
210    {
211        T::deserialize(de::Deserializer::new(value))
212    }
213
214    fn from_value_with<T>(&self, value: Value, options: de::Options) -> Result<T>
215    where
216        T: DeserializeOwned,
217    {
218        T::deserialize(de::Deserializer::new_with_options(value, options))
219    }
220}
221
222// Uses 2 stack spaces and calls checkstack.
223pub(crate) unsafe fn init_metatables(state: *mut ffi::lua_State) -> Result<()> {
224    check_stack(state, 2)?;
225    protect_lua!(state, 0, 0, fn(state) {
226        ffi::lua_createtable(state, 0, 1);
227
228        ffi::lua_pushstring(state, cstr!("__metatable"));
229        ffi::lua_pushboolean(state, 0);
230        ffi::lua_rawset(state, -3);
231
232        let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *const c_void;
233        ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, array_metatable_key);
234    })
235}
236
237pub(crate) unsafe fn push_array_metatable(state: *mut ffi::lua_State) {
238    let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *const c_void;
239    ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, array_metatable_key);
240}
241
242static ARRAY_METATABLE_REGISTRY_KEY: u8 = 0;
243
244pub mod de;
245pub mod ser;
246
247pub use de::{Deserializer, Options as DeserializeOptions};
248pub use ser::{Options as SerializeOptions, Serializer};