Skip to content

Commit 832e8c1

Browse files
authored
json2: add support for encoding embedded structs (fix #24994) (#25475)
1 parent 78401cf commit 832e8c1

2 files changed

Lines changed: 107 additions & 55 deletions

File tree

‎vlib/x/json2/encode.v‎

Lines changed: 79 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -389,86 +389,110 @@ fn (mut encoder Encoder) cached_field_infos[T]() []EncoderFieldInfo {
389389
@[unsafe]
390390
fn (mut encoder Encoder) encode_struct[T](val T) {
391391
encoder.output << `{`
392+
393+
is_first := encoder.encode_struct_fields(val, true, [], '')
394+
395+
if encoder.prettify && !is_first {
396+
encoder.decrement_level()
397+
encoder.add_indent()
398+
}
399+
400+
encoder.output << `}`
401+
}
402+
403+
@[unsafe]
404+
fn (mut encoder Encoder) encode_struct_fields[T](val T, was_first bool, old_used_keys []string, prefix string) bool {
392405
field_infos := encoder.cached_field_infos[T]()
393406
mut i := 0
394-
mut is_first := true
407+
mut is_first := was_first
408+
mut used_keys := old_used_keys
409+
395410
$for field in T.fields {
396-
field_info := field_infos[i]
397-
i++
411+
$if !field.is_embed {
412+
field_info := field_infos[i]
398413

399-
mut write_field := true
414+
mut write_field := true
400415

401-
if field_info.is_skip {
402-
write_field = false
403-
} else {
404-
value := val.$(field.name)
416+
if field_info.is_skip {
417+
write_field = false
418+
} else {
419+
value := val.$(field.name)
405420

406-
if field_info.is_omitempty {
407-
$if value is $option {
408-
write_field = check_not_empty(value) or { false }
409-
} $else {
410-
write_field = check_not_empty(value) or { false }
421+
if field_info.is_omitempty {
422+
$if value is $option {
423+
write_field = check_not_empty(value) or { false }
424+
} $else {
425+
write_field = check_not_empty(value) or { false }
426+
}
411427
}
412-
}
413428

414-
if !field_info.is_required {
415-
$if value is $option {
416-
if value == none {
417-
write_field = false
429+
if !field_info.is_required {
430+
$if value is $option {
431+
if value == none {
432+
write_field = false
433+
}
418434
}
419435
}
420436
}
421-
}
422437

423-
$if field.indirections != 0 {
424-
if val.$(field.name) == unsafe { nil } {
425-
write_field = false
438+
$if field.indirections != 0 {
439+
if val.$(field.name) == unsafe { nil } {
440+
write_field = false
441+
}
426442
}
427-
}
428443

429-
if write_field {
430-
if is_first {
444+
if write_field {
445+
if is_first {
446+
if encoder.prettify {
447+
encoder.increment_level()
448+
}
449+
is_first = false
450+
} else {
451+
encoder.output << `,`
452+
}
431453
if encoder.prettify {
432-
encoder.increment_level()
454+
encoder.add_indent()
433455
}
434-
is_first = false
435-
} else {
436-
encoder.output << `,`
437-
}
438-
if encoder.prettify {
439-
encoder.add_indent()
440-
}
441456

442-
encoder.encode_string(field_info.key_name)
457+
if field_info.key_name in old_used_keys {
458+
encoder.encode_string(prefix + field_info.key_name)
459+
} else {
460+
encoder.encode_string(field_info.key_name)
461+
used_keys << field_info.key_name
462+
}
443463

444-
encoder.output << `:`
445-
if encoder.prettify {
446-
encoder.output << ` `
447-
}
464+
encoder.output << `:`
465+
if encoder.prettify {
466+
encoder.output << ` `
467+
}
448468

449-
$if field is $option {
450-
if val.$(field.name) == none {
451-
unsafe { encoder.output.push_many(null_string.str, null_string.len) }
452-
} else {
469+
$if field is $option {
470+
if val.$(field.name) == none {
471+
unsafe { encoder.output.push_many(null_string.str, null_string.len) }
472+
} else {
473+
encoder.encode_value(val.$(field.name))
474+
}
475+
} $else $if field.indirections == 1 {
476+
encoder.encode_value(*val.$(field.name))
477+
} $else $if field.indirections == 2 {
478+
encoder.encode_value(**val.$(field.name))
479+
} $else $if field.indirections == 3 {
480+
encoder.encode_value(***val.$(field.name))
481+
} $else {
453482
encoder.encode_value(val.$(field.name))
454483
}
455-
} $else $if field.indirections == 1 {
456-
encoder.encode_value(*val.$(field.name))
457-
} $else $if field.indirections == 2 {
458-
encoder.encode_value(**val.$(field.name))
459-
} $else $if field.indirections == 3 {
460-
encoder.encode_value(***val.$(field.name))
461-
} $else {
462-
encoder.encode_value(val.$(field.name))
463484
}
464485
}
486+
i++
465487
}
466-
if encoder.prettify && !is_first {
467-
encoder.decrement_level()
468-
encoder.add_indent()
488+
$for field in T.fields {
489+
$if field.is_embed {
490+
new_prefix := prefix + field.name + '.'
491+
is_first = encoder.encode_struct_fields(val.$(field.name), is_first, used_keys,
492+
new_prefix)
493+
}
469494
}
470-
471-
encoder.output << `}`
495+
return is_first
472496
}
473497

474498
fn (mut encoder Encoder) encode_custom[T](val T) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import x.json2 as json
2+
3+
struct Baz {
4+
c bool = true
5+
}
6+
7+
struct Foo {
8+
Baz
9+
a int = 1
10+
b int = 2
11+
}
12+
13+
struct Bar {
14+
Foo
15+
a string = '1'
16+
c string = '3'
17+
}
18+
19+
fn test_embed() {
20+
assert json.encode(Bar{}) == '{"a":"1","c":"3","Foo.a":1,"b":2,"Foo.Baz.c":true}'
21+
assert json.encode(Bar{}, prettify: true) == '{
22+
"a": "1",
23+
"c": "3",
24+
"Foo.a": 1,
25+
"b": 2,
26+
"Foo.Baz.c": true
27+
}'
28+
}

0 commit comments

Comments
 (0)