Basics working
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..185aa0b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# mapstructure
+
+mapstructure is a Go library for converting generic map values to structures
+and vice versa, while providing helpful error handling.
+
+This library is most useful when decoding values from some data stream (JSON,
+Gob, etc.) where you don't _quite_ know the structure of the underlying data
+until you read a part of it. You can therefore read a `map[string]interface{}`
+and use this library to decode it into the proper underlying native Go
+structure.
diff --git a/mapstructure.go b/mapstructure.go
new file mode 100644
index 0000000..eaf505d
--- /dev/null
+++ b/mapstructure.go
@@ -0,0 +1,62 @@
+package mapstructure
+
+import (
+ "errors"
+ "reflect"
+ "strings"
+)
+
+// MapToStruct takes a map and uses reflection to convert it into the
+// given Go native structure. val must be a pointer to a struct.
+func MapToStruct(m map[string]interface{}, rawVal interface{}) error {
+ val := reflect.ValueOf(rawVal).Elem()
+ if !val.CanAddr() {
+ return errors.New("val must be addressable (a pointer)")
+ }
+
+ if val.Kind() != reflect.Struct {
+ return errors.New("val must be an addressable struct")
+ }
+
+ valType := val.Type()
+
+ for i := 0; i < valType.NumField(); i++ {
+ fieldType := valType.Field(i)
+ fieldName := fieldType.Name
+
+ rawMapVal, ok := m[fieldName]
+ if !ok {
+ // Do a slower search by iterating over each key and
+ // doing case-insensitive search.
+ for mK, mV := range m {
+ if strings.EqualFold(mK, fieldName) {
+ rawMapVal = mV
+ break
+ }
+ }
+
+ if rawMapVal == nil {
+ // There was no matching key in the map for the value in
+ // the struct. Just ignore.
+ continue
+ }
+ }
+
+ field := val.Field(i)
+ if !field.IsValid() {
+ // This should never happen
+ panic("field is not valid")
+ }
+
+ mapVal := reflect.ValueOf(rawMapVal)
+ if !mapVal.IsValid() {
+ // This should never happen because we got the value out
+ // of the map.
+ panic("map value is not valid")
+ }
+
+ field.Set(mapVal)
+ }
+
+ return nil
+}
diff --git a/mapstructure_test.go b/mapstructure_test.go
new file mode 100644
index 0000000..593ba06
--- /dev/null
+++ b/mapstructure_test.go
@@ -0,0 +1,38 @@
+package mapstructure
+
+import "testing"
+
+type Basic struct {
+ Vstring string
+ Vint int
+ Vbool bool
+}
+
+func TestBasicTypes(t *testing.T) {
+ t.Parallel()
+
+ input := map[string]interface{}{
+ "vstring": "foo",
+ "vint": 42,
+ "vbool": true,
+ }
+
+ var result Basic
+ err := MapToStruct(input, &result)
+ if err != nil {
+ t.Errorf("got an err: %s", err.Error())
+ t.FailNow()
+ }
+
+ if result.Vstring != "foo" {
+ t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
+ }
+
+ if result.Vint != 42 {
+ t.Errorf("vint value should be 42: %#v", result.Vint)
+ }
+
+ if result.Vbool != true {
+ t.Errorf("vbool value should be true: %#v", result.Vbool)
+ }
+}