x.json2, toml: add support for Any in decode_struct, encode_struct and to_any (#21972)

This commit is contained in:
tcn 2024-08-01 14:26:09 +02:00 committed by GitHub
parent 28103d15d5
commit 2d43f38bf3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 71 additions and 0 deletions

View File

@ -34,6 +34,10 @@ struct Contact {
phone string
}*/
struct AnyStruct {
val toml.Any
}
struct Employee {
mut:
name string
@ -56,6 +60,11 @@ struct Arrs {
times []toml.Time
}
// individual because toml.decode[Foo](str)! == foo is false
struct AnyArr {
arr []toml.Any
}
fn test_encode_and_decode() {
// *¹
// p := Pet{'Mr. Scratchy McEvilPaws', ['Freddy', 'Fred', 'Charles'], 8, -1, 0.8, true, .manager, Address{'1428 Elm Street', 'Springwood'}, Contact{'123-456-7890'}}
@ -82,6 +91,14 @@ meal_frequency = { bones = 2, kibble = 5 }'
assert toml.decode[Pet](s)! == p
}
fn test_encode_and_decode_any() {
a := AnyStruct{toml.Any(10)}
s := 'val = 10'
assert toml.encode[AnyStruct](a) == s
assert toml.decode[AnyStruct](s)!.val.int() == 10
}
pub fn (e Employee) to_toml() string {
mut mp := map[string]toml.Any{}
mp['name'] = toml.Any(e.name)
@ -250,6 +267,16 @@ times = [
assert toml.encode[Arrs](a) == s
assert toml.decode[Arrs](s)! == a
any_a := AnyArr{[toml.Any(10), 20, 30]}
any_s := 'arr = [
10,
20,
30
]'
assert toml.encode[AnyArr](any_a) == any_s
assert toml.decode[AnyArr](any_s)!.arr.map(it.int()) == [10, 20, 30]
}
fn test_decode_doc() {

View File

@ -68,6 +68,8 @@ fn decode_struct[T](doc Any, mut typ T) {
typ.$(field.name) = value.date()
} $else $if field.typ is Time {
typ.$(field.name) = value.time()
} $else $if field.typ is Any {
typ.$(field.name) = value
} $else $if field.is_array {
arr := value.array()
match field.typ {
@ -81,6 +83,7 @@ fn decode_struct[T](doc Any, mut typ T) {
[]DateTime { typ.$(field.name) = arr.map(it.datetime()) }
[]Date { typ.$(field.name) = arr.map(it.date()) }
[]Time { typ.$(field.name) = arr.map(it.time()) }
[]Any { typ.$(field.name) = arr }
else {}
}
} $else $if field.is_map {
@ -146,6 +149,9 @@ fn decode_struct[T](doc Any, mut typ T) {
return k, v.time()
})
}
map[string]Any {
typ.$(field.name) = mmap.clone()
}
else {}
}
} $else $if field.is_struct {
@ -211,6 +217,8 @@ fn to_any[T](value T) Any {
return Any(value)
} $else $if T is DateTime {
return Any(value)
} $else $if T is Any {
return value
} $else $if T is $struct {
$for method in T.methods {
$if method.name == 'to_toml' {

View File

@ -267,6 +267,12 @@ fn decode_struct[T](_ T, res map[string]Any) !T {
if json_name in res {
typ.$(field.name) = res[json_name]!.to_time()!
}
} $else $if field.typ is Any {
typ.$(field.name) = res[json_name]!
} $else $if field.typ is ?Any {
if json_name in res {
typ.$(field.name) = res[json_name]!
}
} $else $if field.is_array {
arr := res[field.name]! as []Any
// vfmt off
@ -292,6 +298,8 @@ fn decode_struct[T](_ T, res map[string]Any) !T {
// NOTE: Using `!` on `to_time()` inside the array method causes a builder error - 2024/04/01.
[]time.Time { typ.$(field.name) = arr.map(it.to_time() or { time.Time{} }) }
[]?time.Time { typ.$(field.name) = arr.map(?time.Time(it.to_time() or { time.Time{} })) }
[]Any { typ.$(field.name) = arr }
[]?Any { typ.$(field.name) = arr.map(?Any(it)) }
[]u8 { typ.$(field.name) = arr.map(it.u64()) }
[]?u8 { typ.$(field.name) = arr.map(?u8(it.u64())) }
[]u16 { typ.$(field.name) = arr.map(it.u64()) }

View File

@ -0,0 +1,28 @@
import x.json2 as json
struct AnyStruct[T] {
val T
}
struct OptAnyStruct[T] {
val ?T
}
/*struct OptAnyArrStruct {
val []?json.Any
}*/
fn test_values() {
assert json.decode[AnyStruct[json.Any]]('{"val":5}')!.val.int() == 5
assert json.decode[OptAnyStruct[json.Any]]('{}')!.val == none
assert json.decode[AnyStruct[[]json.Any]]('{"val":[5,10]}')!.val.map(it.int()) == [
5,
10,
]
// assert json.decode[OptAnyArrStruct]('{"val":[5,null,10]}')!.val == [?json.Any(5),json.Null{},10] skipped because test still fails even though they're the same
assert json.encode[AnyStruct[json.Any]](AnyStruct[json.Any]{json.Any(5)}) == '{"val":5}'
assert json.encode[OptAnyStruct[json.Any]](OptAnyStruct[json.Any]{none}) == '{}'
assert json.encode[AnyStruct[[]json.Any]](AnyStruct[[]json.Any]{[json.Any(5), 10]}) == '{"val":[5,10]}'
// assert json.encode[OptAnyArrStruct](OptAnyArrStruct{[?json.Any(5),none,10]}) == '{"val":[5,null,10]}' encode_array has not implemented optional arrays yet
}