diff --git a/vlib/toml/tests/encode_and_decode_test.v b/vlib/toml/tests/encode_and_decode_test.v index af517f304e..76fdf60c6f 100644 --- a/vlib/toml/tests/encode_and_decode_test.v +++ b/vlib/toml/tests/encode_and_decode_test.v @@ -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() { diff --git a/vlib/toml/toml.v b/vlib/toml/toml.v index f3b1bb2e14..71db616893 100644 --- a/vlib/toml/toml.v +++ b/vlib/toml/toml.v @@ -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' { diff --git a/vlib/x/json2/decoder.v b/vlib/x/json2/decoder.v index 3f5e58fb17..e139e92eb8 100644 --- a/vlib/x/json2/decoder.v +++ b/vlib/x/json2/decoder.v @@ -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()) } diff --git a/vlib/x/json2/tests/decode_and_encode_struct_any_test.v b/vlib/x/json2/tests/decode_and_encode_struct_any_test.v new file mode 100644 index 0000000000..0f84a634c3 --- /dev/null +++ b/vlib/x/json2/tests/decode_and_encode_struct_any_test.v @@ -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 +}