-
Notifications
You must be signed in to change notification settings - Fork 1
/
indexers.go
153 lines (131 loc) · 3.34 KB
/
indexers.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package refutil
import (
"reflect"
)
// StructIndexer implements Indexer for
// structs
type StructIndexer struct {
Source Value
keys []Value
}
var _ Indexer = (*StructIndexer)(nil)
// NewStructIndexer will create StructIndexer
func NewStructIndexer(source Value) *StructIndexer {
var keys []Value
t := source.Type()
for i := 0; i < source.NumField(); i++ {
keys = append(keys, NewValue(t.Field(i).Name))
}
s := ValueSorter(keys)
s.Sort()
return &StructIndexer{Source: source, keys: s}
}
// At will return key value for index i
func (v *StructIndexer) At(i int) (Value, Value) {
key := v.keys[i]
field := v.Source.FieldByName(key.String())
return NewValue(key), NewValue(field)
}
// Keys will return list of keys
func (v *StructIndexer) Keys() []Value {
return v.keys
}
// MapIndexer implements Indexer for
// maps
type MapIndexer struct {
Source Value
keys []Value
}
var _ Indexer = (*MapIndexer)(nil)
// NewMapIndexer will create MapIndexer
func NewMapIndexer(source Value) *MapIndexer {
keys := source.MapKeys()
var arr []Value
for _, k := range keys {
arr = append(arr, NewValue(k))
}
s := ValueSorter(arr)
s.Sort()
return &MapIndexer{Source: source, keys: s}
}
// At will return key value for index i
func (v *MapIndexer) At(i int) (Value, Value) {
key := v.keys[i]
field := v.Source.MapIndex(key.Value)
return key, NewValue(field)
}
// Keys will return list of keys
func (v *MapIndexer) Keys() []Value {
return v.keys
}
// SliceIndexer implements Indexer for
// slices or arrays
type SliceIndexer struct {
Source Value
keys []Value
}
var _ Indexer = (*SliceIndexer)(nil)
// NewSliceIndexer will create SliceIndexer
func NewSliceIndexer(source Value) *SliceIndexer {
var keys []Value
for i := 0; i < source.Len(); i++ {
keys = append(keys, NewValue(i))
}
return &SliceIndexer{Source: source, keys: keys}
}
// At will return key value for index i
func (v *SliceIndexer) At(i int) (Value, Value) {
return NewValue(i), v.Source.Index(i)
}
// Keys will return list of keys
func (v *SliceIndexer) Keys() []Value {
return v.keys
}
// CanIndex tells you if you can get value from index.
// Checkout https://golang.org/pkg/reflect/#Value.Index
func (v Value) CanIndex() bool {
nv := v.Indirect()
if nv.KindOneOf(reflect.String, reflect.Slice, reflect.Array) {
return true
}
return false
}
// Index is just wrapper of regular index
// method. It will indirect value if is pointer
func (v Value) Index(i int) Value {
nv := v.Indirect()
return NewValue(nv.Value.Index(i))
}
// CanUseIndexer return bool if Indexer Method can be used
func (v Value) CanUseIndexer() bool {
nv := v.Indirect()
if nv.KindOneOf(reflect.Struct, reflect.Map, reflect.Slice, reflect.Array) {
return true
}
return false
}
// Indexer will return proper Indexer interface
func (v Value) Indexer() Indexer {
nv := v.Indirect()
switch nv.Kind() {
case reflect.Struct:
return NewStructIndexer(nv)
case reflect.Map:
return NewMapIndexer(nv)
case reflect.Slice, reflect.Array:
return NewSliceIndexer(nv)
default:
panic(ErrArgumentNotIndexable)
}
}
// At returns key value of given object if `Indexer`
// interface can be used
func (v Value) At(i int) (Value, Value) {
return v.Indexer().At(i)
}
// At returns key value of given object if `Indexer`
// interface can be used
func (v Data) At(i int) (Value, Value) {
k, x := v.v.Indexer().At(i)
return k, x
}