-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathikea.go
67 lines (60 loc) · 1.57 KB
/
ikea.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package ikea
import (
"errors"
"fmt"
"reflect"
)
// Assemble takes a val interface and an Instruction interface. If the
// val is not a pointer and a struct it returns an error.
func Assemble(val interface{}, ins Instructions) error {
ptrRef := reflect.ValueOf(val)
if ptrRef.Kind() != reflect.Ptr {
return errors.New("Expected a pointer to a Struct")
}
ref := ptrRef.Elem()
if ref.Kind() != reflect.Struct {
return errors.New("Expected a struct type to be passed")
}
return assembleStruct(ref, val, ins)
}
func assembleStruct(ref reflect.Value, val interface{}, inst Instructions) error {
refType := ref.Type()
for i := 0; i < refType.NumField(); i++ {
tag := getTag(refType.Field(i))
if tag == "" {
continue
}
ins, err := inst.GetInstruction(tag)
if err != nil {
return err
}
// TODO: add logic that will skip fields that have values
// already set
// TODO: add logic that will determine to set a StructField or
// a Struct
if err := setField(ref.Field(i), refType.Field(i), ins()); err != nil {
return err
}
}
return nil
}
func getTag(field reflect.StructField) string {
tag := field.Tag.Get("ikea")
if tag != "" {
return tag
}
return ""
}
func setField(field reflect.Value, refType reflect.StructField, value interface{}) error {
vt := reflect.TypeOf(value)
if field.Kind() != vt.Kind() {
return setterError(field.Kind(), value)
}
field.Set(reflect.ValueOf(value))
return nil
}
func setterError(k reflect.Kind, value interface{}) error {
return fmt.Errorf(
"Value not of %v type. Value: %v, Type: %T", k, value, value,
)
}