]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go
update vendor and go.mod
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / aws / awsutil / path_value.go
CommitLineData
bae9f6d2
JC
1package awsutil
2
3import (
4 "reflect"
5 "regexp"
6 "strconv"
7 "strings"
8
9 "github.com/jmespath/go-jmespath"
10)
11
12var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`)
13
14// rValuesAtPath returns a slice of values found in value v. The values
15// in v are explored recursively so all nested values are collected.
16func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTerm bool) []reflect.Value {
17 pathparts := strings.Split(path, "||")
18 if len(pathparts) > 1 {
19 for _, pathpart := range pathparts {
20 vals := rValuesAtPath(v, pathpart, createPath, caseSensitive, nilTerm)
21 if len(vals) > 0 {
22 return vals
23 }
24 }
25 return nil
26 }
27
28 values := []reflect.Value{reflect.Indirect(reflect.ValueOf(v))}
29 components := strings.Split(path, ".")
30 for len(values) > 0 && len(components) > 0 {
31 var index *int64
32 var indexStar bool
33 c := strings.TrimSpace(components[0])
34 if c == "" { // no actual component, illegal syntax
35 return nil
36 } else if caseSensitive && c != "*" && strings.ToLower(c[0:1]) == c[0:1] {
37 // TODO normalize case for user
38 return nil // don't support unexported fields
39 }
40
41 // parse this component
42 if m := indexRe.FindStringSubmatch(c); m != nil {
43 c = m[1]
44 if m[2] == "" {
45 index = nil
46 indexStar = true
47 } else {
48 i, _ := strconv.ParseInt(m[2], 10, 32)
49 index = &i
50 indexStar = false
51 }
52 }
53
54 nextvals := []reflect.Value{}
55 for _, value := range values {
56 // pull component name out of struct member
57 if value.Kind() != reflect.Struct {
58 continue
59 }
60
61 if c == "*" { // pull all members
62 for i := 0; i < value.NumField(); i++ {
63 if f := reflect.Indirect(value.Field(i)); f.IsValid() {
64 nextvals = append(nextvals, f)
65 }
66 }
67 continue
68 }
69
70 value = value.FieldByNameFunc(func(name string) bool {
71 if c == name {
72 return true
73 } else if !caseSensitive && strings.ToLower(name) == strings.ToLower(c) {
74 return true
75 }
76 return false
77 })
78
79 if nilTerm && value.Kind() == reflect.Ptr && len(components[1:]) == 0 {
80 if !value.IsNil() {
81 value.Set(reflect.Zero(value.Type()))
82 }
83 return []reflect.Value{value}
84 }
85
86 if createPath && value.Kind() == reflect.Ptr && value.IsNil() {
87 // TODO if the value is the terminus it should not be created
88 // if the value to be set to its position is nil.
89 value.Set(reflect.New(value.Type().Elem()))
90 value = value.Elem()
91 } else {
92 value = reflect.Indirect(value)
93 }
94
95 if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
96 if !createPath && value.IsNil() {
97 value = reflect.ValueOf(nil)
98 }
99 }
100
101 if value.IsValid() {
102 nextvals = append(nextvals, value)
103 }
104 }
105 values = nextvals
106
107 if indexStar || index != nil {
108 nextvals = []reflect.Value{}
109 for _, valItem := range values {
110 value := reflect.Indirect(valItem)
111 if value.Kind() != reflect.Slice {
112 continue
113 }
114
115 if indexStar { // grab all indices
116 for i := 0; i < value.Len(); i++ {
117 idx := reflect.Indirect(value.Index(i))
118 if idx.IsValid() {
119 nextvals = append(nextvals, idx)
120 }
121 }
122 continue
123 }
124
125 // pull out index
126 i := int(*index)
127 if i >= value.Len() { // check out of bounds
128 if createPath {
129 // TODO resize slice
130 } else {
131 continue
132 }
133 } else if i < 0 { // support negative indexing
134 i = value.Len() + i
135 }
136 value = reflect.Indirect(value.Index(i))
137
138 if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
139 if !createPath && value.IsNil() {
140 value = reflect.ValueOf(nil)
141 }
142 }
143
144 if value.IsValid() {
145 nextvals = append(nextvals, value)
146 }
147 }
148 values = nextvals
149 }
150
151 components = components[1:]
152 }
153 return values
154}
155
156// ValuesAtPath returns a list of values at the case insensitive lexical
157// path inside of a structure.
158func ValuesAtPath(i interface{}, path string) ([]interface{}, error) {
159 result, err := jmespath.Search(path, i)
160 if err != nil {
161 return nil, err
162 }
163
164 v := reflect.ValueOf(result)
165 if !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) {
166 return nil, nil
167 }
168 if s, ok := result.([]interface{}); ok {
169 return s, err
170 }
171 if v.Kind() == reflect.Map && v.Len() == 0 {
172 return nil, nil
173 }
174 if v.Kind() == reflect.Slice {
175 out := make([]interface{}, v.Len())
176 for i := 0; i < v.Len(); i++ {
177 out[i] = v.Index(i).Interface()
178 }
179 return out, nil
180 }
181
182 return []interface{}{result}, nil
183}
184
185// SetValueAtPath sets a value at the case insensitive lexical path inside
186// of a structure.
187func SetValueAtPath(i interface{}, path string, v interface{}) {
863486a6
AG
188 rvals := rValuesAtPath(i, path, true, false, v == nil)
189 for _, rval := range rvals {
190 if rval.Kind() == reflect.Ptr && rval.IsNil() {
191 continue
bae9f6d2 192 }
863486a6 193 setValue(rval, v)
bae9f6d2
JC
194 }
195}
196
197func setValue(dstVal reflect.Value, src interface{}) {
198 if dstVal.Kind() == reflect.Ptr {
199 dstVal = reflect.Indirect(dstVal)
200 }
201 srcVal := reflect.ValueOf(src)
202
203 if !srcVal.IsValid() { // src is literal nil
204 if dstVal.CanAddr() {
205 // Convert to pointer so that pointer's value can be nil'ed
206 // dstVal = dstVal.Addr()
207 }
208 dstVal.Set(reflect.Zero(dstVal.Type()))
209
210 } else if srcVal.Kind() == reflect.Ptr {
211 if srcVal.IsNil() {
212 srcVal = reflect.Zero(dstVal.Type())
213 } else {
214 srcVal = reflect.ValueOf(src).Elem()
215 }
216 dstVal.Set(srcVal)
217 } else {
218 dstVal.Set(srcVal)
219 }
220
221}