Skip to content

Commit 6f7689d

Browse files
authored
Mark meta keys as decoded when using Unmarshaler interface (#426)
Keys were marked as "Undecoded" in the meta when using UnmarshalTOML from the Unmarshaler interface. Unlike Primitive, I don't think this makes sense as UnmarshalTOML() explicitly "decodes" the value. Also mark all values below the table or array, and assume the parent UnmarshalTOML() handled this correctly. Fixes #425
1 parent 8323983 commit 6f7689d

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

decode.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,19 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v any) error {
196196
return md.unify(primValue.undecoded, rvalue(v))
197197
}
198198

199+
// markDecodedRecursive is a helper to mark any key under the given tmap as
200+
// decoded, recursing as needed
201+
func markDecodedRecursive(md *MetaData, tmap map[string]any) {
202+
for key := range tmap {
203+
md.decoded[md.context.add(key).String()] = struct{}{}
204+
if tmap, ok := tmap[key].(map[string]any); ok {
205+
md.context = append(md.context, key)
206+
markDecodedRecursive(md, tmap)
207+
md.context = md.context[0 : len(md.context)-1]
208+
}
209+
}
210+
}
211+
199212
// unify performs a sort of type unification based on the structure of `rv`,
200213
// which is the client representation.
201214
//
@@ -222,6 +235,16 @@ func (md *MetaData) unify(data any, rv reflect.Value) error {
222235
if err != nil {
223236
return md.parseErr(err)
224237
}
238+
// Assume the Unmarshaler decoded everything, so mark all keys under
239+
// this table as decoded.
240+
if tmap, ok := data.(map[string]any); ok {
241+
markDecodedRecursive(md, tmap)
242+
}
243+
if aot, ok := data.([]map[string]any); ok {
244+
for _, tmap := range aot {
245+
markDecodedRecursive(md, tmap)
246+
}
247+
}
225248
return nil
226249
}
227250
if v, ok := rvi.(encoding.TextUnmarshaler); ok {

decode_test.go

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ func TestCustomEncode(t *testing.T) {
10181018
// Test for #341
10191019
func TestCustomDecode(t *testing.T) {
10201020
var outer Outer
1021-
_, err := Decode(`
1021+
meta, err := Decode(`
10221022
Int = 10
10231023
Enum = "OTHER_VALUE"
10241024
Slice = ["text1", "text2"]
@@ -1036,6 +1036,9 @@ func TestCustomDecode(t *testing.T) {
10361036
if fmt.Sprint(outer.Slice.value) != fmt.Sprint([]string{"text1", "text2"}) {
10371037
t.Errorf("\nhave:\n%v\nwant:\n%v\n", outer.Slice.value, []string{"text1", "text2"})
10381038
}
1039+
if len(meta.Undecoded()) > 0 {
1040+
t.Errorf("\ncustom decode leaves unencoded fields: %v\n", meta.Undecoded())
1041+
}
10391042
}
10401043

10411044
// TODO: this should be improved for v2:
@@ -1144,3 +1147,45 @@ func BenchmarkKey(b *testing.B) {
11441147
k.String()
11451148
}
11461149
}
1150+
1151+
type UnmarshalTOMLNoop struct {
1152+
}
1153+
1154+
func (cs *UnmarshalTOMLNoop) UnmarshalTOML(data any) error {
1155+
return nil
1156+
}
1157+
1158+
func TestDecodeCustomStructMarkedDecoded(t *testing.T) {
1159+
var s struct {
1160+
Str UnmarshalTOMLNoop `toml:"str"`
1161+
Int UnmarshalTOMLNoop `toml:"int"`
1162+
Arr UnmarshalTOMLNoop `toml:"arr"`
1163+
Tbl UnmarshalTOMLNoop `toml:"tbl"`
1164+
Aot UnmarshalTOMLNoop `toml:"aot"`
1165+
}
1166+
meta, err := Decode(`
1167+
str = "bar"
1168+
int = 1
1169+
arr = [2]
1170+
1171+
[tbl]
1172+
b = 3
1173+
inline = {c = 4}
1174+
1175+
[[aot]]
1176+
a = 1
1177+
[[aot]]
1178+
a = 1
1179+
`, &s)
1180+
if err != nil {
1181+
t.Fatalf("Decode failed: %s", err)
1182+
}
1183+
1184+
// Note that even though the custom unmarshaller did not decode all fields
1185+
// as far as the metadata is concerned they are handled. It is the job of
1186+
// the unmarshaller to ensure this or we would need a more powerful
1187+
// interface like UnmarshalTOML(data any, md *MetaData)
1188+
if len(meta.Undecoded()) > 0 {
1189+
t.Errorf("\ncustom decode leaves undecoded fields: %v\n", meta.Undecoded())
1190+
}
1191+
}

0 commit comments

Comments
 (0)