]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/jmespath/go-jmespath/util.go
Merge branch 'master' of /Users/jake/terraform
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / jmespath / go-jmespath / util.go
CommitLineData
bae9f6d2
JC
1package jmespath
2
3import (
4 "errors"
5 "reflect"
6)
7
8// IsFalse determines if an object is false based on the JMESPath spec.
9// JMESPath defines false values to be any of:
10// - An empty string array, or hash.
11// - The boolean value false.
12// - nil
13func isFalse(value interface{}) bool {
14 switch v := value.(type) {
15 case bool:
16 return !v
17 case []interface{}:
18 return len(v) == 0
19 case map[string]interface{}:
20 return len(v) == 0
21 case string:
22 return len(v) == 0
23 case nil:
24 return true
25 }
26 // Try the reflection cases before returning false.
27 rv := reflect.ValueOf(value)
28 switch rv.Kind() {
29 case reflect.Struct:
30 // A struct type will never be false, even if
31 // all of its values are the zero type.
32 return false
33 case reflect.Slice, reflect.Map:
34 return rv.Len() == 0
35 case reflect.Ptr:
36 if rv.IsNil() {
37 return true
38 }
39 // If it's a pointer type, we'll try to deref the pointer
40 // and evaluate the pointer value for isFalse.
41 element := rv.Elem()
42 return isFalse(element.Interface())
43 }
44 return false
45}
46
47// ObjsEqual is a generic object equality check.
48// It will take two arbitrary objects and recursively determine
49// if they are equal.
50func objsEqual(left interface{}, right interface{}) bool {
51 return reflect.DeepEqual(left, right)
52}
53
54// SliceParam refers to a single part of a slice.
55// A slice consists of a start, a stop, and a step, similar to
56// python slices.
57type sliceParam struct {
58 N int
59 Specified bool
60}
61
62// Slice supports [start:stop:step] style slicing that's supported in JMESPath.
63func slice(slice []interface{}, parts []sliceParam) ([]interface{}, error) {
64 computed, err := computeSliceParams(len(slice), parts)
65 if err != nil {
66 return nil, err
67 }
68 start, stop, step := computed[0], computed[1], computed[2]
69 result := []interface{}{}
70 if step > 0 {
71 for i := start; i < stop; i += step {
72 result = append(result, slice[i])
73 }
74 } else {
75 for i := start; i > stop; i += step {
76 result = append(result, slice[i])
77 }
78 }
79 return result, nil
80}
81
82func computeSliceParams(length int, parts []sliceParam) ([]int, error) {
83 var start, stop, step int
84 if !parts[2].Specified {
85 step = 1
86 } else if parts[2].N == 0 {
87 return nil, errors.New("Invalid slice, step cannot be 0")
88 } else {
89 step = parts[2].N
90 }
91 var stepValueNegative bool
92 if step < 0 {
93 stepValueNegative = true
94 } else {
95 stepValueNegative = false
96 }
97
98 if !parts[0].Specified {
99 if stepValueNegative {
100 start = length - 1
101 } else {
102 start = 0
103 }
104 } else {
105 start = capSlice(length, parts[0].N, step)
106 }
107
108 if !parts[1].Specified {
109 if stepValueNegative {
110 stop = -1
111 } else {
112 stop = length
113 }
114 } else {
115 stop = capSlice(length, parts[1].N, step)
116 }
117 return []int{start, stop, step}, nil
118}
119
120func capSlice(length int, actual int, step int) int {
121 if actual < 0 {
122 actual += length
123 if actual < 0 {
124 if step < 0 {
125 actual = -1
126 } else {
127 actual = 0
128 }
129 }
130 } else if actual >= length {
131 if step < 0 {
132 actual = length - 1
133 } else {
134 actual = length
135 }
136 }
137 return actual
138}
139
140// ToArrayNum converts an empty interface type to a slice of float64.
141// If any element in the array cannot be converted, then nil is returned
142// along with a second value of false.
143func toArrayNum(data interface{}) ([]float64, bool) {
144 // Is there a better way to do this with reflect?
145 if d, ok := data.([]interface{}); ok {
146 result := make([]float64, len(d))
147 for i, el := range d {
148 item, ok := el.(float64)
149 if !ok {
150 return nil, false
151 }
152 result[i] = item
153 }
154 return result, true
155 }
156 return nil, false
157}
158
159// ToArrayStr converts an empty interface type to a slice of strings.
160// If any element in the array cannot be converted, then nil is returned
161// along with a second value of false. If the input data could be entirely
162// converted, then the converted data, along with a second value of true,
163// will be returned.
164func toArrayStr(data interface{}) ([]string, bool) {
165 // Is there a better way to do this with reflect?
166 if d, ok := data.([]interface{}); ok {
167 result := make([]string, len(d))
168 for i, el := range d {
169 item, ok := el.(string)
170 if !ok {
171 return nil, false
172 }
173 result[i] = item
174 }
175 return result, true
176 }
177 return nil, false
178}
179
180func isSliceType(v interface{}) bool {
181 if v == nil {
182 return false
183 }
184 return reflect.TypeOf(v).Kind() == reflect.Slice
185}