mirror of
https://github.com/vlang/v.git
synced 2025-09-18 11:56:57 -04:00
json2: decode refactor/fix (#16588)
This commit is contained in:
parent
50110d4c19
commit
5288c613ef
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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')
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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}'
|
||||||
}
|
}
|
@ -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])
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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 () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user