-
Notifications
You must be signed in to change notification settings - Fork 20
/
util.go
45 lines (40 loc) · 1.04 KB
/
util.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
package goq
import "reflect"
// TypeDeref returns the underlying type if the given type is a pointer.
func TypeDeref(t reflect.Type) reflect.Type {
for t != nil && t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}
// indirect is stolen mostly from pkg/encoding/json/decode.go and removed some
// cases (handling `null`) that goquery doesn't need to handle.
func indirect(v reflect.Value) (Unmarshaler, reflect.Value) {
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
v = v.Addr()
}
for {
// Load value from interface, but only if the result will be
// usefully addressable.
if v.Kind() == reflect.Interface && !v.IsNil() {
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() && (e.Elem().Kind() == reflect.Ptr) {
v = e
continue
}
}
if v.Kind() != reflect.Ptr {
break
}
if v.IsNil() {
v.Set(reflect.New(TypeDeref(v.Type())))
}
if v.Type().NumMethod() > 0 {
if u, ok := v.Interface().(Unmarshaler); ok {
return u, reflect.Value{}
}
}
v = v.Elem()
}
return nil, v
}