json2: decode refactor/fix (#16588)

This commit is contained in:
Hitalo Souza 2022-12-05 11:58:44 -03:00 committed by GitHub
parent 50110d4c19
commit 5288c613ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 251 additions and 243 deletions

View File

@ -58,8 +58,8 @@ fn test_int() {
assert sample_data['f32'] or { 0 }.int() == 2 assert sample_data['f32'] or { 0 }.int() == 2
assert sample_data['f64'] or { 0 }.int() == 1 assert sample_data['f64'] or { 0 }.int() == 1
assert json.Any(true).int() == 1 assert json.Any(true).int() == 1
assert json.Any('123').int() == 123
// invalid conversions // invalid conversions
assert json.Any('123').int() == 0
assert sample_data['null'] or { 0 }.int() == 0 assert sample_data['null'] or { 0 }.int() == 0
assert sample_data['arr'] or { 0 }.int() == 0 assert sample_data['arr'] or { 0 }.int() == 0
assert sample_data['obj'] or { 0 }.int() == 0 assert sample_data['obj'] or { 0 }.int() == 0
@ -72,8 +72,8 @@ fn test_i64() {
assert sample_data['f32'] or { 0 }.i64() == 2 assert sample_data['f32'] or { 0 }.i64() == 2
assert sample_data['f64'] or { 0 }.i64() == 1 assert sample_data['f64'] or { 0 }.i64() == 1
assert json.Any(true).i64() == 1 assert json.Any(true).i64() == 1
assert json.Any('123').i64() == 123
// invalid conversions // invalid conversions
assert json.Any('123').i64() == 0
assert sample_data['null'] or { 0 }.i64() == 0 assert sample_data['null'] or { 0 }.i64() == 0
assert sample_data['arr'] or { 0 }.i64() == 0 assert sample_data['arr'] or { 0 }.i64() == 0
assert sample_data['obj'] or { 0 }.i64() == 0 assert sample_data['obj'] or { 0 }.i64() == 0

View File

@ -59,7 +59,7 @@ pub fn (err UnknownTokenError) msg() string {
} }
struct Parser { struct Parser {
mut: pub mut:
scanner &Scanner = unsafe { nil } scanner &Scanner = unsafe { nil }
p_tok Token p_tok Token
tok Token tok Token

View File

@ -1,48 +1,48 @@
module json2 import x.json2 as json
fn test_raw_decode_string() { fn test_raw_decode_string() {
str := raw_decode('"Hello!"')! str := json.raw_decode('"Hello!"')!
assert str.str() == 'Hello!' assert str.str() == 'Hello!'
} }
fn test_raw_decode_string_escape() { fn test_raw_decode_string_escape() {
jstr := raw_decode('"\u001b"')! jstr := json.raw_decode('"\u001b"')!
str := jstr.str() str := jstr.str()
assert str.len == 1 assert str.len == 1
assert str[0] == 27 assert str[0] == 27
} }
fn test_raw_decode_number() { fn test_raw_decode_number() {
num := raw_decode('123')! num := json.raw_decode('123')!
assert num.int() == 123 assert num.int() == 123
} }
fn test_raw_decode_array() { fn test_raw_decode_array() {
raw_arr := raw_decode('["Foo", 1]')! raw_arr := json.raw_decode('["Foo", 1]')!
arr := raw_arr.arr() arr := raw_arr.arr()
assert arr[0] or { 0 }.str() == 'Foo' assert arr[0] or { 0 }.str() == 'Foo'
assert arr[1] or { 0 }.int() == 1 assert arr[1] or { 0 }.int() == 1
} }
fn test_raw_decode_bool() { fn test_raw_decode_bool() {
bol := raw_decode('false')! bol := json.raw_decode('false')!
assert bol.bool() == false assert bol.bool() == false
} }
fn test_raw_decode_map() { fn test_raw_decode_map() {
raw_mp := raw_decode('{"name":"Bob","age":20}')! raw_mp := json.raw_decode('{"name":"Bob","age":20}')!
mp := raw_mp.as_map() mp := raw_mp.as_map()
assert mp['name'] or { 0 }.str() == 'Bob' assert mp['name'] or { 0 }.str() == 'Bob'
assert mp['age'] or { 0 }.int() == 20 assert mp['age'] or { 0 }.int() == 20
} }
fn test_raw_decode_null() { fn test_raw_decode_null() {
nul := raw_decode('null')! nul := json.raw_decode('null')!
assert nul is Null assert nul is json.Null
} }
fn test_raw_decode_invalid() { fn test_raw_decode_invalid() {
raw_decode('1z') or { json.raw_decode('1z') or {
assert err.msg() == '[x.json2] invalid token `z` (0:17)' assert err.msg() == '[x.json2] invalid token `z` (0:17)'
return return
} }
@ -50,25 +50,25 @@ fn test_raw_decode_invalid() {
} }
fn test_raw_decode_string_with_dollarsign() { fn test_raw_decode_string_with_dollarsign() {
str := raw_decode(r'"Hello $world"')! str := json.raw_decode(r'"Hello $world"')!
assert str.str() == r'Hello $world' assert str.str() == r'Hello $world'
} }
fn test_raw_decode_map_with_whitespaces() { fn test_raw_decode_map_with_whitespaces() {
raw_mp := raw_decode(' \n\t{"name":"Bob","age":20}\n\t')! raw_mp := json.raw_decode(' \n\t{"name":"Bob","age":20}\n\t')!
mp := raw_mp.as_map() mp := raw_mp.as_map()
assert mp['name'] or { 0 }.str() == 'Bob' assert mp['name'] or { 0 }.str() == 'Bob'
assert mp['age'] or { 0 }.int() == 20 assert mp['age'] or { 0 }.int() == 20
} }
fn test_nested_array_object() { fn test_nested_array_object() {
mut parser := new_parser(r'[[[[[],[],[]]]],{"Test":{}},[[]]]', false) mut parser := json.new_parser(r'[[[[[],[],[]]]],{"Test":{}},[[]]]', false)
decoded := parser.decode()! decoded := parser.decode()!
assert parser.n_level == 0 assert parser.n_level == 0
} }
fn test_raw_decode_map_invalid() { fn test_raw_decode_map_invalid() {
raw_decode('{"name","Bob","age":20}') or { json.raw_decode('{"name","Bob","age":20}') or {
assert err.msg() == '[x.json2] invalid token `comma`, expecting `colon` (0:5)' assert err.msg() == '[x.json2] invalid token `comma`, expecting `colon` (0:5)'
return return
} }
@ -76,7 +76,7 @@ fn test_raw_decode_map_invalid() {
} }
fn test_raw_decode_array_invalid() { fn test_raw_decode_array_invalid() {
raw_decode('["Foo", 1,}') or { json.raw_decode('["Foo", 1,}') or {
assert err.msg() == '[x.json2] invalid token `rcbr` (0:5)' assert err.msg() == '[x.json2] invalid token `rcbr` (0:5)'
return return
} }

View File

@ -12,42 +12,11 @@ mut:
sx64 i64 sx64 i64
} }
pub fn (mut x IntegerValues) from_json(f json2.Any) {
fm := f.as_map()
if v := fm['ux8'] {
x.ux8 = u8(v.u64())
}
if v := fm['ux16'] {
x.ux16 = u16(v.u64())
}
if v := fm['ux32'] {
x.ux32 = u32(v.u64())
}
if v := fm['ux64'] {
x.ux64 = v.u64()
}
//
if v := fm['sx8'] {
x.sx8 = i8(v.i64())
}
if v := fm['sx16'] {
x.sx16 = i16(v.i64())
}
if v := fm['sx32'] {
x.sx32 = int(v.i64())
}
if v := fm['sx64'] {
x.sx64 = v.i64()
}
}
fn test_all_primitive_integer_types_are_encodable_and_decodable() { fn test_all_primitive_integer_types_are_encodable_and_decodable() {
f := IntegerValues{1, 2, 3, 4, -1, -2, -3, -4} f := IntegerValues{1, 2, 3, 4, -1, -2, -3, -4}
s := json2.encode[IntegerValues](f) s := json2.encode[IntegerValues](f)
dump(s)
assert s == '{"ux8":1,"ux16":2,"ux32":3,"ux64":4,"sx8":-1,"sx16":-2,"sx32":-3,"sx64":-4}' assert s == '{"ux8":1,"ux16":2,"ux32":3,"ux64":4,"sx8":-1,"sx16":-2,"sx32":-3,"sx64":-4}'
x := json2.decode[IntegerValues](s)! x := json2.decode[IntegerValues](s)!
dump(x)
assert x == f assert x == f
println('done') println('done')
} }

View File

@ -4,6 +4,7 @@
module json2 module json2
import strings import strings
import time
// Decodes a JSON string into an `Any` type. Returns an option. // Decodes a JSON string into an `Any` type. Returns an option.
pub fn raw_decode(src string) !Any { pub fn raw_decode(src string) !Any {
@ -19,9 +20,41 @@ pub fn fast_raw_decode(src string) !Any {
// decode is a generic function that decodes a JSON string into the target type. // decode is a generic function that decodes a JSON string into the target type.
pub fn decode[T](src string) !T { pub fn decode[T](src string) !T {
res := raw_decode(src)! res := raw_decode(src)!.as_map()
mut typ := T{} mut typ := T{}
typ.from_json(res) $for field in T.fields {
$if field.typ is u8 {
typ.$(field.name) = u8(res[field.name]!.u64())
} $else $if field.typ is u16 {
typ.$(field.name) = u16(res[field.name]!.u64())
} $else $if field.typ is u32 {
typ.$(field.name) = u32(res[field.name]!.u64())
} $else $if field.typ is u64 {
typ.$(field.name) = res[field.name]!.u64()
} $else $if field.typ is int {
typ.$(field.name) = res[field.name]!.int()
} $else $if field.typ is i8 {
typ.$(field.name) = i8(res[field.name]!.i64())
} $else $if field.typ is i16 {
typ.$(field.name) = i16(res[field.name]!.i64())
} $else $if field.typ is i32 {
// typ.$(field.name) = res[field.name]!.i32()
} $else $if field.typ is i64 {
typ.$(field.name) = res[field.name]!.i64()
} $else $if field.typ is f32 {
typ.$(field.name) = res[field.name]!.f32()
} $else $if field.typ is f64 {
typ.$(field.name) = res[field.name]!.f64()
} $else $if field.typ is bool {
typ.$(field.name) = res[field.name]!.bool()
} $else $if field.typ is string {
typ.$(field.name) = res[field.name]!.str()
} $else $if field.typ is time.Time {
// typ.$(field.name) = res[field.name]!.str()
} $else {
return error("The type of `${field.name}` can't be decoded. Please open an issue at https://github.com/vlang/v/issues/new/choose")
}
}
return typ return typ
} }
@ -41,57 +74,133 @@ pub fn encode[T](val T) string {
// int uses `Any` as an integer. // int uses `Any` as an integer.
pub fn (f Any) int() int { pub fn (f Any) int() int {
match f { match f {
int { return f } int {
i8, i16, i64, u8, u16, u32, u64, f32, f64, bool { return int(f) } return f
else { return 0 } }
i8, i16, i64, u8, u16, u32, u64, f32, f64, bool {
return int(f)
}
string {
if f == 'false' || f == 'true' {
return int(f.bool())
}
return f.int()
}
else {
return 0
}
} }
} }
// i64 uses `Any` as a 64-bit integer. // i64 uses `Any` as a 64-bit integer.
pub fn (f Any) i64() i64 { pub fn (f Any) i64() i64 {
match f { match f {
i64 { return f } i64 {
i8, i16, int, u8, u16, u32, u64, f32, f64, bool { return i64(f) } return f
else { return 0 } }
i8, i16, int, u8, u16, u32, u64, f32, f64, bool {
return i64(f)
}
string {
if f == 'false' || f == 'true' {
return i64(f.bool())
}
return f.i64()
}
else {
return 0
}
} }
} }
// u64 uses `Any` as a 64-bit unsigned integer. // u64 uses `Any` as a 64-bit unsigned integer.
pub fn (f Any) u64() u64 { pub fn (f Any) u64() u64 {
match f { match f {
u64 { return f } u64 {
u8, u16, u32, i8, i16, int, i64, f32, f64, bool { return u64(f) } return f
else { return 0 } }
u8, u16, u32, i8, i16, int, i64, f32, f64, bool {
return u64(f)
}
string {
if f == 'false' || f == 'true' {
return u64(f.bool())
}
return f.u64()
}
else {
return 0
}
} }
} }
// f32 uses `Any` as a 32-bit float. // f32 uses `Any` as a 32-bit float.
pub fn (f Any) f32() f32 { pub fn (f Any) f32() f32 {
match f { match f {
f32 { return f } f32 {
bool, i8, i16, int, i64, u8, u16, u32, u64, f64 { return f32(f) } return f
else { return 0.0 } }
bool, i8, i16, int, i64, u8, u16, u32, u64, f64 {
return f32(f)
}
string {
if f == 'false' || f == 'true' {
return f32(f.bool())
}
return f.f32()
}
else {
return 0.0
}
} }
} }
// f64 uses `Any` as a 64-bit float. // f64 uses `Any` as a 64-bit float.
pub fn (f Any) f64() f64 { pub fn (f Any) f64() f64 {
match f { match f {
f64 { return f } f64 {
i8, i16, int, i64, u8, u16, u32, u64, f32 { return f64(f) } return f
else { return 0.0 } }
i8, i16, int, i64, u8, u16, u32, u64, f32 {
return f64(f)
}
string {
if f == 'false' || f == 'true' {
return f64(f.bool())
}
return f.f64()
}
else {
return 0.0
}
} }
} }
// bool uses `Any` as a bool. // bool uses `Any` as a bool.
pub fn (f Any) bool() bool { pub fn (f Any) bool() bool {
match f { match f {
bool { return f } bool {
string { return f.bool() } return f
i8, i16, int, i64 { return i64(f) != 0 } }
u8, u16, u32, u64 { return u64(f) != 0 } string {
f32, f64 { return f64(f) != 0.0 } if f.len > 0 {
else { return false } return f != '0' && f != '0.0' && f != 'false'
} else {
return false
}
}
i8, i16, int, i64 {
return i64(f) != 0
}
u8, u16, u32, u64 {
return u64(f) != 0
}
f32, f64 {
return f64(f) != 0.0
}
else {
return false
}
} }
} }

View File

@ -44,14 +44,6 @@ fn (e Employee) to_json() string {
return mp.str() return mp.str()
} }
fn (mut e Employee) from_json(any json.Any) {
mp := any.as_map()
e.name = mp['name'] or { json.Any('') }.str()
e.age = mp['age'] or { json.Any(0) }.int()
e.salary = mp['salary'] or { json.Any(0) }.f32()
e.title = unsafe { JobTitle(mp['title'] or { json.Any(0) }.int()) }
}
// ! BUGFIX // ! BUGFIX
// fn test_simplegg() { // fn test_simplegg() {
// // x := EmployeeOp{'Peter', 28, 95000.5, .worker} // // x := EmployeeOp{'Peter', 28, 95000.5, .worker}
@ -102,92 +94,34 @@ fn test_character_unescape() {
assert lines['slash'] or { 0 }.str() == '/dev/null' assert lines['slash'] or { 0 }.str() == '/dev/null'
} }
fn (mut u User2) from_json(an json.Any) { struct MultTypeTest[T] {
mp := an.as_map() mut:
mut js_field_name := '' val T
$for field in User.fields {
js_field_name = field.name
for attr in field.attrs {
if attr.starts_with('json:') {
js_field_name = attr.all_after('json:').trim_left(' ')
break
}
}
match field.name {
'age' { u.age = mp[js_field_name] or { 0 }.int() }
'nums' { u.nums = mp[js_field_name] or { 0 }.arr().map(it.int()) }
else {}
}
}
} }
struct User2 { // NOTE - This can substitute a lot of others tests
pub mut: fn test_bool_decode() {
age int assert json.decode[MultTypeTest[bool]]('{"val": ""}')!.val == false
nums []int assert json.decode[MultTypeTest[bool]]('{"val": "0"}')!.val == false
reg_date time.Time assert json.decode[MultTypeTest[bool]]('{"val": "1"}')!.val == true
} assert json.decode[MultTypeTest[bool]]('{"val": "2"}')!.val == true
assert json.decode[MultTypeTest[bool]]('{"val": 0}')!.val == false
assert json.decode[MultTypeTest[bool]]('{"val": 1}')!.val == true
assert json.decode[MultTypeTest[bool]]('{"val": 2}')!.val == true
assert json.decode[MultTypeTest[bool]]('{"val": "true"}')!.val == true
assert json.decode[MultTypeTest[bool]]('{"val": "false"}')!.val == false
assert json.decode[MultTypeTest[bool]]('{"val": true}')!.val == true
assert json.decode[MultTypeTest[bool]]('{"val": false}')!.val == false
struct User { assert json.decode[MultTypeTest[int]]('{"val": ""}')!.val == 0
pub mut: assert json.decode[MultTypeTest[int]]('{"val": "0"}')!.val == 0
age int assert json.decode[MultTypeTest[int]]('{"val": "1"}')!.val == 1
nums []int assert json.decode[MultTypeTest[int]]('{"val": "2"}')!.val == 2
last_name string [json: lastName] assert json.decode[MultTypeTest[int]]('{"val": 0}')!.val == 0
is_registered bool [json: IsRegistered] assert json.decode[MultTypeTest[int]]('{"val": 1}')!.val == 1
typ int [json: 'type'] assert json.decode[MultTypeTest[int]]('{"val": 2}')!.val == 2
pets string [json: 'pet_animals'; raw] assert json.decode[MultTypeTest[int]]('{"val": "true"}')!.val == 1
} assert json.decode[MultTypeTest[int]]('{"val": "false"}')!.val == 0
assert json.decode[MultTypeTest[int]]('{"val": true}')!.val == 1
fn (mut u User) from_json(an json.Any) { assert json.decode[MultTypeTest[int]]('{"val": false}')!.val == 0
mp := an.as_map()
mut js_field_name := ''
$for field in User.fields {
// FIXME: C error when initializing js_field_name inside comptime for
js_field_name = field.name
for attr in field.attrs {
if attr.starts_with('json:') {
js_field_name = attr.all_after('json:').trim_left(' ')
break
}
}
match field.name {
'age' { u.age = mp[js_field_name] or { 0 }.int() }
'nums' { u.nums = mp[js_field_name] or { 0 }.arr().map(it.int()) }
'last_name' { u.last_name = mp[js_field_name] or { 0 }.str() }
'is_registered' { u.is_registered = mp[js_field_name] or { 0 }.bool() }
'typ' { u.typ = mp[js_field_name] or { 0 }.int() }
'pets' { u.pets = mp[js_field_name] or { 0 }.str() }
else {}
}
}
}
fn (u User) to_json() string {
// TODO: derive from field
mut mp := {
'age': json.Any(u.age)
}
mp['nums'] = u.nums.map(json.Any(it))
mp['lastName'] = json.Any(u.last_name)
mp['IsRegistered'] = json.Any(u.is_registered)
mp['type'] = json.Any(u.typ)
mp['pet_animals'] = json.Any(u.pets)
return mp.str()
}
struct Color {
pub mut:
space string
point string [raw]
}
fn (mut c Color) from_json(an json.Any) {
mp := an.as_map()
$for field in Color.fields {
match field.name {
'space' { c.space = mp[field.name] or { 0 }.str() }
'point' { c.point = mp[field.name] or { 0 }.str() }
else {}
}
}
} }

View File

@ -13,7 +13,7 @@ fn test_json_decode_with_optional_arg() {
} }
fn print_info() !string { fn print_info() !string {
dbconf := json.decode<DbConfig>(os.read_file('dbconf.json')!)! dbconf := json.decode[DbConfig](os.read_file('dbconf.json')!)!
println(dbconf) println(dbconf)
return '${dbconf}' return '${dbconf}'
} }

View File

@ -7,15 +7,15 @@ struct Some {
} }
fn test_json_decode_with_sumtype() { fn test_json_decode_with_sumtype() {
v1 := json.decode<Some>('{"t": ["string", "string2"]}')! v1 := json.decode[Some]('{"t": ["string", "string2"]}')!
println(v1) println(v1)
assert v1.t == Test(['string', 'string2']) assert v1.t == Test(['string', 'string2'])
v2 := json.decode<Some>('{"t": [11, 22]}')! v2 := json.decode[Some]('{"t": [11, 22]}')!
println(v2) println(v2)
assert v2.t == Test([11, 22]) assert v2.t == Test([11, 22])
v3 := json.decode<Some>('{"t": [true, false]}')! v3 := json.decode[Some]('{"t": [true, false]}')!
println(v3) println(v3)
assert v3.t == Test([true, false]) assert v3.t == Test([true, false])
} }

View File

@ -1,5 +1,5 @@
import x.json2 as json import x.json2 as json
import time // import time
enum JobTitle { enum JobTitle {
manager manager
@ -9,11 +9,11 @@ enum JobTitle {
struct Employee { struct Employee {
pub mut: pub mut:
name string name string
age int age int
salary f32 salary f32
title JobTitle // title JobTitle //! FIXME - decode
sub_employee SubEmployee // sub_employee SubEmployee //! FIXME - decode
} }
struct SubEmployee { struct SubEmployee {
@ -21,37 +21,30 @@ pub mut:
name string name string
age int age int
salary f32 salary f32
title JobTitle // title JobTitle //! FIXME - decode
} }
fn test_simple() { fn test_simple() {
sub_employee := SubEmployee{ sub_employee := SubEmployee{
name: 'João' name: 'João'
} }
x := Employee{'Peter', 28, 95000.5, .worker, sub_employee} x := Employee{'Peter', 28, 95000.5}
s := json.encode[Employee](x) s := json.encode[Employee](x)
assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":2,"sub_employee":{"name":"João","age":0,"salary":0.0,"title":0}}' assert s == '{"name":"Peter","age":28,"salary":95000.5}'
// y := json.decode<Employee>(s) or {
// println(err) y := json.decode[Employee](s) or {
// assert false println(err)
// return assert false
// } return
// assert y.name == 'Peter' }
// assert y.age == 28 assert y.name == 'Peter'
// assert y.salary == 95000.5 assert y.age == 28
// assert y.title == .worker assert y.salary == 95000.5
// x := Employee{'Peter', 28, 95000.5, .worker} // assert y.title == .worker //! FIXME
// s := json.encode<Employee>(x) // assert y.sub_employee.name == 'Peter'
// assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":2}' // assert y.sub_employee.age == 0
// // y := json.decode<Employee>(s) or { // assert y.sub_employee.salary == 0.0
// // println(err) // assert y.sub_employee.title == .worker //! FIXME
// // assert false
// // return
// // }
// // assert y.name == 'Peter'
// // assert y.age == 28
// // assert y.salary == 95000.5
// // assert y.title == .worker
} }
// const currency_id = 'cconst' // const currency_id = 'cconst'
@ -100,11 +93,11 @@ fn test_encode_user() {
assert usr.foo() == expected assert usr.foo() == expected
} }
// struct Color { struct Color {
// pub mut: pub mut:
// space string space string
// point string [raw] point string [raw]
// } }
fn test_encode_map() { fn test_encode_map() {
expected := '{"one":1,"two":2,"three":3,"four":4}' expected := '{"one":1,"two":2,"three":3,"four":4}'
@ -147,3 +140,41 @@ struct StByteArray {
fn test_byte_array() { fn test_byte_array() {
assert json.encode(StByteArray{ ba: [byte(1), 2, 3, 4, 5] }) == '{"ba":[1,2,3,4,5]}' assert json.encode(StByteArray{ ba: [byte(1), 2, 3, 4, 5] }) == '{"ba":[1,2,3,4,5]}'
} }
struct Bar {
x string
}
fn bar[T](payload string) !Bar { // ?T doesn't work currently
result := json.decode[T](payload)!
return result
}
fn test_generic() {
result := bar[Bar]('{"x":"test"}') or { Bar{} }
assert result.x == 'test'
}
fn test_raw_json_field() {
color := json.decode[Color]('{"space": "YCbCr", "point": {"Y": 123}}') or {
assert false
Color{}
}
assert color.point == '{"Y":123}'
assert color.space == 'YCbCr'
}
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)!
assert foo_dec.name == 'bar'
assert foo_dec.data == 12
}

View File

@ -7,7 +7,7 @@ enum JobTitle {
worker worker
} }
struct Employee { pub struct Employee {
pub mut: pub mut:
name string name string
age int age int
@ -17,7 +17,7 @@ pub mut:
const currency_id = 'cconst' const currency_id = 'cconst'
struct Price { pub struct Price {
net f64 net f64
currency_id string [json: currencyId] = currency_id currency_id string [json: currencyId] = currency_id
} }
@ -55,7 +55,7 @@ struct Item {
} }
enum Animal { enum Animal {
dog Will be encoded as `0` dog // Will be encoded as `0`
cat cat
} }
@ -94,16 +94,6 @@ fn test_encode_decode_sumtype() {
assert (game.other[4] as time.Time).unix_time() == (dec.other[4] as time.Time).unix_time() assert (game.other[4] as time.Time).unix_time() == (dec.other[4] as time.Time).unix_time()
} }
struct Bar {
x string
}
//! BUGFIX - .from_json(res)
fn test_generic() {
result := bar<Bar>('{"x":"test"}') or { Bar{} }
assert result.x == 'test'
}
struct User2 { struct User2 {
mut: mut:
age int age int
@ -111,7 +101,7 @@ mut:
reg_date time.Time reg_date time.Time
} }
User struct needs to be `pub mut` for now in order to access and manipulate values // User struct needs to be `pub mut` for now in order to access and manipulate values
struct User { struct User {
pub mut: pub mut:
age int age int
@ -155,15 +145,6 @@ pub mut:
point string [raw] point string [raw]
} }
fn test_raw_json_field() {
color := json.decode<Color>('{"space": "YCbCr", "point": {"Y": 123}}') or {
assert false
Color{}
}
assert color.point == '{"Y":123}'
assert color.space == 'YCbCr'
}
//! FIX: returning 0 //! FIX: returning 0
fn test_bad_raw_json_field() { fn test_bad_raw_json_field() {
color := json.decode<Color>('{"space": "YCbCr"}') or { color := json.decode<Color>('{"space": "YCbCr"}') or {
@ -282,22 +263,6 @@ fn test_nested_type() {
} }
} }
struct Foo[T] {
pub:
name string
data T
}
//! BUGFIX - .from_json(res)
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)!
assert foo_dec.name == 'bar'
assert foo_dec.data == 12
}
//! BUGFIX - .from_json(res) //! BUGFIX - .from_json(res)
fn test_errors() { fn test_errors() {
invalid_array := fn () { invalid_array := fn () {