...
1 package funk
2
3 import (
4 "errors"
5 "fmt"
6 "reflect"
7 "strings"
8 )
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 func Set(in interface{}, val interface{}, path string) error {
24 if in == nil {
25 return errors.New("Cannot Set nil")
26 }
27 parts := []string{}
28 if path != "" {
29 parts = strings.Split(path, ".")
30 }
31 return setByParts(in, val, parts)
32 }
33
34
35 func setByParts(in interface{}, val interface{}, parts []string) error {
36
37 if in == nil {
38
39 return errors.New("Cannot traverse nil/uninitialized interface{}")
40 }
41
42 inValue := reflect.ValueOf(in)
43 inKind := inValue.Type().Kind()
44
45
46
47
48 if inKind == reflect.Ptr {
49 inValue = inValue.Elem()
50 } else if inKind != reflect.Array && inKind != reflect.Slice {
51 return fmt.Errorf("Type %s not supported by Set", inValue.Type().String())
52 }
53
54 return set(inValue, reflect.ValueOf(val), parts)
55 }
56
57
58 func set(inValue reflect.Value, setValue reflect.Value, parts []string) error {
59
60
61 i := 0
62 for i < len(parts) {
63
64 kind := inValue.Kind()
65
66 switch kind {
67 case reflect.Invalid:
68
69 return errors.New("nil pointer found along the path")
70 case reflect.Struct:
71 fValue := inValue.FieldByName(parts[i])
72 if !fValue.IsValid() {
73 return fmt.Errorf("field name %v is not found in struct %v", parts[i], inValue.Type().String())
74 }
75 if !fValue.CanSet() {
76 return fmt.Errorf("field name %v is not exported in struct %v", parts[i], inValue.Type().String())
77 }
78 inValue = fValue
79 i++
80 case reflect.Slice | reflect.Array:
81
82 length := inValue.Len()
83 for j := 0; j < length; j++ {
84 err := set(inValue.Index(j), setValue, parts[i:])
85 if err != nil {
86 return err
87 }
88 }
89 return nil
90 case reflect.Ptr:
91
92 if inValue.IsNil() {
93
94
95 inValue.Set(reflect.New(inValue.Type().Elem()))
96 }
97
98 inValue = redirectValue(inValue)
99 case reflect.Interface:
100
101
102
103 return setByParts(inValue.Interface(), setValue.Interface(), parts[i:])
104 default:
105 return fmt.Errorf("kind %v in path %v is not supported", kind, parts[i])
106 }
107
108 }
109
110
111
112
113 if inValue.Kind() != setValue.Kind() && inValue.Kind() != reflect.Interface {
114 return fmt.Errorf("cannot set target of type %v with type %v", inValue.Kind(), setValue.Kind())
115 }
116 inValue.Set(setValue)
117
118 return nil
119 }
120
121
122
123
124 func MustSet(in interface{}, val interface{}, path string) {
125 err := Set(in, val, path)
126 if err != nil {
127 panic(err)
128 }
129 }
130
View as plain text