-
Notifications
You must be signed in to change notification settings - Fork 0
/
ref.go
110 lines (92 loc) · 2.38 KB
/
ref.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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package pl
import (
"fmt"
"reflect"
"strings"
)
type Ref []RefKey
func (r Ref) String() string {
paths := make([]string, len(r))
for i, k := range r {
paths[i] = k.String()
}
return strings.Join(paths, "")
}
func Resolve(data any, ref Ref) (any, error) {
cursor := reflect.ValueOf(data)
for i, key := range ref {
t := cursor.Type()
for {
switch t.Kind() {
case reflect.Pointer:
fallthrough
case reflect.Interface:
cursor = cursor.Elem()
t = cursor.Type()
continue
}
break
}
if key.Name != nil {
switch t.Kind() {
case reflect.Map:
if t.Key().Kind() != reflect.String {
return nil, fmt.Errorf("%s is a map but key type is not a string", ref[:i].String())
}
cursor = cursor.MapIndex(reflect.ValueOf(*key.Name))
if !cursor.IsValid() {
return nil, fmt.Errorf("$%s has no key %s", ref[:i].String(), *key.Name)
}
case reflect.Struct:
cursor = cursor.FieldByName(*key.Name)
if !cursor.IsValid() {
return nil, fmt.Errorf("$%s has no field %s", ref[:i].String(), *key.Name)
}
default:
return nil, fmt.Errorf("$%s is not an object but %s", ref[:i].String(), t.String())
}
} else if key.Index != nil {
switch t.Kind() {
case reflect.Map:
var index any
switch t.Key().Kind() {
case reflect.Int:
index = *key.Index
case reflect.Int16:
index = int16(*key.Index)
case reflect.Int32:
index = int32(*key.Index)
case reflect.Int64:
index = int64(*key.Index)
case reflect.Uint:
index = uint(*key.Index)
case reflect.Uint16:
index = uint16(*key.Index)
case reflect.Uint32:
index = uint32(*key.Index)
case reflect.Uint64:
index = uint64(*key.Index)
default:
return nil, fmt.Errorf("%s is a map but key type is not an integer", ref[:i].String())
}
cursor = cursor.MapIndex(reflect.ValueOf(index))
if !cursor.IsValid() {
return nil, fmt.Errorf("$%s has no key %d", ref[:i].String(), *key.Index)
}
continue
case reflect.Array:
case reflect.Slice:
default:
return nil, fmt.Errorf("$%s is not a list but %s", ref[:i].String(), t.String())
}
l := cursor.Len()
if l <= *key.Index {
return nil, fmt.Errorf("$%s: out of range", ref[:i].String())
}
cursor = cursor.Index(*key.Index)
} else {
return nil, fmt.Errorf("invalid key at %d", i)
}
}
return cursor.Interface(), nil
}