]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/jmespath/go-jmespath/util.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / jmespath / go-jmespath / util.go
1 package jmespath
2
3 import (
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
13 func 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.
50 func 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.
57 type sliceParam struct {
58 N int
59 Specified bool
60 }
61
62 // Slice supports [start:stop:step] style slicing that's supported in JMESPath.
63 func 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
82 func 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
120 func 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.
143 func 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.
164 func 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
180 func isSliceType(v interface{}) bool {
181 if v == nil {
182 return false
183 }
184 return reflect.TypeOf(v).Kind() == reflect.Slice
185 }