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() {
|
||||
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}}}'
|
||||
|
|
|
@ -482,9 +482,9 @@ static inline $opt_el_type __Option_${styp}_popval($styp ch) {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// TODO: merge cc_type and cc_type2
|
||||
// cc_type but without the `struct` prefix
|
||||
fn (g &Gen) cc_type2(t table.Type) string {
|
||||
sym := g.table.get_type_symbol(g.unwrap_generic(t))
|
||||
mut styp := util.no_dots(sym.name)
|
||||
if sym.kind == .struct_ {
|
||||
|
@ -501,6 +501,14 @@ fn (g &Gen) cc_type(t table.Type) string {
|
|||
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__') {
|
||||
styp = styp[3..]
|
||||
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)
|
||||
}
|
||||
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 {
|
||||
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.typ(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_ {
|
||||
// Speaker_name_table[s._interface_idx].speak(s._object)
|
||||
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)
|
||||
if is_json_encode {
|
||||
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`
|
||||
encode_name := c_name(name) + '_' + util.no_dots(json_type_str)
|
||||
g.writeln('// json.encode')
|
||||
|
@ -507,7 +509,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||
} else {
|
||||
ast_type := node.args[0].expr as ast.Type
|
||||
// `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
|
||||
g.gen_json_for_type(ast_type.typ)
|
||||
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
|
||||
// cJSON_Parse(str) call is added by the compiler
|
||||
// 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
|
||||
g.register_optional(typ)
|
||||
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;')
|
||||
// Code gen encoder
|
||||
// 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)'
|
||||
g.json_forward_decls.writeln('$enc_fn_dec;\n')
|
||||
enc.writeln('
|
||||
|
|
|
@ -237,6 +237,20 @@ fn test_generic_struct() {
|
|||
// 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 }
|
||||
|
||||
|
|
|
@ -122,3 +122,12 @@ pub fn (f Any) arr() []Any {
|
|||
|
||||
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