From 747af8c360ac57d95f8c556b0f11e1b2fb1544ff Mon Sep 17 00:00:00 2001 From: Larsimusrex Date: Fri, 18 Jul 2025 10:03:21 +0200 Subject: [PATCH] x.json2.decoder2: fix decoding of structs with option fields (fix #24409) (#24922) --- vlib/x/json2/decoder2/decode.v | 28 ++++++++----------- .../decoder2/tests/decode_option_field_test.v | 23 +++++++++++++++ 2 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 vlib/x/json2/decoder2/tests/decode_option_field_test.v diff --git a/vlib/x/json2/decoder2/decode.v b/vlib/x/json2/decoder2/decode.v index 0733ad7a56..71771116a4 100644 --- a/vlib/x/json2/decoder2/decode.v +++ b/vlib/x/json2/decoder2/decode.v @@ -546,18 +546,7 @@ pub fn decode[T](val string) !T { // decode_value decodes a value from the JSON nodes. @[manualfree] fn (mut decoder Decoder) decode_value[T](mut val T) ! { - $if T is $option { - value_info := decoder.current_node.value - - if value_info.value_kind == .null { - decoder.current_node = decoder.current_node.next - // val = none // Is this line needed? - return - } - mut unwrapped_val := create_value_from_optional(val.$(field.name)) - decoder.decode_value(mut unwrapped_val)! - val.$(field.name) = unwrapped_val - } $else $if T.unaliased_typ is string { + $if T.unaliased_typ is string { string_info := decoder.current_node.value if string_info.value_kind == .string_ { @@ -815,11 +804,18 @@ fn (mut decoder Decoder) decode_value[T](mut val T) ! { } } else { $if field.typ is $option { - mut unwrapped_val := create_value_from_optional(val.$(field.name)) or { - return + // it would be nicer to do this at the start of the function + // but options cant be passed to generic functions + if decoder.current_node.value.length == 4 + && decoder.json[decoder.current_node.value.position..decoder.current_node.value.position + 4] == 'null' { + val.$(field.name) = none + } else { + mut unwrapped_val := create_value_from_optional(val.$(field.name)) or { + return + } + decoder.decode_value(mut unwrapped_val)! + val.$(field.name) = unwrapped_val } - decoder.decode_value(mut unwrapped_val)! - val.$(field.name) = unwrapped_val } $else { decoder.decode_value(mut val.$(field.name))! } diff --git a/vlib/x/json2/decoder2/tests/decode_option_field_test.v b/vlib/x/json2/decoder2/tests/decode_option_field_test.v new file mode 100644 index 0000000000..bd8935af98 --- /dev/null +++ b/vlib/x/json2/decoder2/tests/decode_option_field_test.v @@ -0,0 +1,23 @@ +import x.json2.decoder2 +import json + +struct Data { + name ?string + value string +} + +fn test_decode_option_field() { + assert decoder2.decode[Data]('{"name": "test", "value": "hi"}')! == Data{ + name: 'test' + value: 'hi' + } + assert decoder2.decode[Data]('{"name": null, "value": "hi"}')! == Data{ + name: none + value: 'hi' + } + assert decoder2.decode[Data]('{"value": "hi"}')! == Data{ + name: none + value: 'hi' + } + assert decoder2.decode[Data]('{"name": null, "value": null}') or { return } == Data{} +}