1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

json: fix -cstrict build + optional map (#18014)

This commit is contained in:
Felipe Pena 2023-04-22 04:55:25 -03:00 committed by GitHub
parent 4c54f36a70
commit c43ea09d87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 31 deletions

View File

@ -0,0 +1,22 @@
import json
struct Test {
optional_string ?string
optional_array ?[]string
optional_struct_array ?[]string
optional_map ?map[string]string
}
fn test_main() {
test := Test{}
encoded := json.encode(test)
assert dump(encoded) == '{}'
test2 := Test{
optional_map: {
'foo': 'bar'
}
}
encoded2 := json.encode(test2)
assert dump(encoded2) == '{"optional_map":{"foo":"bar"}}'
}

View File

@ -135,8 +135,8 @@ ${enc_fn_dec} {
m := sym.info as ast.Map m := sym.info as ast.Map
g.gen_json_for_type(m.key_type) g.gen_json_for_type(m.key_type)
g.gen_json_for_type(m.value_type) g.gen_json_for_type(m.value_type)
dec.writeln(g.decode_map(m.key_type, m.value_type, ret_styp)) dec.writeln(g.decode_map(utyp, m.key_type, m.value_type, ret_styp))
enc.writeln(g.encode_map(m.key_type, m.value_type)) enc.writeln(g.encode_map(utyp, m.key_type, m.value_type))
} else if sym.kind == .alias { } else if sym.kind == .alias {
a := sym.info as ast.Alias a := sym.info as ast.Alias
parent_typ := a.parent_type parent_typ := a.parent_type
@ -155,8 +155,8 @@ ${enc_fn_dec} {
m := psym.info as ast.Map m := psym.info as ast.Map
g.gen_json_for_type(m.key_type) g.gen_json_for_type(m.key_type)
g.gen_json_for_type(m.value_type) g.gen_json_for_type(m.value_type)
dec.writeln(g.decode_map(m.key_type, m.value_type, ret_styp)) dec.writeln(g.decode_map(utyp, m.key_type, m.value_type, ret_styp))
enc.writeln(g.encode_map(m.key_type, m.value_type)) enc.writeln(g.encode_map(utyp, m.key_type, m.value_type))
} else { } else {
verror('json: ${sym.name} is not struct') verror('json: ${sym.name} is not struct')
} }
@ -184,7 +184,7 @@ ${enc_fn_dec} {
dec.writeln('\t${result_name}_${ret_styp} ret;') dec.writeln('\t${result_name}_${ret_styp} ret;')
dec.writeln('\t_result_ok(&res, (${result_name}*)&ret, sizeof(res));') dec.writeln('\t_result_ok(&res, (${result_name}*)&ret, sizeof(res));')
if utyp.has_flag(.option) { if utyp.has_flag(.option) {
dec.writeln('\t_option_ok(&res.data, &ret.data, sizeof(${g.base_type(utyp)}));') dec.writeln('\t_option_ok(&res.data, (${option_name}*)&ret.data, sizeof(${g.base_type(utyp)}));')
} }
dec.writeln('\treturn ret;\n}') dec.writeln('\treturn ret;\n}')
enc.writeln('\treturn o;\n}') enc.writeln('\treturn o;\n}')
@ -241,7 +241,7 @@ fn (mut g Gen) gen_enum_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc strin
if is_option { if is_option {
base_typ := g.typ(utyp.clear_flag(.option)) base_typ := g.typ(utyp.clear_flag(.option))
enc.writeln('\to = ${js_enc_name('u64')}(*val.data);') enc.writeln('\to = ${js_enc_name('u64')}(*val.data);')
dec.writeln('\t_option_ok(&(${base_typ}[]){ ${js_dec_name('u64')}(root) }, &res, sizeof(${base_typ}));') dec.writeln('\t_option_ok(&(${base_typ}[]){ ${js_dec_name('u64')}(root) }, (${option_name}*)&res, sizeof(${base_typ}));')
} else { } else {
dec.writeln('\tres = ${js_dec_name('u64')}(root);') dec.writeln('\tres = ${js_dec_name('u64')}(root);')
enc.writeln('\to = ${js_enc_name('u64')}(val);') enc.writeln('\to = ${js_enc_name('u64')}(val);')
@ -280,7 +280,7 @@ fn (mut g Gen) gen_option_enc_dec(typ ast.Type, mut enc strings.Builder, mut dec
enc.writeln('\to = ${encode_name}(*(${type_str}*)val.data);') enc.writeln('\to = ${encode_name}(*(${type_str}*)val.data);')
dec_name := js_dec_name(type_str) dec_name := js_dec_name(type_str)
dec.writeln('\t_option_ok(&(${type_str}[]){ ${dec_name}(root) }, &res, sizeof(${type_str}));') dec.writeln('\t_option_ok(&(${type_str}[]){ ${dec_name}(root) }, (${option_name}*)&res, sizeof(${type_str}));')
} }
[inline] [inline]
@ -393,7 +393,7 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st
dec.writeln('\t\t${variant_typ} value = *(${variant_typ}*)(${tmp}.data);') dec.writeln('\t\t${variant_typ} value = *(${variant_typ}*)(${tmp}.data);')
} }
if is_option { if is_option {
dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${variant_typ}_to_sumtype_${sym.cname}(&value) }, &res, sizeof(${sym.cname}));') dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${variant_typ}_to_sumtype_${sym.cname}(&value) }, (${option_name}*)&res, sizeof(${sym.cname}));')
} else { } else {
dec.writeln('\t\tres = ${variant_typ}_to_sumtype_${ret_styp}(&value);') dec.writeln('\t\tres = ${variant_typ}_to_sumtype_${ret_styp}(&value);')
} }
@ -806,7 +806,7 @@ fn (mut g Gen) decode_array(utyp ast.Type, value_type ast.Type, fixed_array_size
fixed_array_idx_increment += 'fixed_array_idx++;' fixed_array_idx_increment += 'fixed_array_idx++;'
} else { } else {
array_element_assign += 'array_push${noscan}((array*)&res.data, &val);' array_element_assign += 'array_push${noscan}((array*)&res.data, &val);'
res_str += '_option_ok(&(${g.base_type(utyp)}[]) { __new_array${noscan}(0, 0, sizeof(${styp})) }, &res, sizeof(${g.base_type(utyp)}));' res_str += '_option_ok(&(${g.base_type(utyp)}[]) { __new_array${noscan}(0, 0, sizeof(${styp})) }, (${option_name}*)&res, sizeof(${g.base_type(utyp)}));'
array_free_str += 'array_free(&res.data);' array_free_str += 'array_free(&res.data);'
} }
} else { } else {
@ -882,7 +882,7 @@ fn (mut g Gen) encode_array(utyp ast.Type, value_type ast.Type, fixed_array_size
' '
} }
fn (mut g Gen) decode_map(key_type ast.Type, value_type ast.Type, ustyp string) string { fn (mut g Gen) decode_map(utyp ast.Type, key_type ast.Type, value_type ast.Type, ustyp string) string {
styp := g.typ(key_type) styp := g.typ(key_type)
mut styp_v := g.typ(value_type) mut styp_v := g.typ(value_type)
ret_styp := styp_v.replace('*', '_ptr') ret_styp := styp_v.replace('*', '_ptr')
@ -902,22 +902,39 @@ fn (mut g Gen) decode_map(key_type ast.Type, value_type ast.Type, ustyp string)
${styp_v} val = *(${styp_v}*)val2.data; ${styp_v} val = *(${styp_v}*)val2.data;
' '
} }
return '
if(!cJSON_IsObject(root) && !cJSON_IsNull(root)) { if utyp.has_flag(.option) {
return (${result_name}_${ustyp}){ .is_error = true, .err = _v_error(string__plus(_SLIT("Json element is not an object: "), tos2((byteptr)cJSON_PrintUnformatted(root)))), .data = {0}}; return '
} if(!cJSON_IsObject(root) && !cJSON_IsNull(root)) {
res = new_map(sizeof(${styp}), sizeof(${styp_v}), ${hash_fn}, ${key_eq_fn}, ${clone_fn}, ${free_fn}); return (${result_name}_${ustyp}){ .is_error = true, .err = _v_error(string__plus(_SLIT("Json element is not an object: "), tos2((byteptr)cJSON_PrintUnformatted(root)))), .data = {0}};
cJSON *jsval = NULL; }
cJSON_ArrayForEach(jsval, root) _option_ok(&(${g.base_type(utyp)}[]) { new_map(sizeof(${styp}), sizeof(${styp_v}), ${hash_fn}, ${key_eq_fn}, ${clone_fn}, ${free_fn}) }, (${option_name}*)&res, sizeof(${g.base_type(utyp)}));
{ cJSON *jsval = NULL;
${s} cJSON_ArrayForEach(jsval, root)
string key = tos2((byteptr)jsval->string); {
map_set(&res, &key, &val); ${s}
} string key = tos2((byteptr)jsval->string);
map_set((map*)res.data, &key, &val);
}
' '
} else {
return '
if(!cJSON_IsObject(root) && !cJSON_IsNull(root)) {
return (${result_name}_${ustyp}){ .is_error = true, .err = _v_error(string__plus(_SLIT("Json element is not an object: "), tos2((byteptr)cJSON_PrintUnformatted(root)))), .data = {0}};
}
res = new_map(sizeof(${styp}), sizeof(${styp_v}), ${hash_fn}, ${key_eq_fn}, ${clone_fn}, ${free_fn});
cJSON *jsval = NULL;
cJSON_ArrayForEach(jsval, root)
{
${s}
string key = tos2((byteptr)jsval->string);
map_set(&res, &key, &val);
}
'
}
} }
fn (mut g Gen) encode_map(key_type ast.Type, value_type ast.Type) string { fn (mut g Gen) encode_map(utyp ast.Type, key_type ast.Type, value_type ast.Type) string {
styp := g.typ(key_type) styp := g.typ(key_type)
styp_v := g.typ(value_type) styp_v := g.typ(value_type)
fn_name_v := js_enc_name(styp_v) fn_name_v := js_enc_name(styp_v)
@ -930,13 +947,25 @@ fn (mut g Gen) encode_map(key_type ast.Type, value_type ast.Type) string {
// key += '${styp}_str((($styp*)${keys_tmp}.data)[i]);' // key += '${styp}_str((($styp*)${keys_tmp}.data)[i]);'
verror('json: encode only maps with string keys') verror('json: encode only maps with string keys')
} }
return ' if utyp.has_flag(.option) {
o = cJSON_CreateObject(); return '
Array_${styp} ${keys_tmp} = map_keys(&val); o = cJSON_CreateObject();
for (int i = 0; i < ${keys_tmp}.len; ++i) { Array_${styp} ${keys_tmp} = map_keys((map*)val.data);
${key} for (int i = 0; i < ${keys_tmp}.len; ++i) {
cJSON_AddItemToObject(o, (char*) key.str, ${fn_name_v} ( *(${styp_v}*) map_get(&val, &key, &(${styp_v}[]) { ${zero} } ) ) ); ${key}
} cJSON_AddItemToObject(o, (char*) key.str, ${fn_name_v} ( *(${styp_v}*) map_get((map*)val.data, &key, &(${styp_v}[]) { ${zero} } ) ) );
array_free(&${keys_tmp}); }
array_free(&${keys_tmp});
' '
} else {
return '
o = cJSON_CreateObject();
Array_${styp} ${keys_tmp} = map_keys(&val);
for (int i = 0; i < ${keys_tmp}.len; ++i) {
${key}
cJSON_AddItemToObject(o, (char*) key.str, ${fn_name_v} ( *(${styp_v}*) map_get(&val, &key, &(${styp_v}[]) { ${zero} } ) ) );
}
array_free(&${keys_tmp});
'
}
} }