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