toml.Unmarshaler supports leaf nodes (#444)

Fixes #437
This commit is contained in:
Thomas Pelletier
2020-09-13 18:46:13 -04:00
committed by GitHub
parent a7448fe8de
commit e6908614ee
2 changed files with 68 additions and 1 deletions
+11 -1
View File
@@ -1004,8 +1004,18 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
default:
d.visitor.visit()
mvalPtr := reflect.New(mtype)
// Check if pointer to value implements the Unmarshaler interface.
if isCustomUnmarshaler(mvalPtr.Type()) {
if err := callCustomUnmarshaler(mvalPtr, tval); err != nil {
return reflect.ValueOf(nil), fmt.Errorf("unmarshal toml: %v", err)
}
return mvalPtr.Elem(), nil
}
// Check if pointer to value implements the encoding.TextUnmarshaler.
if mvalPtr := reflect.New(mtype); isTextUnmarshaler(mvalPtr.Type()) && !isTimeType(mtype) {
if isTextUnmarshaler(mvalPtr.Type()) && !isTimeType(mtype) {
if err := d.unmarshalText(tval, mvalPtr); err != nil {
return reflect.ValueOf(nil), fmt.Errorf("unmarshal text: %v", err)
}
+57
View File
@@ -3,6 +3,7 @@ package toml
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
@@ -3976,3 +3977,59 @@ func TestGithubIssue431(t *testing.T) {
t.Errorf("UnmarshalTOML should not have been called")
}
}
type durationString struct {
time.Duration
}
func (d *durationString) UnmarshalTOML(v interface{}) error {
d.Duration = 10 * time.Second
return nil
}
type config437Error struct {
}
func (e *config437Error) UnmarshalTOML(v interface{}) error {
return errors.New("expected")
}
type config437 struct {
HTTP struct {
PingTimeout durationString `toml:"PingTimeout"`
ErrorField config437Error
} `toml:"HTTP"`
}
func TestGithubIssue437(t *testing.T) {
src := `
[HTTP]
PingTimeout = "32m"
`
cfg := &config437{}
cfg.HTTP.PingTimeout = durationString{time.Second}
r := strings.NewReader(src)
err := NewDecoder(r).Decode(cfg)
if err != nil {
t.Fatalf("unexpected errors %s", err)
}
expected := durationString{10 * time.Second}
if cfg.HTTP.PingTimeout != expected {
t.Fatalf("expected '%s', got '%s'", expected, cfg.HTTP.PingTimeout)
}
}
func TestLeafUnmarshalerError(t *testing.T) {
src := `
[HTTP]
ErrorField = "foo"
`
cfg := &config437{}
r := strings.NewReader(src)
err := NewDecoder(r).Decode(cfg)
if err == nil {
t.Fatalf("error was expected")
}
}