toml: add decoding for struct fields of type map[string]T (#19447)

This commit is contained in:
squidink7 2023-09-26 19:23:24 +09:30 committed by GitHub
parent bd9f42d14f
commit 12ee3fa86a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 10 deletions

View file

@ -15,6 +15,7 @@ struct Pet {
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

View file

@ -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)