-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathcommon.go
More file actions
55 lines (47 loc) · 1.52 KB
/
common.go
File metadata and controls
55 lines (47 loc) · 1.52 KB
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
package requestmigrations
import (
"reflect"
"strings"
)
// IsStringEmpty checks if the given string s is empty or not
func isStringEmpty(s string) bool { return len(strings.TrimSpace(s)) == 0 }
// dereferenceToLastPtr dereferences nested pointers down to the last pointer level.
// For example: ***T -> *T, **T -> *T, *T -> *T, T -> T
func dereferenceToLastPtr(t reflect.Type) reflect.Type {
if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Ptr {
return dereferenceToLastPtr(t.Elem())
}
return t
}
// typeHasInterfaceFields checks if a type has any interface fields (direct or nested).
// Types with interface fields need runtime value inspection and cannot use cached graphs directly.
func typeHasInterfaceFields(t reflect.Type) bool {
return typeHasInterfaceFieldsRecursive(t, make(map[reflect.Type]bool))
}
func typeHasInterfaceFieldsRecursive(t reflect.Type, visited map[reflect.Type]bool) bool {
// Dereference pointers
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
// Prevent infinite recursion for cyclic types
if visited[t] {
return false
}
visited[t] = true
switch t.Kind() {
case reflect.Interface:
return true
case reflect.Struct:
for i := 0; i < t.NumField(); i++ {
if typeHasInterfaceFieldsRecursive(t.Field(i).Type, visited) {
return true
}
}
case reflect.Slice, reflect.Array:
return typeHasInterfaceFieldsRecursive(t.Elem(), visited)
case reflect.Map:
return typeHasInterfaceFieldsRecursive(t.Key(), visited) ||
typeHasInterfaceFieldsRecursive(t.Elem(), visited)
}
return false
}