json: fix encode/decode support for generic structs (#6489)
parent
05dcdfd267
commit
1aec041371
|
@ -235,6 +235,25 @@ fn test_nested_type() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Foo<T> {
|
||||||
|
pub:
|
||||||
|
name string
|
||||||
|
data T
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generic_struct() {
|
||||||
|
foo_int := Foo<int>{'bar', 12}
|
||||||
|
foo_enc := json.encode(foo_int)
|
||||||
|
assert foo_enc == '{"name":"bar","data":12}'
|
||||||
|
|
||||||
|
foo_dec := json.decode(Foo<int>, foo_enc) or {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert foo_dec.name == 'bar'
|
||||||
|
assert foo_dec.data == 12
|
||||||
|
}
|
||||||
|
|
||||||
fn test_errors() {
|
fn test_errors() {
|
||||||
invalid_array := fn () {
|
invalid_array := fn () {
|
||||||
data := '{"countries":[{"cities":[{"name":"London"},{"name":"Manchester"}],"name":"UK"},{"cities":{"name":"Donlon"},"name":"KU"}],"users":{"Foo":{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"little foo"},"Boo":{"age":20,"nums":[5,3,1],"lastName":"Smith","IsRegistered":false,"type":4,"pet_animals":"little boo"}},"extra":{"2":{"n1":2,"n2":4,"n3":8,"n4":16},"3":{"n1":3,"n2":9,"n3":27,"n4":81}}}'
|
data := '{"countries":[{"cities":[{"name":"London"},{"name":"Manchester"}],"name":"UK"},{"cities":{"name":"Donlon"},"name":"KU"}],"users":{"Foo":{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"little foo"},"Boo":{"age":20,"nums":[5,3,1],"lastName":"Smith","IsRegistered":false,"type":4,"pet_animals":"little boo"}},"extra":{"2":{"n1":2,"n2":4,"n3":8,"n4":16},"3":{"n1":3,"n2":9,"n3":27,"n4":81}}}'
|
||||||
|
|
|
@ -482,9 +482,9 @@ static inline $opt_el_type __Option_${styp}_popval($styp ch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cc_type returns the Cleaned Concrete Type name, *without ptr*,
|
// TODO: merge cc_type and cc_type2
|
||||||
// i.e. it's always just Cat, not Cat_ptr:
|
// cc_type but without the `struct` prefix
|
||||||
fn (g &Gen) cc_type(t table.Type) string {
|
fn (g &Gen) cc_type2(t table.Type) string {
|
||||||
sym := g.table.get_type_symbol(g.unwrap_generic(t))
|
sym := g.table.get_type_symbol(g.unwrap_generic(t))
|
||||||
mut styp := util.no_dots(sym.name)
|
mut styp := util.no_dots(sym.name)
|
||||||
if sym.kind == .struct_ {
|
if sym.kind == .struct_ {
|
||||||
|
@ -501,6 +501,14 @@ fn (g &Gen) cc_type(t table.Type) string {
|
||||||
styp = styp.replace('<', '_T_').replace('>', '').replace(',', '_')
|
styp = styp.replace('<', '_T_').replace('>', '').replace(',', '_')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return styp
|
||||||
|
}
|
||||||
|
|
||||||
|
// cc_type returns the Cleaned Concrete Type name, *without ptr*,
|
||||||
|
// i.e. it's always just Cat, not Cat_ptr:
|
||||||
|
fn (g &Gen) cc_type(t table.Type) string {
|
||||||
|
sym := g.table.get_type_symbol(g.unwrap_generic(t))
|
||||||
|
mut styp := g.cc_type2(t)
|
||||||
if styp.starts_with('C__') {
|
if styp.starts_with('C__') {
|
||||||
styp = styp[3..]
|
styp = styp[3..]
|
||||||
if sym.kind == .struct_ {
|
if sym.kind == .struct_ {
|
||||||
|
|
|
@ -50,7 +50,8 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
|
||||||
name = util.replace_op(name)
|
name = util.replace_op(name)
|
||||||
}
|
}
|
||||||
if it.is_method {
|
if it.is_method {
|
||||||
name = g.table.get_type_symbol(it.receiver.typ).name + '_' + name
|
name = g.cc_type2(it.receiver.typ) + '_' + name
|
||||||
|
// name = g.table.get_type_symbol(it.receiver.typ).name + '_' + name
|
||||||
}
|
}
|
||||||
if it.language == .c {
|
if it.language == .c {
|
||||||
name = util.no_dots(name)
|
name = util.no_dots(name)
|
||||||
|
@ -336,7 +337,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
// mut receiver_type_name := g.cc_type(node.receiver_type)
|
// mut receiver_type_name := g.cc_type(node.receiver_type)
|
||||||
// mut receiver_type_name := g.typ(node.receiver_type)
|
// mut receiver_type_name := g.typ(node.receiver_type)
|
||||||
typ_sym := g.table.get_type_symbol(g.unwrap_generic(node.receiver_type))
|
typ_sym := g.table.get_type_symbol(g.unwrap_generic(node.receiver_type))
|
||||||
mut receiver_type_name := util.no_dots(typ_sym.name)
|
// mut receiver_type_name := util.no_dots(typ_sym.name)
|
||||||
|
mut receiver_type_name := util.no_dots(g.cc_type2(g.unwrap_generic(node.receiver_type)))
|
||||||
if typ_sym.kind == .interface_ {
|
if typ_sym.kind == .interface_ {
|
||||||
// Speaker_name_table[s._interface_idx].speak(s._object)
|
// Speaker_name_table[s._interface_idx].speak(s._object)
|
||||||
g.write('${c_name(receiver_type_name)}_name_table[')
|
g.write('${c_name(receiver_type_name)}_name_table[')
|
||||||
|
@ -494,7 +496,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
cur_line := g.go_before_stmt(0)
|
cur_line := g.go_before_stmt(0)
|
||||||
if is_json_encode {
|
if is_json_encode {
|
||||||
g.gen_json_for_type(node.args[0].typ)
|
g.gen_json_for_type(node.args[0].typ)
|
||||||
json_type_str = g.table.get_type_symbol(node.args[0].typ).name
|
json_type_str = g.typ(node.args[0].typ)
|
||||||
// `json__encode` => `json__encode_User`
|
// `json__encode` => `json__encode_User`
|
||||||
encode_name := c_name(name) + '_' + util.no_dots(json_type_str)
|
encode_name := c_name(name) + '_' + util.no_dots(json_type_str)
|
||||||
g.writeln('// json.encode')
|
g.writeln('// json.encode')
|
||||||
|
@ -507,7 +509,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
} else {
|
} else {
|
||||||
ast_type := node.args[0].expr as ast.Type
|
ast_type := node.args[0].expr as ast.Type
|
||||||
// `json.decode(User, s)` => json.decode_User(s)
|
// `json.decode(User, s)` => json.decode_User(s)
|
||||||
typ := c_name(g.table.get_type_symbol(ast_type.typ).name)
|
typ := c_name(g.typ(ast_type.typ))
|
||||||
fn_name := c_name(name) + '_' + typ
|
fn_name := c_name(name) + '_' + typ
|
||||||
g.gen_json_for_type(ast_type.typ)
|
g.gen_json_for_type(ast_type.typ)
|
||||||
g.writeln('// json.decode')
|
g.writeln('// json.decode')
|
||||||
|
|
|
@ -37,7 +37,7 @@ fn (mut g Gen) gen_json_for_type(typ table.Type) {
|
||||||
// decode_TYPE funcs receive an actual cJSON* object to decode
|
// decode_TYPE funcs receive an actual cJSON* object to decode
|
||||||
// cJSON_Parse(str) call is added by the compiler
|
// cJSON_Parse(str) call is added by the compiler
|
||||||
// Code gen decoder
|
// Code gen decoder
|
||||||
dec_fn_name := js_dec_name(sym.name)
|
dec_fn_name := js_dec_name(styp)
|
||||||
// Make sure that this optional type actually exists
|
// Make sure that this optional type actually exists
|
||||||
g.register_optional(typ)
|
g.register_optional(typ)
|
||||||
dec_fn_dec := 'Option_$styp ${dec_fn_name}(cJSON* root)'
|
dec_fn_dec := 'Option_$styp ${dec_fn_name}(cJSON* root)'
|
||||||
|
@ -58,7 +58,7 @@ $dec_fn_dec {
|
||||||
g.json_forward_decls.writeln('$dec_fn_dec;')
|
g.json_forward_decls.writeln('$dec_fn_dec;')
|
||||||
// Code gen encoder
|
// Code gen encoder
|
||||||
// encode_TYPE funcs receive an object to encode
|
// encode_TYPE funcs receive an object to encode
|
||||||
enc_fn_name := js_enc_name(sym.name)
|
enc_fn_name := js_enc_name(styp)
|
||||||
enc_fn_dec := 'cJSON* ${enc_fn_name}($styp val)'
|
enc_fn_dec := 'cJSON* ${enc_fn_name}($styp val)'
|
||||||
g.json_forward_decls.writeln('$enc_fn_dec;\n')
|
g.json_forward_decls.writeln('$enc_fn_dec;\n')
|
||||||
enc.writeln('
|
enc.writeln('
|
||||||
|
|
|
@ -237,6 +237,20 @@ fn test_generic_struct() {
|
||||||
// println(x.model.name)
|
// println(x.model.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Foo<T> {
|
||||||
|
pub:
|
||||||
|
data T
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f Foo<int>) value() string {
|
||||||
|
return f.data.str()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generic_struct_method() {
|
||||||
|
foo_int := Foo<int>{2}
|
||||||
|
assert foo_int.value() == '2'
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct Abc{ x int y int z int }
|
struct Abc{ x int y int z int }
|
||||||
|
|
||||||
|
|
|
@ -122,3 +122,12 @@ pub fn (f Any) arr() []Any {
|
||||||
|
|
||||||
return [f]
|
return [f]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use `Any` as a bool
|
||||||
|
pub fn (f Any) bool() bool {
|
||||||
|
match f {
|
||||||
|
bool { return *f }
|
||||||
|
string { return (*f).bool() }
|
||||||
|
else { return false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue