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