@@ -8110,6 +8110,24 @@ fn (mut g FlatGen) preintern_json_encode_value_strings(typ types.Type, seen []st
81108110 g.preintern_json_encode_value_strings(clean.value_type, seen)
81118111 return
81128112 }
8113+ if clean is types.SumType {
8114+ sum_name := g.resolve_sum_name(clean.name)
8115+ if sum_name in seen {
8116+ return
8117+ }
8118+ mut next_seen := seen.clone()
8119+ next_seen << sum_name
8120+ g.intern_string('null')
8121+ for variant in g.tc.sum_types[sum_name] or { []string{} } {
8122+ variant_type := g.json_sum_variant_type(variant)
8123+ if variant_type is types.Pointer {
8124+ g.preintern_json_encode_value_strings(variant_type.base_type, next_seen)
8125+ } else {
8126+ g.preintern_json_encode_value_strings(variant_type, next_seen)
8127+ }
8128+ }
8129+ return
8130+ }
81138131 if clean is types.Primitive {
81148132 if clean.props.has(.boolean) {
81158133 g.intern_string('true')
@@ -8247,6 +8265,26 @@ fn (mut g FlatGen) json_encode_value_c_expr(typ types.Type, expr string) ?string
82478265 }
82488266 return none
82498267 }
8268+ if clean is types.SumType {
8269+ sum_name := g.resolve_sum_name(clean.name)
8270+ variants := g.tc.sum_types[sum_name] or { return none }
8271+ null_sid := g.intern_string('null')
8272+ mut result := '_str_${null_sid}'
8273+ for i := variants.len - 1; i >= 0; i-- {
8274+ variant := variants[i]
8275+ variant_type := g.json_sum_variant_type(variant)
8276+ if variant_type is types.Pointer {
8277+ return none
8278+ }
8279+ field := g.sum_field_name(variant)
8280+ encoded := g.json_encode_value_c_expr(variant_type, '(*(${expr}).${field})') or {
8281+ return none
8282+ }
8283+ index := g.sum_type_index(sum_name, variant)
8284+ result = '((${expr}).typ == ${index} ? ${encoded} : ${result})'
8285+ }
8286+ return result
8287+ }
82508288 if clean is types.Struct {
82518289 fields := g.json_encode_struct_field_exprs(clean.name, expr, []string{}) or { return none }
82528290 open := g.intern_string('{')
@@ -8391,7 +8429,8 @@ fn (g &FlatGen) json_struct_field_is_embedded(field types.StructField, type_name
83918429
83928430fn (g &FlatGen) json_encode_omitempty_supported(typ types.Type) bool {
83938431 clean := if typ is types.Alias { typ.base_type } else { typ }
8394- if clean is types.String || clean is types.Enum {
8432+ if clean is types.String || clean is types.Enum || clean is types.Array || clean is types.Map
8433+ || clean is types.Struct || clean is types.SumType {
83958434 return true
83968435 }
83978436 if clean is types.Primitive {
@@ -8401,25 +8440,119 @@ fn (g &FlatGen) json_encode_omitempty_supported(typ types.Type) bool {
84018440}
84028441
84038442fn (mut g FlatGen) json_encode_omitempty_expr(typ types.Type, expr string) ?string {
8443+ clean := if typ is types.Alias { typ.base_type } else { typ }
8444+ ct := g.value_c_type(typ)
8445+ value_name := g.tmp_name()
8446+ default_name := g.tmp_name()
8447+ equal := g.json_encode_equal_c_expr(clean, value_name, default_name, []string{}) or {
8448+ return none
8449+ }
8450+ default_value := g.default_value_to_string(typ)
8451+ return '({ ${ct} ${value_name} = ${expr}; ${ct} ${default_name} = ${default_value}; ${equal}; })'
8452+ }
8453+
8454+ fn (mut g FlatGen) json_encode_equal_c_expr(typ types.Type, left string, right string, seen []string) ?string {
84048455 clean := if typ is types.Alias { typ.base_type } else { typ }
84058456 if clean is types.String {
8406- return '((${expr }).len == 0 )'
8457+ return '((${left }).len == (${right}).len && ((${left}).len == 0 || memcmp((${left}).str, (${right}).str, (${left}).len) == 0) )'
84078458 }
84088459 if clean is types.Enum {
8409- default_value := g.enum_default_value_expr_for_type(clean.name) or { '0' }
8410- return '((${expr}) == ${default_value})'
8460+ return '((${left}) == (${right}))'
84118461 }
84128462 if clean is types.Primitive {
8413- if clean.props.has(.boolean) {
8414- return '(!((bool)(${expr})))'
8463+ if clean.props.has(.boolean) || clean.props.has(.integer) || clean.props.has(.float) {
8464+ return '((${left}) == (${right}))'
8465+ }
8466+ return none
8467+ }
8468+ if clean is types.Array {
8469+ elem_ct := g.value_c_type(clean.elem_type)
8470+ left_name := g.tmp_name()
8471+ right_name := g.tmp_name()
8472+ equal_name := g.tmp_name()
8473+ index_name := g.tmp_name()
8474+ left_elem := g.tmp_name()
8475+ right_elem := g.tmp_name()
8476+ elem_equal := g.json_encode_equal_c_expr(clean.elem_type, '(*${left_elem})',
8477+ '(*${right_elem})', seen) or { return none }
8478+ return '({ Array ${left_name} = ${left}; Array ${right_name} = ${right}; bool ${equal_name} = ${left_name}.len == ${right_name}.len; for (int ${index_name} = 0; ${equal_name} && ${index_name} < ${left_name}.len; ++${index_name}) { ${elem_ct}* ${left_elem} = (${elem_ct}*)array_get(${left_name}, ${index_name}); ${elem_ct}* ${right_elem} = (${elem_ct}*)array_get(${right_name}, ${index_name}); if (!(${elem_equal})) ${equal_name} = false; } ${equal_name}; })'
8479+ }
8480+ if clean is types.Map {
8481+ key_clean := if clean.key_type is types.Alias {
8482+ clean.key_type.base_type
8483+ } else {
8484+ clean.key_type
84158485 }
8416- if clean.props.has(.integer) || clean.props.has(.float) {
8417- return '((${expr}) == 0)'
8486+ if key_clean !is types.String {
8487+ return none
84188488 }
8489+ value_ct := g.value_c_type(clean.value_type)
8490+ left_name := g.tmp_name()
8491+ right_name := g.tmp_name()
8492+ equal_name := g.tmp_name()
8493+ index_name := g.tmp_name()
8494+ key_name := g.tmp_name()
8495+ left_value := g.tmp_name()
8496+ right_value := g.tmp_name()
8497+ value_equal := g.json_encode_equal_c_expr(clean.value_type, '(*${left_value})',
8498+ '(*${right_value})', seen) or { return none }
8499+ return '({ map ${left_name} = ${left}; map ${right_name} = ${right}; bool ${equal_name} = ${left_name}.len == ${right_name}.len; for (int ${index_name} = 0; ${equal_name} && ${index_name} < ${left_name}.key_values.len; ++${index_name}) { if (${left_name}.key_values.deletes != 0 && ${left_name}.key_values.all_deleted != 0 && ${left_name}.key_values.all_deleted[${index_name}] != 0) continue; string* ${key_name} = (string*)(${left_name}.key_values.keys + ${index_name} * ${left_name}.key_values.key_bytes); ${value_ct}* ${left_value} = (${value_ct}*)(${left_name}.key_values.values + ${index_name} * ${left_name}.key_values.value_bytes); if (!map__exists(&${right_name}, ${key_name})) { ${equal_name} = false; break; } ${value_ct}* ${right_value} = (${value_ct}*)map__get(&${right_name}, ${key_name}, ${left_value}); if (!(${value_equal})) ${equal_name} = false; } ${equal_name}; })'
8500+ }
8501+ if clean is types.Struct {
8502+ if clean.name in seen {
8503+ return none
8504+ }
8505+ mut next_seen := seen.clone()
8506+ next_seen << clean.name
8507+ fields := g.tc.structs[clean.name] or { return none }
8508+ mut conditions := []string{cap: fields.len}
8509+ for field in fields {
8510+ field_name := g.cname(field.name)
8511+ condition := g.json_encode_equal_c_expr(field.typ, '(${left}).${field_name}',
8512+ '(${right}).${field_name}', next_seen) or { return none }
8513+ conditions << condition
8514+ }
8515+ return if conditions.len == 0 { 'true' } else { conditions.join(' && ') }
8516+ }
8517+ if clean is types.SumType {
8518+ sum_name := g.resolve_sum_name(clean.name)
8519+ if sum_name in seen {
8520+ return none
8521+ }
8522+ variants := g.tc.sum_types[sum_name] or { return none }
8523+ mut next_seen := seen.clone()
8524+ next_seen << sum_name
8525+ mut active_equal := 'true'
8526+ for i := variants.len - 1; i >= 0; i-- {
8527+ variant := variants[i]
8528+ variant_type := g.json_sum_variant_type(variant)
8529+ if variant_type is types.Pointer {
8530+ return none
8531+ }
8532+ field := g.sum_field_name(variant)
8533+ variant_equal := g.json_encode_equal_c_expr(variant_type, '(*(${left}).${field})',
8534+ '(*(${right}).${field})', next_seen) or { return none }
8535+ index := g.sum_type_index(sum_name, variant)
8536+ active_equal = '((${left}).typ == ${index} ? ${variant_equal} : ${active_equal})'
8537+ }
8538+ return '((${left}).typ == (${right}).typ && ${active_equal})'
84198539 }
84208540 return none
84218541}
84228542
8543+ fn (g &FlatGen) json_sum_variant_type(raw_type string) types.Type {
8544+ clean := raw_type.trim_space()
8545+ if types.is_builtin_type_name(clean) {
8546+ return types.builtin_type_value(clean)
8547+ }
8548+ if clean.starts_with('[]') {
8549+ return types.Type(types.Array{
8550+ elem_type: g.json_sum_variant_type(clean[2..])
8551+ })
8552+ }
8553+ return select_receive_unalias_type(g.tc.parse_canonical_type(clean))
8554+ }
8555+
84238556fn (mut g FlatGen) gen_json_decode_call(node flat.Node) bool {
84248557 if node.children_count < 3 {
84258558 return false
@@ -8860,7 +8993,9 @@ fn (g &FlatGen) json_struct_has_decode_field_attrs(struct_name string) bool {
88608993}
88618994
88628995fn (g &FlatGen) json_struct_has_encode_field_attrs(struct_name string) bool {
8863- return g.json_struct_has_disallowed_field_attrs(struct_name, ['skip', 'json', 'omitempty'])
8996+ // `required` only constrains decoding. It does not change the encoded value.
8997+ return g.json_struct_has_disallowed_field_attrs(struct_name, ['skip', 'json', 'omitempty',
8998+ 'required'])
88648999}
88659000
88669001fn (g &FlatGen) json_struct_has_disallowed_field_attrs(struct_name string, allowed []string) bool {
0 commit comments