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:
parent
dce65c7f46
commit
b4e8e812fe
46
vlib/json/json_generic_array_test.v
Normal file
46
vlib/json/json_generic_array_test.v
Normal 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
|
||||
}
|
@ -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}')
|
||||
|
@ -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] ));
|
||||
}
|
||||
'
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user