diff --git a/vlib/json/json_encode_enum_test.v b/vlib/json/json_encode_enum_test.v new file mode 100644 index 0000000000..096be2b78e --- /dev/null +++ b/vlib/json/json_encode_enum_test.v @@ -0,0 +1,134 @@ +import json + +[json_as_number] +pub enum MessageType { + error = 1 + warning = 2 + info = 3 + log = 4 +} + +pub enum MessageType2 { + error = 1 + warning = 2 + info = 3 + log = 4 +} + +enum TestEnum { + one = 1 + two +} + +type TestAlias = TestEnum +type TestSum = TestEnum | string +type TestSum2 = MessageType | string +type TestAliasAttr = MessageType + +struct TestStruct { + test []TestEnum + test2 TestEnum + test3 TestAlias + test4 TestSum + test5 MessageType +} + +struct TestStruct2 { + a TestAliasAttr + b TestSum2 + c TestSum2 +} + +struct Test { + ab ?int + a ?MessageType +} + +struct Test2 { + a ?MessageType2 +} + +type TSum = MessageType | string +type TSum2 = MessageType2 | string + +struct Test3 { + a ?TSum +} + +struct Test4 { + a ?TSum2 +} + +fn test_encode_with_enum() { + out := json.encode(TestStruct{ + test: [TestEnum.one, TestEnum.one] + test2: TestEnum.two + test3: TestEnum.one + test4: TestEnum.two + test5: .log + }) + assert out == '{"test":["one","one"],"test2":"two","test3":"one","test4":"two","test5":4}' +} + +fn test_encode_direct_enum() { + assert json.encode(TestEnum.one) == '"one"' +} + +fn test_encode_alias_and_sumtype() { + assert json.decode(TestStruct, '{"test":["one","one"],"test2":"two","test3": "one", "test4": "two", "test5":4}')! == TestStruct{ + test: [.one, .one] + test2: .two + test3: TestAlias(.one) + test4: TestSum('two') + test5: .log + } +} + +fn test_enum_attr() { + assert dump(json.encode(MessageType.log)) == '4' + assert dump(json.encode(MessageType.error)) == '1' +} + +fn test_enum_attr_decode() { + assert json.decode(TestStruct2, '{"a": 1, "b":4, "c": "test"}')! == TestStruct2{ + a: .error + b: MessageType.log + c: 'test' + } +} + +fn test_enum_attr_encode() { + assert json.encode(TestStruct2{ + a: .error + b: MessageType.log + c: 'test' + }) == '{"a":1,"b":4,"c":"test"}' +} + +fn test_option_enum() { + assert dump(json.encode(Test{none, none})) == '{}' + assert dump(json.encode(Test{none, MessageType.log})) == '{"a":4}' + t := dump(json.decode(Test, '{"a":4}')!) + assert t.ab == none + assert t.a? == .log + + t2 := dump(json.decode(Test, '{"a":null}')!) + assert t2.a == none + + assert json.encode(Test2{none}) == '{}' + assert dump(json.encode(Test2{MessageType2.log})) == '{"a":"log"}' + z := dump(json.decode(Test2, '{"a":"log"}')!) + assert z.a? == .log + a := dump(json.decode(Test2, '{"a": null}')!) + assert a.a == none +} + +fn test_option_sumtype_enum() { + assert dump(json.encode(Test3{none})) == '{}' + assert dump(json.encode(Test3{ a: 'foo' })) == '{"a":"foo"}' + assert dump(json.encode(Test3{ a: MessageType.warning })) == '{"a":2}' + + assert dump(json.encode(Test4{none})) == '{}' + assert dump(json.encode(Test4{ a: 'foo' })) == '{"a":"foo"}' + assert dump(json.encode(Test4{ a: MessageType2.warning })) == '{"a":"warning"}' +} diff --git a/vlib/json/json_test.v b/vlib/json/json_test.v index 8de3f9c289..f745091b2b 100644 --- a/vlib/json/json_test.v +++ b/vlib/json/json_test.v @@ -18,7 +18,7 @@ fn test_simple() { x := Employee{'Peter', 28, 95000.5, .worker} s := json.encode(x) // eprintln('Employee x: $s') - assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":2}' + assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":"worker"}' y := json.decode(Employee, s)! // eprintln('Employee y: $y') assert y.name == 'Peter' @@ -95,14 +95,15 @@ fn test_encode_decode_sumtype() { enc := json.encode(game) // eprintln('Encoded Game: $enc') - assert enc == '{"title":"Super Mega Game","player":{"name":"Monke","_type":"Human"},"other":[{"tag":"Pen","_type":"Item"},{"tag":"Cookie","_type":"Item"},1,"Stool",{"_type":"Time","value":${t.unix_time()}}]}' + assert enc == '{"title":"Super Mega Game","player":{"name":"Monke","_type":"Human"},"other":[{"tag":"Pen","_type":"Item"},{"tag":"Cookie","_type":"Item"},"cat","Stool",{"_type":"Time","value":${t.unix_time()}}]}' dec := json.decode(SomeGame, enc)! // eprintln('Decoded Game: $dec') assert game.title == dec.title assert game.player == dec.player - assert (game.other[2] as Animal) == (dec.other[2] as Animal) + assert (game.other[2] as Animal) == .cat + assert dec.other[2] == Entity('cat') assert (game.other[4] as time.Time).unix_time() == (dec.other[4] as time.Time).unix_time() } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 602822d10c..f999dd7a70 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6144,16 +6144,21 @@ fn (mut g Gen) size_of(node ast.SizeOf) { g.write('sizeof(${util.no_dots(styp)})') } -fn (mut g Gen) enum_val(node ast.EnumVal) { - styp := g.typ(g.table.unaliased_type(node.typ)) - if g.pref.translated && node.typ.is_number() { +[inline] +fn (mut g Gen) gen_enum_prefix(typ ast.Type) string { + if g.pref.translated && typ.is_number() { // Mostly in translated code, when C enums are used as ints in switches - g.write('_const_main__${node.val}') + return '_const_main__' } else { - g.write('${styp}__${node.val}') + styp := g.typ(g.table.unaliased_type(typ)) + return '${styp}__' } } +fn (mut g Gen) enum_val(node ast.EnumVal) { + g.write('${g.gen_enum_prefix(node.typ)}${node.val}') +} + fn (mut g Gen) as_cast(node ast.AsCast) { // Make sure the sum type can be cast to this type (the types // are the same), otherwise panic. diff --git a/vlib/v/gen/c/json.v b/vlib/v/gen/c/json.v index b481601ec4..57d463c336 100644 --- a/vlib/v/gen/c/json.v +++ b/vlib/v/gen/c/json.v @@ -26,7 +26,7 @@ import strings fn (mut g Gen) gen_json_for_type(typ ast.Type) { utyp := g.unwrap_generic(typ) sym := g.table.sym(utyp) - if (is_js_prim(sym.name) && !utyp.has_flag(.option)) || sym.kind == .enum_ { + if is_js_prim(sym.name) && !utyp.has_flag(.option) { return } g.json_types << utyp @@ -145,9 +145,11 @@ ${enc_fn_dec} { g.gen_json_for_type(parent_typ) continue } - enc.writeln('\to = cJSON_CreateObject();') if psym.info is ast.Struct { + enc.writeln('\to = cJSON_CreateObject();') g.gen_struct_enc_dec(utyp, psym.info, ret_styp, mut enc, mut dec) + } else if psym.kind == .enum_ { + g.gen_enum_enc_dec(utyp, psym, mut enc, mut dec) } else if psym.kind == .sum_type { verror('json: ${sym.name} aliased sumtypes does not work at the moment') } else { @@ -160,6 +162,8 @@ ${enc_fn_dec} { verror('json: ${sym.name} is not a sumtype') } g.gen_sumtype_enc_dec(utyp, sym, mut enc, mut dec, ret_styp) + } else if sym.kind == .enum_ { + g.gen_enum_enc_dec(utyp, sym, mut enc, mut dec) } else if utyp.has_flag(.option) && sym.info !is ast.Struct { g.gen_option_enc_dec(utyp, mut enc, mut dec) } else { @@ -183,6 +187,73 @@ ${enc_fn_dec} { } } +[inline] +fn (mut g Gen) gen_enum_to_str(utyp ast.Type, sym ast.TypeSymbol, enum_var string, result_var string, ident string, mut enc strings.Builder) { + enum_prefix := g.gen_enum_prefix(utyp.clear_flag(.option)) + enc.writeln('${ident}switch (${enum_var}) {') + for val in (sym.info as ast.Enum).vals { + enc.write_string('${ident}\tcase ${enum_prefix}${val}:\t') + enc.writeln('${result_var} = json__encode_string(_SLIT("${val}")); break;') + } + enc.writeln('${ident}}') +} + +[inline] +fn (mut g Gen) gen_str_to_enum(utyp ast.Type, sym ast.TypeSymbol, val_var string, result_var string, ident string, mut dec strings.Builder) { + enum_prefix := g.gen_enum_prefix(utyp.clear_flag(.option)) + is_option := utyp.has_flag(.option) + for k, val in (sym.info as ast.Enum).vals { + if k == 0 { + dec.write_string('${ident}if (string__eq(_SLIT("${val}"), ${val_var}))\t') + } else { + dec.write_string('${ident}else if (string__eq(_SLIT("${val}"), ${val_var}))\t') + } + if is_option { + base_typ := g.base_type(utyp) + dec.writeln('_option_ok(&(${base_typ}[]){ ${enum_prefix}${val} }, ${result_var}, sizeof(${base_typ}));') + } else { + dec.writeln('${result_var} = ${enum_prefix}${val};') + } + } +} + +[inline] +fn (mut g Gen) is_enum_as_int(sym ast.TypeSymbol) bool { + if enum_decl := g.table.enum_decls[sym.name] { + if _ := enum_decl.attrs.find_first('json_as_number') { + return true + } + } + return false +} + +[inline] +fn (mut g Gen) gen_enum_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc strings.Builder, mut dec strings.Builder) { + is_option := utyp.has_flag(.option) + + if g.is_enum_as_int(sym) { + if is_option { + base_typ := g.typ(utyp.clear_flag(.option)) + enc.writeln('\to = ${js_enc_name('u64')}(*val.data);') + dec.writeln('\t_option_ok(&(${base_typ}[]){ ${js_dec_name('u64')}(root) }, &res, sizeof(${base_typ}));') + } else { + dec.writeln('\tres = ${js_dec_name('u64')}(root);') + enc.writeln('\to = ${js_enc_name('u64')}(val);') + } + } else { + tmp := g.new_tmp_var() + dec.writeln('\tstring ${tmp} = ${js_dec_name('string')}(root);') + if is_option { + g.gen_str_to_enum(utyp, sym, tmp, '&res', '\t', mut dec) + g.gen_enum_to_str(utyp, sym, '*(${g.base_type(utyp)}*)val.data', 'o', '\t\t', mut + enc) + } else { + g.gen_str_to_enum(utyp, sym, tmp, 'res', '\t', mut dec) + g.gen_enum_to_str(utyp, sym, 'val', 'o', '\t', mut enc) + } + } +} + [inline] fn (mut g Gen) gen_option_enc_dec(typ ast.Type, mut enc strings.Builder, mut dec strings.Builder) { enc.writeln('\tif (val.state == 2) {') @@ -191,6 +262,9 @@ fn (mut g Gen) gen_option_enc_dec(typ ast.Type, mut enc strings.Builder, mut dec type_str := g.typ(typ.clear_flag(.option)) encode_name := js_enc_name(type_str) enc.writeln('\to = ${encode_name}(*(${type_str}*)val.data);') + + dec_name := js_dec_name(type_str) + dec.writeln('\t_option_ok(&(${type_str}[]){ ${dec_name}(root) }, &res, sizeof(${type_str}));') } [inline] @@ -200,6 +274,8 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st typ := g.table.type_idxs[sym.name] prefix := if utyp.is_ptr() { '*' } else { '' } field_op := if utyp.is_ptr() { '->' } else { '.' } + is_option := utyp.has_flag(.option) + var_data := if is_option { '(*(${g.base_type(utyp)}*)val.data)' } else { 'val' } // DECODING (inline) $if !json_no_inline_sumtypes ? { @@ -231,20 +307,38 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st g.definitions.writeln('static inline ${sym.cname} ${variant_typ}_to_sumtype_${sym.cname}(${variant_typ}* x);') // ENCODING - enc.writeln('\tif (val${field_op}_typ == ${variant.idx()}) {') + if is_option { + enc.writeln('\tif (${var_data}${field_op}_typ == ${variant.idx()}) {') + } else { + enc.writeln('\tif (val${field_op}_typ == ${variant.idx()}) {') + } $if json_no_inline_sumtypes ? { if variant_sym.kind == .enum_ { - enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name('u64')}(*val${field_op}_${variant_typ}));') + enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name('u64')}(*${var_data}${field_op}_${variant_typ}));') } else if variant_sym.name == 'time.Time' { - enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name('i64')}(val${field_op}_${variant_typ}->_v_unix));') + enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name('i64')}(${var_data}${field_op}_${variant_typ}->_v_unix));') } else { - enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name(variant_typ)}(*val${field_op}_${variant_typ}));') + enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name(variant_typ)}(*${var_data}${field_op}_${variant_typ}));') } } $else { if is_js_prim(variant_typ) { - enc.writeln('\t\to = ${js_enc_name(variant_typ)}(*val${field_op}_${variant_typ});') + enc.writeln('\t\tcJSON_free(o); return ${js_enc_name(variant_typ)}(*${var_data}${field_op}_${variant_typ});') } else if variant_sym.kind == .enum_ { - enc.writeln('\t\to = ${js_enc_name('u64')}(*val${field_op}_${variant_typ});') + if g.is_enum_as_int(variant_sym) { + enc.writeln('\t\tcJSON_free(o); return ${js_enc_name('u64')}(*${var_data}${field_op}_${variant_typ});') + } else { + enc.writeln('\t\tcJSON_free(o);') + tmp2 := g.new_tmp_var() + if utyp.has_flag(.option) { + enc.writeln('\t\tu64 ${tmp2} = *${var_data}${field_op}_${variant_typ};') + g.gen_enum_to_str(variant, variant_sym, tmp2, 'o', '\t\t', mut + enc) + } else { + enc.writeln('\t\tu64 ${tmp2} = *${var_data}${field_op}_${variant_typ};') + g.gen_enum_to_str(variant, variant_sym, tmp2, 'o', '\t\t', mut + enc) + } + } } else if variant_sym.name == 'time.Time' { enc.writeln('\t\tcJSON_AddItemToObject(o, "_type", cJSON_CreateString("${unmangled_variant_name}"));') enc.writeln('\t\tcJSON_AddItemToObject(o, "value", ${js_enc_name('i64')}(val${field_op}_${variant_typ}->_v_unix));') @@ -260,25 +354,38 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st $if json_no_inline_sumtypes ? { dec.writeln('\tif (strcmp("${unmangled_variant_name}", root->child->string) == 0) {') if is_js_prim(variant_typ) { - gen_js_get(variant_typ, tmp, unmangled_variant_name, mut dec, true) + gen_js_get(ret_styp, tmp, unmangled_variant_name, mut dec, true) dec.writeln('\t\t${variant_typ} value = ${js_dec_name(variant_typ)}(jsonroot_${tmp});') } else if variant_sym.kind == .enum_ { - gen_js_get(variant_typ, tmp, unmangled_variant_name, mut dec, true) - dec.writeln('\t\t${variant_typ} value = ${js_dec_name('u64')}(jsonroot_${tmp});') + if g.is_enum_as_int(variant_sym) { + gen_js_get(ret_styp, tmp, unmangled_variant_name, mut dec, true) + dec.writeln('\t\t${variant_typ} value = ${js_dec_name('u64')}(jsonroot_${tmp});') + } else { + gen_js_get(ret_styp, tmp, unmangled_variant_name, mut dec, true) + dec.writeln('\t\t${variant_typ} value;') + tmp2 := g.new_tmp_var() + dec.writeln('\t\tstring ${tmp2} = json__decode_string(jsonroot_${tmp});') + g.gen_enum_to_str(variant, variant_sym, tmp2, 'value', '\t\t', mut + dec) + } } else if variant_sym.name == 'time.Time' { - gen_js_get(variant_typ, tmp, unmangled_variant_name, mut dec, true) + gen_js_get(ret_styp, tmp, unmangled_variant_name, mut dec, true) dec.writeln('\t\t${variant_typ} value = time__unix(${js_dec_name('i64')}(jsonroot_${tmp}));') } else { - gen_js_get_opt(js_dec_name(variant_typ), variant_typ, sym.cname, tmp, - unmangled_variant_name, mut dec, true) + gen_js_get_opt(js_dec_name(variant_typ), variant_typ, ret_styp, tmp, unmangled_variant_name, mut + dec, true) dec.writeln('\t\t${variant_typ} value = *(${variant_typ}*)(${tmp}.data);') } - dec.writeln('\t\tres = ${variant_typ}_to_sumtype_${sym.cname}(&value);') + if is_option { + dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${variant_typ}_to_sumtype_${sym.cname}(&value) }, &res, sizeof(${sym.cname}));') + } else { + dec.writeln('\t\tres = ${variant_typ}_to_sumtype_${ret_styp}(&value);') + } dec.writeln('\t}') } $else { if variant_sym.name == 'time.Time' { dec.writeln('\t\t\tif (strcmp("Time", ${type_var}) == 0) {') - gen_js_get(sym.cname, tmp, 'value', mut dec, true) + gen_js_get(ret_styp, tmp, 'value', mut dec, true) dec.writeln('\t\t\t\t${variant_typ} ${tmp} = time__unix(${js_dec_name('i64')}(jsonroot_${tmp}));') dec.writeln('\t\t\t\t${prefix}res = ${variant_typ}_to_sumtype_${sym.cname}(&${tmp});') dec.writeln('\t\t\t}') @@ -325,7 +432,11 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st last_number_type = var_t dec.writeln('\t\tif (cJSON_IsNumber(root)) {') dec.writeln('\t\t\t${var_t} value = ${js_dec_name('u64')}(root);') - dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value);') + if utyp.has_flag(.option) { + dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}(&value) }, &${prefix}res, sizeof(${sym.cname}));') + } else { + dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value);') + } dec.writeln('\t\t}') } @@ -337,7 +448,11 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st string_is_met = true dec.writeln('\t\tif (cJSON_IsString(root)) {') dec.writeln('\t\t\t${var_t} value = ${js_dec_name(var_t)}(root);') - dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value);') + if utyp.has_flag(.option) { + dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}(&value) }, &${prefix}res, sizeof(${sym.cname}));') + } else { + dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value);') + } dec.writeln('\t\t}') } @@ -437,12 +552,36 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st dec.writeln('\t}') } else if field_sym.kind == .enum_ { tmp := g.new_tmp_var() - gen_js_get(styp, tmp, name, mut dec, is_required) - dec.writeln('\tif (jsonroot_${tmp}) {') - dec.writeln('\t\t${prefix}${op}${c_name(field.name)} = json__decode_u64(jsonroot_${tmp});') + is_option_field := field.typ.has_flag(.option) + if field.typ.has_flag(.option) { + gen_js_get_opt(js_dec_name(field_type), field_type, styp, tmp, name, mut + dec, true) + dec.writeln('\tif (jsonroot_${tmp} && !cJSON_IsNull(jsonroot_${tmp})) {') + } else { + gen_js_get(styp, tmp, name, mut dec, is_required) + dec.writeln('\tif (jsonroot_${tmp}) {') + } + if g.is_enum_as_int(field_sym) { + if is_option_field { + base_typ := g.base_type(field.typ) + dec.writeln('\t\t_option_ok(&(${base_typ}[]) { ${js_dec_name('u64')}(jsonroot_${tmp}) }, &${prefix}${op}${c_name(field.name)}, sizeof(${base_typ}));') + } else { + dec.writeln('\t\t${prefix}${op}${c_name(field.name)} = ${js_dec_name('u64')}(jsonroot_${tmp});') + } + } else { + if is_option_field { + base_typ := g.base_type(field.typ) + dec.writeln('\t\t_option_ok(&(${base_typ}[]) { *(${base_typ}*)((${g.typ(field.typ)}*)${tmp}.data)->data }, &${prefix}${op}${c_name(field.name)}, sizeof(${base_typ}));') + } else { + tmp2 := g.new_tmp_var() + dec.writeln('\t\tstring ${tmp2} = json__decode_string(jsonroot_${tmp});') + g.gen_str_to_enum(field.typ, field_sym, tmp2, '${prefix}${op}${c_name(field.name)}', + '\t\t', mut dec) + } + } if field.has_default_expr { dec.writeln('\t} else {') - dec.writeln('\t\t${prefix}.${c_name(field.name)} = ${g.expr_string(field.default_expr)};') + dec.writeln('\t\t${prefix}${op}${c_name(field.name)} = ${g.expr_string(field.default_expr)};') } dec.writeln('\t}') } else if field_sym.name == 'time.Time' { @@ -507,8 +646,9 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st } else { 'val' } - if field.typ.has_flag(.option) { - enc.writeln('\tif (val${op}${c_name(field.name)}.state != 2)') + is_option := field.typ.has_flag(.option) + if is_option { + enc.writeln('\tif (val${op}${c_name(field.name)}.state != 2) {') } if is_omit_empty { enc.writeln('\t if (val${op}${c_name(field.name)} != ${g.type_default(field.typ)})') @@ -520,7 +660,29 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st } } if field_sym.kind == .enum_ { - enc.writeln('\tcJSON_AddItemToObject(o, "${name}", json__encode_u64(${prefix_enc}${op}${c_name(field.name)}));\n') + if g.is_enum_as_int(field_sym) { + if field.typ.has_flag(.option) { + enc.writeln('\tcJSON_AddItemToObject(o, "${name}", json__encode_u64(*${prefix_enc}${op}${c_name(field.name)}.data));\n') + } else { + enc.writeln('\tcJSON_AddItemToObject(o, "${name}", json__encode_u64(${prefix_enc}${op}${c_name(field.name)}));\n') + } + } else { + if field.typ.has_flag(.option) { + enc.writeln('\t{') + enc.writeln('\t\tcJSON *enum_val;') + g.gen_enum_to_str(field.typ, field_sym, '*(${g.base_type(field.typ)}*)${prefix_enc}${op}${c_name(field.name)}.data', + 'enum_val', '\t\t', mut enc) + enc.writeln('\t\tcJSON_AddItemToObject(o, "${name}", enum_val);') + enc.writeln('\t}') + } else { + enc.writeln('\t{') + enc.writeln('\t\tcJSON *enum_val;') + g.gen_enum_to_str(field.typ, field_sym, '${prefix_enc}${op}${c_name(field.name)}', + 'enum_val', '\t\t', mut enc) + enc.writeln('\t\tcJSON_AddItemToObject(o, "${name}", enum_val);') + enc.writeln('\t}') + } + } } else { if field_sym.name == 'time.Time' { // time struct requires special treatment @@ -542,6 +704,10 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st } } } + + if is_option { + enc.writeln('\t} // !none') + } } } @@ -557,7 +723,7 @@ fn gen_js_get(styp string, tmp string, name string, mut dec strings.Builder, is_ fn gen_js_get_opt(dec_name string, field_type string, styp string, tmp string, name string, mut dec strings.Builder, is_required bool) { gen_js_get(styp, tmp, name, mut dec, is_required) value_field_type := field_type.replace('*', '_ptr') - dec.writeln('\t${result_name}_${value_field_type.replace('*', '_ptr')} ${tmp};') + dec.writeln('\t${result_name}_${value_field_type.replace('*', '_ptr')} ${tmp} = {0};') dec.writeln('\tif (jsonroot_${tmp}) {') dec.writeln('\t\t${tmp} = ${dec_name}(jsonroot_${tmp});') dec.writeln('\t\tif (${tmp}.is_error) {')