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 {
|
fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string {
|
||||||
left := g.unwrap(left_type)
|
left_typ := g.unwrap(left_type)
|
||||||
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
ptr_styp := g.typ(left_typ.typ.set_nr_muls(0))
|
||||||
if left_type in g.generated_eq_fns {
|
if left_type in g.generated_eq_fns {
|
||||||
return ptr_styp
|
return ptr_styp
|
||||||
}
|
}
|
||||||
g.generated_eq_fns << left_type
|
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)
|
elem := g.unwrap(elem_info.elem_type)
|
||||||
size := elem_info.size
|
size := elem_info.size
|
||||||
g.definitions.writeln('static bool ${ptr_styp}_arr_eq(${ptr_styp} a, ${ptr_styp} b); // auto')
|
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)
|
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('static bool ${ptr_styp}_arr_eq(${ptr_styp} a, ${ptr_styp} b) {')
|
||||||
fn_builder.writeln('\tfor (int i = 0; i < ${size}; ++i) {')
|
fn_builder.writeln('\tfor (int i = 0; i < ${size}; ++i) {')
|
||||||
// compare every pair of elements of the two fixed arrays
|
// compare every pair of elements of the two fixed arrays
|
||||||
if elem.sym.kind == .string {
|
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() {
|
} else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() {
|
||||||
eq_fn := g.gen_sumtype_equality_fn(elem.typ)
|
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() {
|
} else if elem.sym.kind == .struct_ && !elem.typ.is_ptr() {
|
||||||
eq_fn := g.gen_struct_equality_fn(elem.typ)
|
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() {
|
} else if elem.sym.kind == .interface_ && !elem.typ.is_ptr() {
|
||||||
eq_fn := g.gen_interface_equality_fn(elem.typ)
|
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() {
|
} else if elem.sym.kind == .array && !elem.typ.is_ptr() {
|
||||||
eq_fn := g.gen_array_equality_fn(elem.typ)
|
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() {
|
} else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() {
|
||||||
eq_fn := g.gen_fixed_array_equality_fn(elem.typ)
|
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() {
|
} else if elem.sym.kind == .map && !elem.typ.is_ptr() {
|
||||||
eq_fn := g.gen_map_equality_fn(elem.typ)
|
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() {
|
} else if elem.sym.kind == .alias && !elem.typ.is_ptr() {
|
||||||
eq_fn := g.gen_alias_equality_fn(elem.typ)
|
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 {
|
} 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 {
|
} 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\treturn false;')
|
||||||
fn_builder.writeln('\t\t}')
|
fn_builder.writeln('\t\t}')
|
||||||
|
|
|
@ -128,8 +128,8 @@ ${enc_fn_dec} {
|
||||||
value_type := g.table.value_type(utyp)
|
value_type := g.table.value_type(utyp)
|
||||||
// If we have `[]Profile`, have to register a Profile en(de)coder first
|
// If we have `[]Profile`, have to register a Profile en(de)coder first
|
||||||
g.gen_json_for_type(value_type)
|
g.gen_json_for_type(value_type)
|
||||||
dec.writeln(g.decode_array(value_type, array_size))
|
dec.writeln(g.decode_array(utyp, value_type, array_size, ret_styp))
|
||||||
enc.writeln(g.encode_array(value_type, array_size))
|
enc.writeln(g.encode_array(utyp, value_type, array_size))
|
||||||
} else if sym.kind == .map {
|
} else if sym.kind == .map {
|
||||||
// Handle maps
|
// Handle maps
|
||||||
m := sym.info as ast.Map
|
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)
|
gen_js_get_opt(dec_name, field_type, styp, tmp, name, mut dec, is_required)
|
||||||
dec.writeln('\tif (jsonroot_${tmp}) {')
|
dec.writeln('\tif (jsonroot_${tmp}) {')
|
||||||
|
|
||||||
if field_sym.kind == .array_fixed {
|
if field.typ.has_flag(.option) {
|
||||||
dec.writeln('\t\tvmemcpy(${prefix}${op}${c_name(field.name)},*(${field_type}*)${tmp}.data,sizeof(${field_type}));')
|
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 {
|
} 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 {
|
if field.has_default_expr {
|
||||||
dec.writeln('\t} else {')
|
dec.writeln('\t} else {')
|
||||||
|
@ -757,23 +765,36 @@ fn is_js_prim(typ string) bool {
|
||||||
'u32', 'u64', 'byte']
|
'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)
|
styp := g.typ(value_type)
|
||||||
fn_name := js_dec_name(styp)
|
fn_name := js_dec_name(styp)
|
||||||
noscan := g.check_noscan(value_type)
|
noscan := g.check_noscan(value_type)
|
||||||
|
|
||||||
fixed_array_str, fixed_array_size_str, res_str, array_free_str := if fixed_array_size > -1 {
|
mut res_str := ''
|
||||||
// fixed array
|
mut array_free_str := ''
|
||||||
'fixed_', '_${fixed_array_size}', '', ''
|
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 {
|
} else {
|
||||||
'', '', 'res = __new_array${noscan}(0, 0, sizeof(${styp}));', 'array_free(&res);'
|
if fixed_array_size > -1 {
|
||||||
}
|
fixed_array_idx += 'int fixed_array_idx = 0;'
|
||||||
|
array_element_assign += 'res[fixed_array_idx] = val;'
|
||||||
fixed_array_idx, array_element_assign, fixed_array_idx_increment := if fixed_array_size > -1 {
|
fixed_array_idx_increment += 'fixed_array_idx++;'
|
||||||
// fixed array
|
} else {
|
||||||
'int fixed_array_idx = 0;', 'res[fixed_array_idx] = val;', 'fixed_array_idx++;'
|
array_element_assign += 'array_push${noscan}((array*)&res, &val);'
|
||||||
} else {
|
res_str += 'res = __new_array${noscan}(0, 0, sizeof(${styp}));'
|
||||||
'', 'array_push${noscan}((array*)&res, &val);', ''
|
array_free_str += 'array_free(&res);'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mut s := ''
|
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);
|
${result_name}_${styp} val2 = ${fn_name} ((cJSON *)jsval);
|
||||||
if(val2.is_error) {
|
if(val2.is_error) {
|
||||||
${array_free_str}
|
${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;
|
${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 '
|
return '
|
||||||
if(root && !cJSON_IsArray(root) && !cJSON_IsNull(root)) {
|
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}
|
${res_str}
|
||||||
const cJSON *jsval = NULL;
|
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)
|
styp := g.typ(value_type)
|
||||||
fn_name := js_enc_name(styp)
|
fn_name := js_enc_name(styp)
|
||||||
|
|
||||||
data_str, size_str := if fixed_array_size > -1 {
|
mut data_str := ''
|
||||||
// fixed array
|
mut size_str := ''
|
||||||
'', '${fixed_array_size}'
|
|
||||||
|
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 {
|
} 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 '
|
return '
|
||||||
o = cJSON_CreateArray();
|
o = cJSON_CreateArray();
|
||||||
for (int i = 0; i < ${size_str}; i++){
|
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