Allow unmarshal from any TomlTree (#157)

Fixes #153
This commit is contained in:
John K. Luebs
2017-05-05 19:29:08 -04:00
committed by Thomas Pelletier
parent 97253b98df
commit 53be957dac
2 changed files with 35 additions and 13 deletions
+18 -13
View File
@@ -1,6 +1,7 @@
package toml package toml
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
@@ -224,24 +225,15 @@ func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
} }
} }
/* // Unmarshal attempts to unmarshal the TomlTree into a Go struct pointed by v.
Unmarshal parses the TOML-encoded data and stores the result in the value // Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
pointed to by v. Behavior is similar to the Go json encoder, except that there // sub-structs, and only definite types can be unmarshaled.
is no concept of an Unmarshaler interface or UnmarshalTOML function for func (t *TomlTree) Unmarshal(v interface{}) error {
sub-structs, and currently only definite types can be unmarshaled to (i.e. no
`interface{}`).
*/
func Unmarshal(data []byte, v interface{}) error {
mtype := reflect.TypeOf(v) mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct { if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
return errors.New("Only a pointer to struct can be unmarshaled from TOML") return errors.New("Only a pointer to struct can be unmarshaled from TOML")
} }
t, err := Load(string(data))
if err != nil {
return err
}
sval, err := valueFromTree(mtype.Elem(), t) sval, err := valueFromTree(mtype.Elem(), t)
if err != nil { if err != nil {
return err return err
@@ -250,6 +242,19 @@ func Unmarshal(data []byte, v interface{}) error {
return nil return nil
} }
// Unmarshal parses the TOML-encoded data and stores the result in the value
// pointed to by v. Behavior is similar to the Go json encoder, except that there
// is no concept of an Unmarshaler interface or UnmarshalTOML function for
// sub-structs, and currently only definite types can be unmarshaled to (i.e. no
// `interface{}`).
func Unmarshal(data []byte, v interface{}) error {
t, err := LoadReader(bytes.NewReader(data))
if err != nil {
return err
}
return t.Unmarshal(v)
}
// Convert toml tree to marshal struct or map, using marshal type // Convert toml tree to marshal struct or map, using marshal type
func valueFromTree(mtype reflect.Type, tval *TomlTree) (reflect.Value, error) { func valueFromTree(mtype reflect.Type, tval *TomlTree) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr { if mtype.Kind() == reflect.Ptr {
+17
View File
@@ -177,6 +177,23 @@ func TestDocUnmarshal(t *testing.T) {
} }
} }
func TestDocPartialUnmarshal(t *testing.T) {
result := testDocSubs{}
tree, _ := LoadFile("marshal_test.toml")
subTree := tree.Get("subdoc").(*TomlTree)
err := subTree.Unmarshal(&result)
expected := docData.Subdocs
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result, expected) {
resStr, _ := json.MarshalIndent(result, "", " ")
expStr, _ := json.MarshalIndent(expected, "", " ")
t.Errorf("Bad partial unmartial: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr)
}
}
type tomlTypeCheckTest struct { type tomlTypeCheckTest struct {
name string name string
item interface{} item interface{}