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

json: fix encode/decode fixed array (#17887)

This commit is contained in:
Felipe Pena 2023-04-05 19:15:23 -03:00 committed by GitHub
parent dce65c7f46
commit b4e8e812fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 120 additions and 38 deletions

View File

@ -0,0 +1,46 @@
import json
pub struct DocumentFindFilter[T] {
pub:
selector ?T
selector2 ?[]T
selector3 ?[1]T
limit ?int
skip ?int
fields ?[]string // This breaks the compiler when encoding to JSON
conflicts ?bool
read_quorum ?int [json: r]
update ?bool
stable ?bool
stale ?string
execution_stats ?bool
}
fn test_string() {
t := DocumentFindFilter[string]{
selector: 'aa'
selector2: ['a', 'b']
selector3: ['z']!
}
assert json.encode(t) == '{"selector":"aa","selector2":["a","b"],"selector3":["z"]}'
assert json.decode(DocumentFindFilter[string], '{"selector":"aa","selector2":["a","b"],"selector3":["z"]}')! == t
}
fn test_int() ! {
t := DocumentFindFilter[int]{
selector: 1
selector2: [1, 2]
selector3: [3]!
}
assert json.encode(t) == '{"selector":1,"selector2":[1,2],"selector3":[3]}'
assert json.decode(DocumentFindFilter[int], '{"selector":1,"selector2":[1,2],"selector3":[3]}')! == t
}
fn test_none() ! {
t := DocumentFindFilter[int]{}
assert json.encode(t) == '{}'
assert json.decode(DocumentFindFilter[int], '{}')! == t
}

View File

@ -342,48 +342,51 @@ fn (mut g Gen) gen_array_equality_fn(left_type ast.Type) string {
}
fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string {
left := g.unwrap(left_type)
ptr_styp := g.typ(left.typ.set_nr_muls(0))
left_typ := g.unwrap(left_type)
ptr_styp := g.typ(left_typ.typ.set_nr_muls(0))
if left_type in g.generated_eq_fns {
return ptr_styp
}
g.generated_eq_fns << left_type
elem_info := left.sym.array_fixed_info()
elem_info := left_typ.sym.array_fixed_info()
elem := g.unwrap(elem_info.elem_type)
size := elem_info.size
g.definitions.writeln('static bool ${ptr_styp}_arr_eq(${ptr_styp} a, ${ptr_styp} b); // auto')
left := if left_type.has_flag(.option) { 'a.data' } else { 'a' }
right := if left_type.has_flag(.option) { 'b.data' } else { 'b' }
mut fn_builder := strings.new_builder(512)
fn_builder.writeln('static bool ${ptr_styp}_arr_eq(${ptr_styp} a, ${ptr_styp} b) {')
fn_builder.writeln('\tfor (int i = 0; i < ${size}; ++i) {')
// compare every pair of elements of the two fixed arrays
if elem.sym.kind == .string {
fn_builder.writeln('\t\tif (!string__eq(a[i], b[i])) {')
fn_builder.writeln('\t\tif (!string__eq(((string*)${left})[i], ((string*)${right})[i])) {')
} else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() {
eq_fn := g.gen_sumtype_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(a[i], b[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(${left}[i], ${right}[i])) {')
} else if elem.sym.kind == .struct_ && !elem.typ.is_ptr() {
eq_fn := g.gen_struct_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(a[i], b[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(${left}[i], ${right}[i])) {')
} else if elem.sym.kind == .interface_ && !elem.typ.is_ptr() {
eq_fn := g.gen_interface_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(a[i], b[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(${left}[i], ${right}[i])) {')
} else if elem.sym.kind == .array && !elem.typ.is_ptr() {
eq_fn := g.gen_array_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a[i], b[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(${left}[i], ${right}[i])) {')
} else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() {
eq_fn := g.gen_fixed_array_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a[i], b[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(${left}[i], ${right}[i])) {')
} else if elem.sym.kind == .map && !elem.typ.is_ptr() {
eq_fn := g.gen_map_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(a[i], b[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(${left}[i], ${right}[i])) {')
} else if elem.sym.kind == .alias && !elem.typ.is_ptr() {
eq_fn := g.gen_alias_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(a[i], b[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(${left}[i], ${right}[i])) {')
} else if elem.sym.kind == .function {
fn_builder.writeln('\t\tif (a[i] != b[i]) {')
fn_builder.writeln('\t\tif (${left}[i] != ${right}[i]) {')
} else {
fn_builder.writeln('\t\tif (a[i] != b[i]) {')
fn_builder.writeln('\t\tif (${left}[i] != ${right}[i]) {')
}
fn_builder.writeln('\t\t\treturn false;')
fn_builder.writeln('\t\t}')

View File

@ -128,8 +128,8 @@ ${enc_fn_dec} {
value_type := g.table.value_type(utyp)
// If we have `[]Profile`, have to register a Profile en(de)coder first
g.gen_json_for_type(value_type)
dec.writeln(g.decode_array(value_type, array_size))
enc.writeln(g.encode_array(value_type, array_size))
dec.writeln(g.decode_array(utyp, value_type, array_size, ret_styp))
enc.writeln(g.encode_array(utyp, value_type, array_size))
} else if sym.kind == .map {
// Handle maps
m := sym.info as ast.Map
@ -628,10 +628,18 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st
gen_js_get_opt(dec_name, field_type, styp, tmp, name, mut dec, is_required)
dec.writeln('\tif (jsonroot_${tmp}) {')
if field_sym.kind == .array_fixed {
dec.writeln('\t\tvmemcpy(${prefix}${op}${c_name(field.name)},*(${field_type}*)${tmp}.data,sizeof(${field_type}));')
if field.typ.has_flag(.option) {
if field_sym.kind == .array_fixed {
dec.writeln('\t\tvmemcpy(&${prefix}${op}${c_name(field.name)}, (${field_type}*)${tmp}.data, sizeof(${field_type}));')
} else {
dec.writeln('\t\tvmemcpy(&${prefix}${op}${c_name(field.name)}, (${field_type}*)${tmp}.data, sizeof(${field_type}));')
}
} else {
dec.writeln('\t\t${prefix}${op}${c_name(field.name)} = *(${field_type}*) ${tmp}.data;')
if field_sym.kind == .array_fixed {
dec.writeln('\t\tvmemcpy(${prefix}${op}${c_name(field.name)},*(${field_type}*)${tmp}.data,sizeof(${field_type}));')
} else {
dec.writeln('\t\t${prefix}${op}${c_name(field.name)} = *(${field_type}*) ${tmp}.data;')
}
}
if field.has_default_expr {
dec.writeln('\t} else {')
@ -757,23 +765,36 @@ fn is_js_prim(typ string) bool {
'u32', 'u64', 'byte']
}
fn (mut g Gen) decode_array(value_type ast.Type, fixed_array_size int) string {
fn (mut g Gen) decode_array(utyp ast.Type, value_type ast.Type, fixed_array_size int, ret_styp string) string {
styp := g.typ(value_type)
fn_name := js_dec_name(styp)
noscan := g.check_noscan(value_type)
fixed_array_str, fixed_array_size_str, res_str, array_free_str := if fixed_array_size > -1 {
// fixed array
'fixed_', '_${fixed_array_size}', '', ''
mut res_str := ''
mut array_free_str := ''
mut fixed_array_idx := ''
mut fixed_array_idx_increment := ''
mut array_element_assign := ''
if utyp.has_flag(.option) {
if fixed_array_size > -1 {
fixed_array_idx += 'int fixed_array_idx = 0;'
array_element_assign += '((${styp}*)res.data)[fixed_array_idx] = val;'
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)}));'
array_free_str += 'array_free(&res.data);'
}
} else {
'', '', 'res = __new_array${noscan}(0, 0, sizeof(${styp}));', 'array_free(&res);'
}
fixed_array_idx, array_element_assign, fixed_array_idx_increment := if fixed_array_size > -1 {
// fixed array
'int fixed_array_idx = 0;', 'res[fixed_array_idx] = val;', 'fixed_array_idx++;'
} else {
'', 'array_push${noscan}((array*)&res, &val);', ''
if fixed_array_size > -1 {
fixed_array_idx += 'int fixed_array_idx = 0;'
array_element_assign += 'res[fixed_array_idx] = val;'
fixed_array_idx_increment += 'fixed_array_idx++;'
} else {
array_element_assign += 'array_push${noscan}((array*)&res, &val);'
res_str += 'res = __new_array${noscan}(0, 0, sizeof(${styp}));'
array_free_str += 'array_free(&res);'
}
}
mut s := ''
@ -784,7 +805,7 @@ fn (mut g Gen) decode_array(value_type ast.Type, fixed_array_size int) string {
${result_name}_${styp} val2 = ${fn_name} ((cJSON *)jsval);
if(val2.is_error) {
${array_free_str}
return *(${result_name}_Array_${fixed_array_str}${styp}${fixed_array_size_str}*)&val2;
return *(${result_name}_${ret_styp}*)&val2;
}
${styp} val = *(${styp}*)val2.data;
'
@ -792,7 +813,7 @@ fn (mut g Gen) decode_array(value_type ast.Type, fixed_array_size int) string {
return '
if(root && !cJSON_IsArray(root) && !cJSON_IsNull(root)) {
return (${result_name}_Array_${fixed_array_str}${styp}${fixed_array_size_str}){.is_error = true, .err = _v_error(string__plus(_SLIT("Json element is not an array: "), tos2((byteptr)cJSON_PrintUnformatted(root)))), .data = {0}};
return (${result_name}_${ret_styp}){.is_error = true, .err = _v_error(string__plus(_SLIT("Json element is not an array: "), tos2((byteptr)cJSON_PrintUnformatted(root)))), .data = {0}};
}
${res_str}
const cJSON *jsval = NULL;
@ -806,21 +827,33 @@ fn (mut g Gen) decode_array(value_type ast.Type, fixed_array_size int) string {
'
}
fn (mut g Gen) encode_array(value_type ast.Type, fixed_array_size int) string {
fn (mut g Gen) encode_array(utyp ast.Type, value_type ast.Type, fixed_array_size int) string {
styp := g.typ(value_type)
fn_name := js_enc_name(styp)
data_str, size_str := if fixed_array_size > -1 {
// fixed array
'', '${fixed_array_size}'
mut data_str := ''
mut size_str := ''
if utyp.has_flag(.option) {
data_str, size_str = if fixed_array_size > -1 {
// fixed array
'(${styp}*)(*(${g.base_type(utyp)}*)val.data)', '${fixed_array_size}'
} else {
'(${styp}*)(*(${g.base_type(utyp)}*)val.data).data', '(*(${g.base_type(utyp)}*)val.data).len'
}
} else {
'.data', 'val.len'
data_str, size_str = if fixed_array_size > -1 {
// fixed array
'(${styp}*)val', '${fixed_array_size}'
} else {
'(${styp}*)val.data', 'val.len'
}
}
return '
o = cJSON_CreateArray();
for (int i = 0; i < ${size_str}; i++){
cJSON_AddItemToArray(o, ${fn_name} ( ((${styp}*)val${data_str})[i] ));
cJSON_AddItemToArray(o, ${fn_name}( (${data_str})[i] ));
}
'
}