Add encode_empty_tables_as_array serialize option.

This will change the behaviour of encoding empty Lua tables into array instead of map.
This commit is contained in:
Alex Orlenko
2025-04-26 17:53:56 +01:00
parent 3e87d3ea9b
commit d0ea428e23
4 changed files with 82 additions and 1 deletions
+18
View File
@@ -49,6 +49,11 @@ pub struct Options {
///
/// Default: **false**
pub sort_keys: bool,
/// If true, empty Lua tables will be encoded as array, instead of map.
///
/// Default: **false**
pub encode_empty_tables_as_array: bool,
}
impl Default for Options {
@@ -64,6 +69,7 @@ impl Options {
deny_unsupported_types: true,
deny_recursive_tables: true,
sort_keys: false,
encode_empty_tables_as_array: false,
}
}
@@ -93,6 +99,15 @@ impl Options {
self.sort_keys = enabled;
self
}
/// Sets [`encode_empty_tables_as_array`] option.
///
/// [`encode_empty_tables_as_array`]: #structfield.encode_empty_tables_as_array
#[must_use]
pub const fn encode_empty_tables_as_array(mut self, enabled: bool) -> Self {
self.encode_empty_tables_as_array = enabled;
self
}
}
impl Deserializer {
@@ -141,6 +156,9 @@ impl<'de> serde::Deserializer<'de> for Deserializer {
Err(_) => visitor.visit_bytes(&s.as_bytes()),
},
Value::Table(ref t) if t.raw_len() > 0 || t.is_array() => self.deserialize_seq(visitor),
Value::Table(ref t) if self.options.encode_empty_tables_as_array && t.is_empty() => {
self.deserialize_seq(visitor)
}
Value::Table(_) => self.deserialize_map(visitor),
Value::LightUserData(ud) if ud.0.is_null() => visitor.visit_none(),
Value::UserData(ud) if ud.is_serializable() => {
+4 -1
View File
@@ -1020,7 +1020,10 @@ impl Serialize for SerializableTable<'_> {
// Array
let len = self.table.raw_len();
if len > 0 || self.table.is_array() {
if len > 0
|| self.table.is_array()
|| (self.options.encode_empty_tables_as_array && self.table.is_empty())
{
let mut seq = serializer.serialize_seq(Some(len))?;
let mut serialize_err = None;
let res = self.table.for_each_value::<Value>(|value| {
+9
View File
@@ -700,6 +700,15 @@ impl<'a> SerializableValue<'a> {
self.options.sort_keys = enabled;
self
}
/// If true, empty Lua tables will be encoded as array, instead of map.
///
/// Default: **false**
#[must_use]
pub const fn encode_empty_tables_as_array(mut self, enabled: bool) -> Self {
self.options.encode_empty_tables_as_array = enabled;
self
}
}
#[cfg(feature = "serialize")]
+51
View File
@@ -249,6 +249,26 @@ fn test_serialize_same_table_twice() -> LuaResult<()> {
Ok(())
}
#[test]
fn test_serialize_empty_table() -> LuaResult<()> {
let lua = Lua::new();
let table = Value::Table(lua.create_table()?);
let json = serde_json::to_string(&table.to_serializable()).unwrap();
assert_eq!(json, "{}");
// Set the option to encode empty tables as array
let json = serde_json::to_string(&table.to_serializable().encode_empty_tables_as_array(true)).unwrap();
assert_eq!(json, "[]");
// Check hashmap table with this option
table.as_table().unwrap().set("hello", "world")?;
let json = serde_json::to_string(&table.to_serializable().encode_empty_tables_as_array(true)).unwrap();
assert_eq!(json, r#"{"hello":"world"}"#);
Ok(())
}
#[test]
fn test_to_value_struct() -> LuaResult<()> {
let lua = Lua::new();
@@ -667,6 +687,37 @@ fn test_from_value_userdata() -> Result<(), Box<dyn StdError>> {
Ok(())
}
#[test]
fn test_from_value_empty_table() -> Result<(), Box<dyn StdError>> {
let lua = Lua::new();
// By default we encode empty tables as objects
let t = lua.create_table()?;
let got = lua.from_value::<serde_json::Value>(Value::Table(t.clone()))?;
assert_eq!(got, serde_json::json!({}));
// Set the option to encode empty tables as array
let got = lua
.from_value_with::<serde_json::Value>(
Value::Table(t.clone()),
DeserializeOptions::new().encode_empty_tables_as_array(true),
)
.unwrap();
assert_eq!(got, serde_json::json!([]));
// Check hashmap table with this option
t.raw_set("hello", "world")?;
let got = lua
.from_value_with::<serde_json::Value>(
Value::Table(t),
DeserializeOptions::new().encode_empty_tables_as_array(true),
)
.unwrap();
assert_eq!(got, serde_json::json!({"hello": "world"}));
Ok(())
}
#[test]
fn test_from_value_sorted() -> Result<(), Box<dyn StdError>> {
let lua = Lua::new();