From 651a1161598b7c67bd4ecfbdb619ad7fe93584e6 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 21 Sep 2024 03:01:11 -0300 Subject: [PATCH] json: fix decoding of structs with embeds (#22264) --- vlib/json/json_decode_embed_test.v | 28 ++++++++++++++++++++++++++++ vlib/v/gen/c/json.v | 27 +++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 vlib/json/json_decode_embed_test.v diff --git a/vlib/json/json_decode_embed_test.v b/vlib/json/json_decode_embed_test.v new file mode 100644 index 00000000000000..314226aa7f6e58 --- /dev/null +++ b/vlib/json/json_decode_embed_test.v @@ -0,0 +1,28 @@ +module main + +import json + +struct Json2 { + inner []f64 +} + +struct Json { + Json2 + test f64 +} + +fn test_main() { + str := '{ + "inner": [1, 2, 3, 4, 5], + "test": 1.0 + }' + data := json.decode(Json, str) or { + eprintln('Failed to decode json, error: ${err}') + return + } + println(data) + assert data.inner.len == 5 + assert data.inner[0] == 1.0 + assert data.inner[4] == 5.0 + assert data.test == 1.0 +} diff --git a/vlib/v/gen/c/json.v b/vlib/v/gen/c/json.v index 0e1ba421ab319d..4bbfc783bf39c0 100644 --- a/vlib/v/gen/c/json.v +++ b/vlib/v/gen/c/json.v @@ -167,7 +167,7 @@ ${enc_fn_dec} { } } else if psym.info is ast.Struct { enc.writeln('\to = cJSON_CreateObject();') - g.gen_struct_enc_dec(utyp, psym.info, ret_styp, mut enc, mut dec) + g.gen_struct_enc_dec(utyp, psym.info, ret_styp, mut enc, mut dec, '') } else if psym.kind == .enum_ { g.gen_enum_enc_dec(utyp, psym, mut enc, mut dec) } else if psym.kind == .sum_type { @@ -201,7 +201,7 @@ ${enc_fn_dec} { if sym.info !is ast.Struct { verror('json: ${sym.name} is not struct') } - g.gen_struct_enc_dec(utyp, sym.info, ret_styp, mut enc, mut dec) + g.gen_struct_enc_dec(utyp, sym.info, ret_styp, mut enc, mut dec, '') } // cJSON_delete dec.writeln('\t${result_name}_${ret_styp} ret;') @@ -606,7 +606,7 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st @[inline] fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp string, mut enc strings.Builder, - mut dec strings.Builder) { + mut dec strings.Builder, embed_prefix string) { info := type_info as ast.Struct for field in info.fields { mut name := field.name @@ -646,7 +646,12 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st field_type := g.typ(field.typ) field_sym := g.table.sym(field.typ) op := if utyp.is_ptr() { '->' } else { '.' } - prefix := if utyp.has_flag(.option) { '(*(${g.base_type(utyp)}*)res.data)' } else { 'res' } + embed_member := if embed_prefix.len > 0 { '.${embed_prefix}' } else { '' } + prefix := if utyp.has_flag(.option) { + '(*(${g.base_type(utyp)}*)res${embed_member}.data)' + } else { + 'res${embed_member}' + } // First generate decoding if is_raw { if field.typ.has_flag(.option) { @@ -757,6 +762,17 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st dec.writeln('\t}') } } else { + // embeded + if name.len > 0 && name[0].is_capital() && field_sym.info is ast.Struct { + for embed in info.embeds { + if embed == int(field.typ) { + g.gen_struct_enc_dec(field.typ, g.table.sym(field.typ).info, + styp, mut enc, mut dec, name) + break + } + } + continue + } tmp := g.new_tmp_var() gen_js_get_opt(dec_name, field_type, styp, tmp, name, mut dec, is_required) dec.writeln('\tif (jsonroot_${tmp}) {') @@ -781,6 +797,9 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st dec.writeln('\t}') } } + if embed_prefix.len > 0 { + return + } // Encoding mut enc_name := js_enc_name(field_type) prefix_enc := if utyp.has_flag(.option) {