From b76eb6211757490046121712dc5c7b10d5f8fec9 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Fri, 11 Sep 2020 10:04:46 -0400 Subject: [PATCH] Marshal into empty interface{} (#433) Allows to marshal a TOML document into an empty `interface{}`, resulting in a `map[string]interface{}`. Fixes #432 --- marshal.go | 3 +++ marshal_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/marshal.go b/marshal.go index e6b4703..73056cd 100644 --- a/marshal.go +++ b/marshal.go @@ -76,6 +76,7 @@ var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() var localDateType = reflect.TypeOf(LocalDate{}) var localTimeType = reflect.TypeOf(LocalTime{}) var localDateTimeType = reflect.TypeOf(LocalDateTime{}) +var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{}) // Check if the given marshal type maps to a Tree primitive func isPrimitive(mtype reflect.Type) bool { @@ -703,6 +704,8 @@ func (d *Decoder) unmarshal(v interface{}) error { switch elem.Kind() { case reflect.Struct, reflect.Map: + case reflect.Interface: + elem = mapStringInterfaceType default: return errors.New("only a pointer to struct or map can be unmarshaled from TOML") } diff --git a/marshal_test.go b/marshal_test.go index e5f3215..b91b286 100644 --- a/marshal_test.go +++ b/marshal_test.go @@ -3888,3 +3888,56 @@ func TestPreserveNotEmptyField(t *testing.T) { t.Errorf("Bad unmarshal: expected %+v, got %+v", expected, actual) } } + +// github issue 432 +func TestUnmarshalEmptyInterface(t *testing.T) { + doc := []byte(`User = "pelletier"`) + + var v interface{} + + err := Unmarshal(doc, &v) + if err != nil { + t.Fatal(err) + } + + x, ok := v.(map[string]interface{}) + if !ok { + t.Fatal(err) + } + + if x["User"] != "pelletier" { + t.Fatalf("expected User=pelletier, but got %v", x) + } +} + +func TestUnmarshalEmptyInterfaceDeep(t *testing.T) { + doc := []byte(` +User = "pelletier" +Age = 99 + +[foo] +bar = 42 +`) + + var v interface{} + + err := Unmarshal(doc, &v) + if err != nil { + t.Fatal(err) + } + + x, ok := v.(map[string]interface{}) + if !ok { + t.Fatal(err) + } + + expected := map[string]interface{}{ + "User": "pelletier", + "Age": 99, + "foo": map[string]interface{}{ + "bar": 42, + }, + } + + reflect.DeepEqual(x, expected) +}