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
g.gen_json_for_type(m.key_type)
g.gen_json_for_type(m.value_type)
dec.writeln(g.decode_map(m.key_type, m.value_type, ret_styp))
enc.writeln(g.encode_map(m.key_type, m.value_type))
dec.writeln(g.decode_map(utyp, m.key_type, m.value_type, ret_styp))
enc.writeln(g.encode_map(utyp, m.key_type, m.value_type))
} else if sym.kind == .alias {
a := sym.info as ast.Alias
parent_typ := a.parent_type
@ -155,8 +155,8 @@ ${enc_fn_dec} {
m := psym.info as ast.Map
g.gen_json_for_type(m.key_type)
g.gen_json_for_type(m.value_type)
dec.writeln(g.decode_map(m.key_type, m.value_type, ret_styp))
enc.writeln(g.encode_map(m.key_type, m.value_type))
dec.writeln(g.decode_map(utyp, m.key_type, m.value_type, ret_styp))
enc.writeln(g.encode_map(utyp, m.key_type, m.value_type))
} else {
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_ok(&res, (${result_name}*)&ret, sizeof(res));')
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}')
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 {
base_typ := g.typ(utyp.clear_flag(.option))
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 {
dec.writeln('\tres = ${js_dec_name('u64')}(root);')
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);')
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]
@ -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);')
}
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 {
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++;'
} else {
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);'
}
} 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)
mut styp_v := g.typ(value_type)
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;
'
}
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);
}
if utyp.has_flag(.option) {
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}};
}
_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;
cJSON_ArrayForEach(jsval, root)
{
${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_v := g.typ(value_type)
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]);'
verror('json: encode only maps with string keys')
}
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});
if utyp.has_flag(.option) {
return '
o = cJSON_CreateObject();
Array_${styp} ${keys_tmp} = map_keys((map*)val.data);
for (int i = 0; i < ${keys_tmp}.len; ++i) {
${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});
'
} 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});
'
}
}