blob: d8079f9049ef9459de439a13cdd7bcd1aea43777 [file] [log] [blame]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -04001package model
2
3import (
4 "bytes"
5 "encoding/gob"
6 "reflect"
7 "strings"
8)
9
10func IsProtoMessage(object interface{}) bool {
11 var ok bool
12
13 if object != nil {
14 st := reflect.TypeOf(object)
15 _, ok = st.MethodByName("ProtoMessage")
16 }
17 return ok
18}
19
20func FindOwnerType(obj reflect.Value, name string, depth int, found bool) reflect.Type {
21 k := obj.Kind()
22 switch k {
23 case reflect.Ptr:
24 t := obj.Type().Elem()
25 n := reflect.New(t)
26
27 if rc := FindOwnerType(n.Elem(), name, depth+1, false); rc != nil {
28 return rc
29 }
30
31 case reflect.Struct:
32 for i := 0; i < obj.NumField(); i += 1 {
33 v := reflect.Indirect(obj)
34
35 json := strings.Split(v.Type().Field(i).Tag.Get("json"), ",")
36
37 if json[0] == name {
38 return FindOwnerType(obj.Field(i), name, depth+1, true)
39 }
40
41 if rc := FindOwnerType(obj.Field(i), name, depth+1, false); rc != nil {
42 return rc
43 }
44 }
45 case reflect.Slice:
46 s := reflect.MakeSlice(obj.Type(), 1, 1)
47 n := reflect.New(obj.Type())
48 n.Elem().Set(s)
49
50 for i := 0; i < n.Elem().Len(); i += 1 {
51 if found {
52 return reflect.ValueOf(n.Elem().Index(i).Interface()).Type()
53 }
54 }
55
56 for i := 0; i < obj.Len(); i += 1 {
57 if found {
58 return obj.Index(i).Type()
59 }
60
61 if rc := FindOwnerType(obj.Index(i), name, depth+1, false); rc != nil {
62 return rc
63 }
64 }
65 default:
66 //fmt.Printf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
67 }
68
69 return nil
70}
71
72func FindKeyOwner(iface interface{}, name string, depth int) interface{} {
73 obj := reflect.ValueOf(iface)
74 k := obj.Kind()
75 switch k {
76 case reflect.Ptr:
77 t := obj.Type().Elem()
78 n := reflect.New(t)
79
80 if rc := FindKeyOwner(n.Elem().Interface(), name, depth+1); rc != nil {
81 return rc
82 }
83
84 case reflect.Struct:
85 for i := 0; i < obj.NumField(); i++ {
86 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
87
88 if json[0] == name {
89 return obj.Type().Field(i).Type
90 }
91
92 if rc := FindKeyOwner(obj.Field(i).Interface(), name, depth+1); rc != nil {
93 return rc
94 }
95 }
96
97 case reflect.Slice:
98 s := reflect.MakeSlice(obj.Type(), 1, 1)
99 n := reflect.New(obj.Type())
100 n.Elem().Set(s)
101
102 for i := 0; i < n.Elem().Len(); i += 1 {
103 if rc := FindKeyOwner(n.Elem().Index(i).Interface(), name, depth+1); rc != nil {
104 return rc
105 }
106 }
107 default:
108 //fmt.Printf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
109 }
110
111 return nil
112}
113
114// FIXME: Need to figure out if GetAttributeValue and GetAttributeStructure can become one
115// Code is repeated in both, but outputs have a different purpose
116// Left as-is for now to get things working
117func GetAttributeValue(data interface{}, name string, depth int) reflect.Value {
118 var result reflect.Value
119 obj := reflect.ValueOf(data)
120
121 if !obj.IsValid() {
122 return result
123 }
124
125 k := obj.Kind()
126 switch k {
127 case reflect.Ptr:
128 t := obj.Type().Elem()
129 n := reflect.New(t)
130
131 if rc := GetAttributeValue(n.Elem().Interface(), name, depth+1); rc.IsValid() {
132 return rc
133 }
134
135 case reflect.Struct:
136 for i := 0; i < obj.NumField(); i++ {
137 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
138
139 if json[0] == name {
140 return obj.Field(i)
141 }
142
143 if obj.Field(i).IsValid() {
144 if rc := GetAttributeValue(obj.Field(i).Interface(), name, depth+1); rc.IsValid() {
145 return rc
146 }
147 }
148 }
149
150 case reflect.Slice:
151 s := reflect.MakeSlice(obj.Type(), 1, 1)
152 n := reflect.New(obj.Type())
153 n.Elem().Set(s)
154
155 for i := 0; i < obj.Len(); i += 1 {
156 if rc := GetAttributeValue(obj.Index(i).Interface(), name, depth+1); rc.IsValid() {
157 return rc
158 }
159 }
160 default:
161 //fmt.Printf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
162 }
163
164 return result
165
166}
167
168// FIXME: See GetAttributeValue(...) comment
169func GetAttributeStructure(data interface{}, name string, depth int) reflect.StructField {
170 var result reflect.StructField
171 obj := reflect.ValueOf(data)
172
173 if !obj.IsValid() {
174 return result
175 }
176
177 k := obj.Kind()
178 switch k {
179 case reflect.Ptr:
180 t := obj.Type().Elem()
181 n := reflect.New(t)
182
183 if rc := GetAttributeStructure(n.Elem().Interface(), name, depth+1); rc.Name != "" {
184 return rc
185 }
186
187 case reflect.Struct:
188 for i := 0; i < obj.NumField(); i++ {
189 v := reflect.Indirect(obj)
190 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
191
192 if json[0] == name {
193 return v.Type().Field(i)
194 }
195
196 if obj.Field(i).IsValid() {
197 if rc := GetAttributeStructure(obj.Field(i).Interface(), name, depth+1); rc.Name != "" {
198 return rc
199 }
200 }
201 }
202
203 case reflect.Slice:
204 s := reflect.MakeSlice(obj.Type(), 1, 1)
205 n := reflect.New(obj.Type())
206 n.Elem().Set(s)
207
208 for i := 0; i < obj.Len(); i += 1 {
209 if rc := GetAttributeStructure(obj.Index(i).Interface(), name, depth+1); rc.Name != "" {
210 return rc
211 }
212
213 }
214 default:
215 //fmt.Printf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
216 }
217
218 return result
219
220}
221
222func Clone(a interface{}) interface{} {
223 b := reflect.ValueOf(a)
224 buff := new(bytes.Buffer)
225 enc := gob.NewEncoder(buff)
226 dec := gob.NewDecoder(buff)
227 enc.Encode(a)
228 dec.Decode(b.Elem().Interface())
229
230 return b.Interface()
231}