Skip to content

Commit 3327dcb

Browse files
committed
Add null_as_nil option to json/yaml decode
1 parent 7f4db25 commit 3327dcb

File tree

4 files changed

+40
-5
lines changed

4 files changed

+40
-5
lines changed

src/json.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,18 @@ struct LuaJsonMapIter {
192192
///
193193
/// The optional `opts` table can contain:
194194
/// - `set_array_metatable` (boolean): If true, sets a metatable for arrays. Default is false.
195+
/// - `null_as_nil` (boolean): If true, `null`s will be represented as Lua `nil`. Default is false.
195196
pub fn decode(lua: &Lua, (data, opts): (StringOrBytes, Option<Table>)) -> Result<StdResult<Value, String>> {
196197
let opts = opts.as_ref();
197198
let mut options = SerializeOptions::new();
198-
if let Some(enabled) = opts.and_then(|t| t.get::<bool>("set_array_metatable").ok()) {
199+
if let Some(enabled) = opts.and_then(|t| t.raw_get::<bool>("set_array_metatable").ok()) {
199200
options = options.set_array_metatable(enabled);
200201
}
202+
if let Some(enabled) = opts.and_then(|t| t.raw_get::<bool>("null_as_nil").ok()) {
203+
options = options
204+
.serialize_unit_to_null(!enabled)
205+
.serialize_none_to_null(!enabled);
206+
}
201207

202208
let json: serde_json::Value = lua_try!(serde_json::from_slice(&data.as_bytes_deref()));
203209
Ok(Ok(lua.to_value_with(&json, options)?))
@@ -220,11 +226,11 @@ pub fn encode(value: Value, opts: Option<Table>) -> StdResult<String, String> {
220226
let mut value = value.to_serializable();
221227
let opts = opts.as_ref();
222228

223-
if opts.and_then(|t| t.get::<bool>("relaxed").ok()) == Some(true) {
229+
if opts.and_then(|t| t.raw_get::<bool>("relaxed").ok()) == Some(true) {
224230
value = value.deny_recursive_tables(false).deny_unsupported_types(false);
225231
}
226232

227-
if opts.and_then(|t| t.get::<bool>("pretty").ok()) == Some(true) {
233+
if opts.and_then(|t| t.raw_get::<bool>("pretty").ok()) == Some(true) {
228234
value = value.sort_keys(true);
229235
return serde_json::to_string_pretty(&value).map_err(|e| e.to_string());
230236
}

src/yaml.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,18 @@ struct LuaYamlMapIter {
198198
///
199199
/// The `opts` table can contain the following options:
200200
/// - `set_array_metatable` (boolean): If true, sets a metatable for arrays. Default is false.
201+
/// - `null_as_nil` (boolean): If true, `null`s will be represented as Lua `nil`. Default is false.
201202
pub fn decode(lua: &Lua, (data, opts): (StringOrBytes, Option<Table>)) -> Result<StdResult<Value, String>> {
202203
let opts = opts.as_ref();
203204
let mut options = SerializeOptions::new();
204-
if let Some(enabled) = opts.and_then(|t| t.get::<bool>("set_array_metatable").ok()) {
205+
if let Some(enabled) = opts.and_then(|t| t.raw_get::<bool>("set_array_metatable").ok()) {
205206
options = options.set_array_metatable(enabled);
206207
}
208+
if let Some(enabled) = opts.and_then(|t| t.raw_get::<bool>("null_as_nil").ok()) {
209+
options = options
210+
.serialize_unit_to_null(!enabled)
211+
.serialize_none_to_null(!enabled);
212+
}
207213

208214
let mut yaml: serde_yaml::Value = lua_try!(serde_yaml::from_slice(&data.as_bytes_deref()));
209215
lua_try!(yaml.apply_merge());
@@ -227,7 +233,7 @@ pub fn encode(value: Value, opts: Option<Table>) -> StdResult<String, String> {
227233
let opts = opts.as_ref();
228234
let mut value = value.to_serializable();
229235

230-
if opts.and_then(|t| t.get::<bool>("relaxed").ok()) == Some(true) {
236+
if opts.and_then(|t| t.raw_get::<bool>("relaxed").ok()) == Some(true) {
231237
value = value.deny_recursive_tables(false).deny_unsupported_types(false);
232238
}
233239

tests/lua/json_tests.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ testing:test("decode", function(t)
3737
t.assert_eq(err, nil)
3838
t.assert_eq(type(value), "table", "value is not a table")
3939
t.assert_eq(getmetatable(value), nil, "array metatable is set")
40+
41+
-- Test null_as_nil option
42+
value = json.decode('{"a": null, "b": 1}')
43+
t.assert_eq(type(value.a), "userdata", "null should be userdata by default")
44+
t.assert_eq(value.b, 1)
45+
46+
value = json.decode('{"a": null, "b": 1}', { null_as_nil = true })
47+
t.assert_eq(value.a, nil, "null should be nil when null_as_nil is true")
48+
t.assert_eq(value.b, 1)
4049
end)
4150

4251
-- Test decode to native object

tests/lua/yaml_tests.lua

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ testing:test("decode", function(t)
3535
t.assert_eq(err, nil)
3636
t.assert_eq(value.key, "value")
3737
t.assert_eq(value.number, 42)
38+
39+
-- Test null_as_nil option
40+
value = yaml.decode("a: null\nb: 1")
41+
t.assert_eq(type(value.a), "userdata", "null should be userdata by default")
42+
t.assert_eq(value.b, 1)
43+
44+
value = yaml.decode("a: null\nb: 1", { null_as_nil = true })
45+
t.assert_eq(value.a, nil, "null should be nil when null_as_nil is true")
46+
t.assert_eq(value.b, 1)
47+
48+
-- Test with alternative YAML null representations
49+
value = yaml.decode("a: ~\nb: 1", { null_as_nil = true })
50+
t.assert_eq(value.a, nil, "~ should be nil when null_as_nil is true")
51+
t.assert_eq(value.b, 1)
3852
end)
3953

4054
-- Test decode to native object

0 commit comments

Comments
 (0)