-
Notifications
You must be signed in to change notification settings - Fork 0
/
dig.go
123 lines (98 loc) · 2.3 KB
/
dig.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
package dig
import (
"errors"
"strconv"
)
type enumerable interface {
getAt(key string) interface{}
setAt(key string, value interface{})
}
type dict map[string]interface{}
func (d dict) getAt(key string) interface{} {
return d[key]
}
func (d dict) setAt(key string, value interface{}) {
d[key] = value
}
type slice []interface{}
type cache map[string]func(...interface{}) interface{}
type getterSetterFunc func(i ...interface{}) interface{}
type mmap struct {
source dict
cache cache
}
type Map interface {
GetValue(path string) (interface{}, error)
SetValue(path string, value interface{}) error
Source() dict
PropertyPaths() []string
}
func NewMap(source dict) Map {
cache := make(cache)
recurseDict(source, cache, "")
return &mmap{
source: source,
cache: cache,
}
}
func (m *mmap) GetValue(path string) (interface{}, error) {
getterFunc, ok := m.cache[path]
if !ok {
return nil, errors.New("the path does not exist")
}
return getterFunc(), nil
}
func (m *mmap) SetValue(path string, value interface{}) error {
setterFunc, ok := m.cache[path]
if !ok {
return errors.New("the path does not exist")
}
setterFunc(value)
return nil
}
func (m *mmap) PropertyPaths() []string {
var pp []string
for key := range m.cache {
pp = append(pp, key)
}
return pp
}
func recurseDict(m dict, cache cache, pathPrefix string) {
for key, value := range m {
path := key
if pathPrefix != "" {
path = pathPrefix + "." + key
}
process(value, cache, path, m, key)
}
}
func process(value interface{}, cache cache, path string, m enumerable, key string) {
switch value.(type) {
case map[string]interface{}:
recurseDict(value.(map[string]interface{}), cache, path)
case []interface{}:
recurseSlice(value.([]interface{}), cache, path)
case string, int, int32, int64, float32, float64:
cache[path] = func(m enumerable, key string) getterSetterFunc {
return func(i ...interface{}) interface{} {
if i != nil {
m.setAt(key, i[0])
}
return m.getAt(key)
}
}(m, key)
}
}
func recurseSlice(m slice, cache cache, pathPrefix string) {
for idx, value := range m {
strIdx := strconv.Itoa(idx)
path := strIdx
if pathPrefix != "" {
path = pathPrefix + "." + strIdx
}
process(value, cache, path, nil, strIdx)
}
}
func (m *mmap) Source() dict {
return m.source
}