diff --git a/vlib/toml/tests/encode_and_decode_test.v b/vlib/toml/tests/encode_and_decode_test.v index d9253021980346..af517f304e2799 100644 --- a/vlib/toml/tests/encode_and_decode_test.v +++ b/vlib/toml/tests/encode_and_decode_test.v @@ -7,14 +7,15 @@ enum JobTitle { } struct Pet { - name string - nicknames []string - age u64 - income int - height f32 - has_furr bool - title JobTitle - address Address + name string + nicknames []string + age u64 + income int + height f32 + has_furr bool + title JobTitle + address Address + meal_frequency map[string]int // *¹ Currently it is only possible to decode a single nested struct generically. // As soon as we decode another nested struct (e.g. within this struct, like `contact` below) // or only one nested struct within another struct, it results in wrong values or errors. @@ -58,7 +59,10 @@ struct Arrs { 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'}} - p := Pet{'Mr. Scratchy McEvilPaws', ['Freddy', 'Fred', 'Charles'], 8, -1, 0.8, true, .manager, Address{'1428 Elm Street', 'Springwood'}} + p := Pet{'Mr. Scratchy McEvilPaws', ['Freddy', 'Fred', 'Charles'], 8, -1, 0.8, true, .manager, Address{'1428 Elm Street', 'Springwood'}, { + 'bones': 2 + 'kibble': 5 + }} s := 'name = "Mr. Scratchy McEvilPaws" nicknames = [ "Freddy", @@ -70,7 +74,8 @@ income = -1 height = 0.8 has_furr = true title = 2 -address = { street = "1428 Elm Street", city = "Springwood" }' +address = { street = "1428 Elm Street", city = "Springwood" } +meal_frequency = { bones = 2, kibble = 5 }' // contact = { phone = "123-456-7890" }' // *¹ assert toml.encode[Pet](p) == s diff --git a/vlib/toml/toml.v b/vlib/toml/toml.v index 80dc901032b10f..be45f884be56be 100644 --- a/vlib/toml/toml.v +++ b/vlib/toml/toml.v @@ -7,6 +7,7 @@ import toml.ast import toml.input import toml.scanner import toml.parser +import maps // Null is used in sumtype checks as a "default" value when nothing else is possible. pub struct Null { @@ -70,6 +71,63 @@ fn decode_struct[T](doc Any, mut typ T) { '[]toml.Time' { typ.$(field.name) = arr.map(it.time()) } else {} } + } $else $if field.is_map { + mut mmap := value.as_map() + match typeof(typ.$(field.name)).name { + 'map[string]string' { + typ.$(field.name) = mmap.as_strings() + } + // Should be cleaned up to use the more modern lambda syntax + // |k, v| k, v.int() + // Unfortunately lambdas have issues with multiple return at the time of writing + 'map[string]int' { + typ.$(field.name) = maps.to_map[string, Any, string, int](mmap, fn (k string, v Any) (string, int) { + return k, v.int() + }) + } + 'map[string]i64' { + typ.$(field.name) = maps.to_map[string, Any, string, i64](mmap, fn (k string, v Any) (string, i64) { + return k, v.i64() + }) + } + 'map[string]u64' { + typ.$(field.name) = maps.to_map[string, Any, string, u64](mmap, fn (k string, v Any) (string, u64) { + return k, v.u64() + }) + } + 'map[string]f32' { + typ.$(field.name) = maps.to_map[string, Any, string, f32](mmap, fn (k string, v Any) (string, f32) { + return k, v.f32() + }) + } + 'map[string]f64' { + typ.$(field.name) = maps.to_map[string, Any, string, f64](mmap, fn (k string, v Any) (string, f64) { + return k, v.f64() + }) + } + 'map[string]bool' { + typ.$(field.name) = maps.to_map[string, Any, string, bool](mmap, fn (k string, v Any) (string, bool) { + return k, v.bool() + }) + } + 'map[string]toml.DateTime' { + typ.$(field.name) = maps.to_map[string, Any, string, DateTime](mmap, + fn (k string, v Any) (string, DateTime) { + return k, v.datetime() + }) + } + 'map[string]toml.Date' { + typ.$(field.name) = maps.to_map[string, Any, string, Date](mmap, fn (k string, v Any) (string, Date) { + return k, v.date() + }) + } + 'map[string]toml.Time' { + typ.$(field.name) = maps.to_map[string, Any, string, Time](mmap, fn (k string, v Any) (string, Time) { + return k, v.time() + }) + } + else {} + } } $else $if field.is_struct { mut s := typ.$(field.name) decode_struct(value, mut s)