Skip to content

Instantly share code, notes, and snippets.

@owulveryck
Created February 2, 2017 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save owulveryck/8e816bbf931190d5a9d10509fd6937b1 to your computer and use it in GitHub Desktop.
Save owulveryck/8e816bbf931190d5a9d10509fd6937b1 to your computer and use it in GitHub Desktop.
Golang / Reflection
package item
import (
"errors"
"reflect"
)
// Marshal takes an interface and returns an Item compatible with tidedot
func Marshal(o interface{}) map[string]interface{} {
oType := reflect.TypeOf(o)
// Get the numeber of fields in the interface
numField := oType.NumField()
result := make(map[string]interface{}, numField)
for i := 0; i < numField; i++ {
f := oType.Field(i)
// No need to save a private field as we won't be able to restore it
if f.PkgPath == "" {
result[f.Name] = reflect.ValueOf(o).Field(i).Interface()
}
}
return result
}
// Unmarshal parses i and sets it if possible into o
// returns an error if not possible or if interface is not a struct
func Unmarshal(i map[string]interface{}, o interface{}) error {
oType := reflect.TypeOf(o)
if oType.Kind() != reflect.Ptr {
return errors.New("Expected pointer")
}
//temp := reflect.New(oType)
oVal := reflect.ValueOf(o).Elem()
if oVal.Kind() != reflect.Struct {
return errors.New("Interface is " + oType.Kind().String() + ", not struct")
}
for k, v := range i {
f := oVal.FieldByName(k)
if f.IsValid() {
// A Value can be changed only if it is
// addressable and was not obtained by
// the use of unexported struct fields.
if f.CanSet() {
if f.Kind() == reflect.ValueOf(v).Kind() {
f.Set(reflect.ValueOf(v))
} else {
return errors.New("Cannot set " + reflect.ValueOf(v).Kind().String() + " into " + f.Kind().String())
}
} else {
return errors.New("Cannot set field " + k)
}
} else {
return errors.New("Field \"" + k + "\" is not valid")
}
}
return nil
}
package item
import (
"testing"
)
type testStruct struct {
ID string
Field1 int64
Field3 float64
private string
Struct subStruct
}
type subStruct struct {
ID string
}
func TestUnmarshal(t *testing.T) {
var test testStruct
vals := map[string]interface{}{
"ID": "foo",
"Field1": int64(1),
"Field3": float64(2.0),
"Struct": subStruct{"subid"},
}
err := Unmarshal(vals, &test)
if err != nil {
t.Fatal(err)
}
t.Log(test)
vals = map[string]interface{}{
"id": "foo",
"Field1": int64(1),
"Field3": float64(2.0),
}
err = Unmarshal(vals, &test)
if err != nil {
t.Log(err)
} else {
t.Fail()
}
}
func TestMarshal(t *testing.T) {
test := testStruct{
ID: "foo",
Field1: int64(1),
Field3: float64(2.1),
Struct: subStruct{"subid"},
}
t.Log(test)
it := Marshal(test)
t.Log(it)
err := Unmarshal(it, &test)
if err != nil {
t.Fatal(err)
}
t.Log(test)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment