json: fix struct field default value support (#14304)
parent
ca00b59b3f
commit
11bdb04d0c
|
@ -71,6 +71,11 @@ fn decode_i64(root &C.cJSON) i64 {
|
|||
return i64(root.valuedouble) // i64 is double in C
|
||||
}
|
||||
|
||||
// TODO: remove when `byte` is removed
|
||||
fn decode_byte(root &C.cJSON) byte {
|
||||
return byte(decode_u8(root))
|
||||
}
|
||||
|
||||
fn decode_u8(root &C.cJSON) u8 {
|
||||
if isnil(root) {
|
||||
return u8(0)
|
||||
|
@ -132,8 +137,6 @@ fn decode_string(root &C.cJSON) string {
|
|||
if isnil(root.valuestring) {
|
||||
return ''
|
||||
}
|
||||
// println('decode string valuestring="$root.valuestring"')
|
||||
// return tos(root.valuestring, _strlen(root.valuestring))
|
||||
return unsafe { tos_clone(&u8(root.valuestring)) } // , _strlen(root.valuestring))
|
||||
}
|
||||
|
||||
|
@ -145,6 +148,7 @@ fn decode_bool(root &C.cJSON) bool {
|
|||
}
|
||||
|
||||
// ///////////////////
|
||||
|
||||
fn encode_int(val int) &C.cJSON {
|
||||
return C.cJSON_CreateNumber(val)
|
||||
}
|
||||
|
@ -161,6 +165,11 @@ fn encode_i64(val i64) &C.cJSON {
|
|||
return C.cJSON_CreateNumber(val)
|
||||
}
|
||||
|
||||
// TODO: remove when `byte` is removed
|
||||
fn encode_byte(root byte) &C.cJSON {
|
||||
return encode_u8(u8(root))
|
||||
}
|
||||
|
||||
fn encode_u8(val u8) &C.cJSON {
|
||||
return C.cJSON_CreateNumber(val)
|
||||
}
|
||||
|
|
|
@ -27,6 +27,25 @@ fn test_simple() ? {
|
|||
assert y.title == .worker
|
||||
}
|
||||
|
||||
const currency_id = 'cconst'
|
||||
|
||||
struct Price {
|
||||
net f64
|
||||
currency_id string [json: currencyId] = currency_id
|
||||
}
|
||||
|
||||
fn test_field_with_default_expr() ? {
|
||||
data := '[{"net":1},{"net":2,"currencyId":"cjson"}]'
|
||||
prices := json.decode([]Price, data)?
|
||||
assert prices == [Price{
|
||||
net: 1
|
||||
currency_id: 'cconst'
|
||||
}, Price{
|
||||
net: 2
|
||||
currency_id: 'cjson'
|
||||
}]
|
||||
}
|
||||
|
||||
fn test_decode_top_level_array() {
|
||||
s := '[{"name":"Peter", "age": 29}, {"name":"Bob", "age":31}]'
|
||||
x := json.decode([]Employee, s) or { panic(err) }
|
||||
|
@ -454,3 +473,11 @@ fn test_encode_sumtype_defined_ahead() {
|
|||
println(ret)
|
||||
assert ret == '{"value":0,"_type":"GPScale"}'
|
||||
}
|
||||
|
||||
struct StByteArray {
|
||||
ba []byte
|
||||
}
|
||||
|
||||
fn test_byte_array() {
|
||||
assert json.encode(StByteArray{ ba: [byte(1), 2, 3, 4, 5] }) == '{"ba":[1,2,3,4,5]}'
|
||||
}
|
||||
|
|
|
@ -79,7 +79,6 @@ pub fn pref_arch_to_table_language(pref_arch pref.Arch) Language {
|
|||
// * Table.type_kind(typ) not TypeSymbol.kind.
|
||||
// Each TypeSymbol is entered into `Table.types`.
|
||||
// See also: Table.sym.
|
||||
|
||||
[minify]
|
||||
pub struct TypeSymbol {
|
||||
pub:
|
||||
|
|
|
@ -7,16 +7,21 @@ import v.ast
|
|||
import v.util
|
||||
import strings
|
||||
|
||||
// TODO replace with comptime code generation.
|
||||
// TODO remove cJSON dependency.
|
||||
// OLD: User decode_User(string js) {
|
||||
// now it's
|
||||
// TODO: replace with comptime code generation.
|
||||
// TODO: remove cJSON dependency.
|
||||
|
||||
// Old:
|
||||
// `User decode_User(string js) {`
|
||||
// now it's:
|
||||
// ```
|
||||
// User decode_User(cJSON* root) {
|
||||
// User res;
|
||||
// res.name = decode_string(js_get(root, "name"));
|
||||
// res.profile = decode_Profile(js_get(root, "profile"));
|
||||
// return res;
|
||||
// }
|
||||
// ```
|
||||
|
||||
// Codegen json_decode/encode funcs
|
||||
fn (mut g Gen) gen_json_for_type(typ ast.Type) {
|
||||
utyp := g.unwrap_generic(typ).set_nr_muls(0)
|
||||
|
@ -40,7 +45,6 @@ fn (mut g Gen) gen_jsons() {
|
|||
sym := g.table.sym(utyp)
|
||||
styp := g.typ(utyp)
|
||||
g.register_optional(utyp)
|
||||
// println('gen_json_for_type($sym.name)')
|
||||
// decode_TYPE funcs receive an actual cJSON* object to decode
|
||||
// cJSON_Parse(str) call is added by the compiler
|
||||
// Codegen decoder
|
||||
|
@ -116,7 +120,6 @@ $enc_fn_dec {
|
|||
g.gen_json_for_type(value_type)
|
||||
dec.writeln(g.decode_array(value_type))
|
||||
enc.writeln(g.encode_array(value_type))
|
||||
// enc += g.encode_array(t)
|
||||
} else if sym.kind == .map {
|
||||
// Handle maps
|
||||
m := sym.info as ast.Map
|
||||
|
@ -156,7 +159,6 @@ $enc_fn_dec {
|
|||
g.gen_struct_enc_dec(sym.info, styp, mut enc, mut dec)
|
||||
}
|
||||
// cJSON_delete
|
||||
// p.cgen.fns << '$dec return opt_ok(res); \n}'
|
||||
dec.writeln('\t${option_name}_$styp ret;')
|
||||
dec.writeln('\topt_ok2(&res, ($option_name*)&ret, sizeof(res));')
|
||||
dec.writeln('\treturn ret;\n}')
|
||||
|
@ -396,17 +398,41 @@ fn (mut g Gen) gen_struct_enc_dec(type_info ast.TypeInfo, styp string, mut enc s
|
|||
if is_js_prim(field_type) {
|
||||
tmp := g.new_tmp_var()
|
||||
gen_js_get(styp, tmp, name, mut dec, is_required)
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\tif (jsonroot_$tmp) {')
|
||||
}
|
||||
dec.writeln('\tres.${c_name(field.name)} = $dec_name (jsonroot_$tmp);')
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\t} else {')
|
||||
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
|
||||
dec.writeln('\t}')
|
||||
}
|
||||
} else if field_sym.kind == .enum_ {
|
||||
tmp := g.new_tmp_var()
|
||||
gen_js_get(styp, tmp, name, mut dec, is_required)
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\tif (jsonroot_$tmp) {')
|
||||
}
|
||||
dec.writeln('\tres.${c_name(field.name)} = json__decode_u64(jsonroot_$tmp);')
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\t} else {')
|
||||
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
|
||||
dec.writeln('\t}')
|
||||
}
|
||||
} else if field_sym.name == 'time.Time' {
|
||||
// time struct requires special treatment
|
||||
// it has to be decoded from a unix timestamp number
|
||||
tmp := g.new_tmp_var()
|
||||
gen_js_get(styp, tmp, name, mut dec, is_required)
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\tif (jsonroot_$tmp) {')
|
||||
}
|
||||
dec.writeln('\tres.${c_name(field.name)} = time__unix(json__decode_u64(jsonroot_$tmp));')
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\t} else {')
|
||||
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
|
||||
dec.writeln('\t}')
|
||||
}
|
||||
} else if field_sym.kind == .alias {
|
||||
alias := field_sym.info as ast.Alias
|
||||
parent_type := g.typ(alias.parent_type)
|
||||
|
@ -414,17 +440,41 @@ fn (mut g Gen) gen_struct_enc_dec(type_info ast.TypeInfo, styp string, mut enc s
|
|||
if is_js_prim(parent_type) {
|
||||
tmp := g.new_tmp_var()
|
||||
gen_js_get(styp, tmp, name, mut dec, is_required)
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\tif (jsonroot_$tmp) {')
|
||||
}
|
||||
dec.writeln('\tres.${c_name(field.name)} = $parent_dec_name (jsonroot_$tmp);')
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\t} else {')
|
||||
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
|
||||
dec.writeln('\t}')
|
||||
}
|
||||
} else {
|
||||
g.gen_json_for_type(field.typ)
|
||||
tmp := g.new_tmp_var()
|
||||
gen_js_get_opt(dec_name, field_type, styp, tmp, name, mut dec, is_required)
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\tif (jsonroot_$tmp) {')
|
||||
}
|
||||
dec.writeln('\tres.${c_name(field.name)} = *($field_type*) ${tmp}.data;')
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\t} else {')
|
||||
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
|
||||
dec.writeln('\t}')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tmp := g.new_tmp_var()
|
||||
gen_js_get_opt(dec_name, field_type, styp, tmp, name, mut dec, is_required)
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\tif (jsonroot_$tmp) {')
|
||||
}
|
||||
dec.writeln('\tres.${c_name(field.name)} = *($field_type*) ${tmp}.data;')
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\t} else {')
|
||||
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
|
||||
dec.writeln('\t}')
|
||||
}
|
||||
}
|
||||
}
|
||||
// Encoding
|
||||
|
|
|
@ -40,11 +40,6 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||
return ast.StructDecl{}
|
||||
}
|
||||
mut name := p.check_name()
|
||||
// defer {
|
||||
// if name.contains('App') {
|
||||
// println('end of struct decl $name')
|
||||
// }
|
||||
// }
|
||||
if name.len == 1 && name[0].is_capital() {
|
||||
p.error_with_pos('single letter capital names are reserved for generic template types.',
|
||||
name_pos)
|
||||
|
@ -328,9 +323,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||
p.error_with_pos('invalid recursive struct `$orig_name`', name_pos)
|
||||
return ast.StructDecl{}
|
||||
}
|
||||
mut ret := 0
|
||||
// println('reg type symbol $name mod=$p.mod')
|
||||
ret = p.table.register_sym(t)
|
||||
mut ret := p.table.register_sym(t)
|
||||
// allow duplicate c struct declarations
|
||||
if ret == -1 && language != .c {
|
||||
p.error_with_pos('cannot register struct `$name`, another type with this name exists',
|
||||
|
|
Loading…
Reference in New Issue