diff options
author | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
---|---|---|
committer | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
commit | bae9f6d2fd5eb5bc80929bd393932b23f14d7c93 (patch) | |
tree | ca9ab12a7d78b1fc27a8f734729081357ce6d252 /vendor/github.com/go-ini/ini/struct.go | |
parent | 254c495b6bebab3fb72a243c4bce858d79e6ee99 (diff) | |
download | terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.gz terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.zst terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.zip |
Initial transfer of provider code
Diffstat (limited to 'vendor/github.com/go-ini/ini/struct.go')
-rw-r--r-- | vendor/github.com/go-ini/ini/struct.go | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/vendor/github.com/go-ini/ini/struct.go b/vendor/github.com/go-ini/ini/struct.go new file mode 100644 index 0000000..5ef38d8 --- /dev/null +++ b/vendor/github.com/go-ini/ini/struct.go | |||
@@ -0,0 +1,431 @@ | |||
1 | // Copyright 2014 Unknwon | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||
4 | // not use this file except in compliance with the License. You may obtain | ||
5 | // a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
12 | // License for the specific language governing permissions and limitations | ||
13 | // under the License. | ||
14 | |||
15 | package ini | ||
16 | |||
17 | import ( | ||
18 | "bytes" | ||
19 | "errors" | ||
20 | "fmt" | ||
21 | "reflect" | ||
22 | "strings" | ||
23 | "time" | ||
24 | "unicode" | ||
25 | ) | ||
26 | |||
27 | // NameMapper represents a ini tag name mapper. | ||
28 | type NameMapper func(string) string | ||
29 | |||
30 | // Built-in name getters. | ||
31 | var ( | ||
32 | // AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. | ||
33 | AllCapsUnderscore NameMapper = func(raw string) string { | ||
34 | newstr := make([]rune, 0, len(raw)) | ||
35 | for i, chr := range raw { | ||
36 | if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { | ||
37 | if i > 0 { | ||
38 | newstr = append(newstr, '_') | ||
39 | } | ||
40 | } | ||
41 | newstr = append(newstr, unicode.ToUpper(chr)) | ||
42 | } | ||
43 | return string(newstr) | ||
44 | } | ||
45 | // TitleUnderscore converts to format title_underscore. | ||
46 | TitleUnderscore NameMapper = func(raw string) string { | ||
47 | newstr := make([]rune, 0, len(raw)) | ||
48 | for i, chr := range raw { | ||
49 | if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { | ||
50 | if i > 0 { | ||
51 | newstr = append(newstr, '_') | ||
52 | } | ||
53 | chr -= ('A' - 'a') | ||
54 | } | ||
55 | newstr = append(newstr, chr) | ||
56 | } | ||
57 | return string(newstr) | ||
58 | } | ||
59 | ) | ||
60 | |||
61 | func (s *Section) parseFieldName(raw, actual string) string { | ||
62 | if len(actual) > 0 { | ||
63 | return actual | ||
64 | } | ||
65 | if s.f.NameMapper != nil { | ||
66 | return s.f.NameMapper(raw) | ||
67 | } | ||
68 | return raw | ||
69 | } | ||
70 | |||
71 | func parseDelim(actual string) string { | ||
72 | if len(actual) > 0 { | ||
73 | return actual | ||
74 | } | ||
75 | return "," | ||
76 | } | ||
77 | |||
78 | var reflectTime = reflect.TypeOf(time.Now()).Kind() | ||
79 | |||
80 | // setSliceWithProperType sets proper values to slice based on its type. | ||
81 | func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { | ||
82 | strs := key.Strings(delim) | ||
83 | numVals := len(strs) | ||
84 | if numVals == 0 { | ||
85 | return nil | ||
86 | } | ||
87 | |||
88 | var vals interface{} | ||
89 | |||
90 | sliceOf := field.Type().Elem().Kind() | ||
91 | switch sliceOf { | ||
92 | case reflect.String: | ||
93 | vals = strs | ||
94 | case reflect.Int: | ||
95 | vals = key.Ints(delim) | ||
96 | case reflect.Int64: | ||
97 | vals = key.Int64s(delim) | ||
98 | case reflect.Uint: | ||
99 | vals = key.Uints(delim) | ||
100 | case reflect.Uint64: | ||
101 | vals = key.Uint64s(delim) | ||
102 | case reflect.Float64: | ||
103 | vals = key.Float64s(delim) | ||
104 | case reflectTime: | ||
105 | vals = key.Times(delim) | ||
106 | default: | ||
107 | return fmt.Errorf("unsupported type '[]%s'", sliceOf) | ||
108 | } | ||
109 | |||
110 | slice := reflect.MakeSlice(field.Type(), numVals, numVals) | ||
111 | for i := 0; i < numVals; i++ { | ||
112 | switch sliceOf { | ||
113 | case reflect.String: | ||
114 | slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i])) | ||
115 | case reflect.Int: | ||
116 | slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i])) | ||
117 | case reflect.Int64: | ||
118 | slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i])) | ||
119 | case reflect.Uint: | ||
120 | slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i])) | ||
121 | case reflect.Uint64: | ||
122 | slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) | ||
123 | case reflect.Float64: | ||
124 | slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) | ||
125 | case reflectTime: | ||
126 | slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) | ||
127 | } | ||
128 | } | ||
129 | field.Set(slice) | ||
130 | return nil | ||
131 | } | ||
132 | |||
133 | // setWithProperType sets proper value to field based on its type, | ||
134 | // but it does not return error for failing parsing, | ||
135 | // because we want to use default value that is already assigned to strcut. | ||
136 | func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { | ||
137 | switch t.Kind() { | ||
138 | case reflect.String: | ||
139 | if len(key.String()) == 0 { | ||
140 | return nil | ||
141 | } | ||
142 | field.SetString(key.String()) | ||
143 | case reflect.Bool: | ||
144 | boolVal, err := key.Bool() | ||
145 | if err != nil { | ||
146 | return nil | ||
147 | } | ||
148 | field.SetBool(boolVal) | ||
149 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
150 | durationVal, err := key.Duration() | ||
151 | // Skip zero value | ||
152 | if err == nil && int(durationVal) > 0 { | ||
153 | field.Set(reflect.ValueOf(durationVal)) | ||
154 | return nil | ||
155 | } | ||
156 | |||
157 | intVal, err := key.Int64() | ||
158 | if err != nil || intVal == 0 { | ||
159 | return nil | ||
160 | } | ||
161 | field.SetInt(intVal) | ||
162 | // byte is an alias for uint8, so supporting uint8 breaks support for byte | ||
163 | case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
164 | durationVal, err := key.Duration() | ||
165 | // Skip zero value | ||
166 | if err == nil && int(durationVal) > 0 { | ||
167 | field.Set(reflect.ValueOf(durationVal)) | ||
168 | return nil | ||
169 | } | ||
170 | |||
171 | uintVal, err := key.Uint64() | ||
172 | if err != nil { | ||
173 | return nil | ||
174 | } | ||
175 | field.SetUint(uintVal) | ||
176 | |||
177 | case reflect.Float32, reflect.Float64: | ||
178 | floatVal, err := key.Float64() | ||
179 | if err != nil { | ||
180 | return nil | ||
181 | } | ||
182 | field.SetFloat(floatVal) | ||
183 | case reflectTime: | ||
184 | timeVal, err := key.Time() | ||
185 | if err != nil { | ||
186 | return nil | ||
187 | } | ||
188 | field.Set(reflect.ValueOf(timeVal)) | ||
189 | case reflect.Slice: | ||
190 | return setSliceWithProperType(key, field, delim) | ||
191 | default: | ||
192 | return fmt.Errorf("unsupported type '%s'", t) | ||
193 | } | ||
194 | return nil | ||
195 | } | ||
196 | |||
197 | func (s *Section) mapTo(val reflect.Value) error { | ||
198 | if val.Kind() == reflect.Ptr { | ||
199 | val = val.Elem() | ||
200 | } | ||
201 | typ := val.Type() | ||
202 | |||
203 | for i := 0; i < typ.NumField(); i++ { | ||
204 | field := val.Field(i) | ||
205 | tpField := typ.Field(i) | ||
206 | |||
207 | tag := tpField.Tag.Get("ini") | ||
208 | if tag == "-" { | ||
209 | continue | ||
210 | } | ||
211 | |||
212 | opts := strings.SplitN(tag, ",", 2) // strip off possible omitempty | ||
213 | fieldName := s.parseFieldName(tpField.Name, opts[0]) | ||
214 | if len(fieldName) == 0 || !field.CanSet() { | ||
215 | continue | ||
216 | } | ||
217 | |||
218 | isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous | ||
219 | isStruct := tpField.Type.Kind() == reflect.Struct | ||
220 | if isAnonymous { | ||
221 | field.Set(reflect.New(tpField.Type.Elem())) | ||
222 | } | ||
223 | |||
224 | if isAnonymous || isStruct { | ||
225 | if sec, err := s.f.GetSection(fieldName); err == nil { | ||
226 | if err = sec.mapTo(field); err != nil { | ||
227 | return fmt.Errorf("error mapping field(%s): %v", fieldName, err) | ||
228 | } | ||
229 | continue | ||
230 | } | ||
231 | } | ||
232 | |||
233 | if key, err := s.GetKey(fieldName); err == nil { | ||
234 | if err = setWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { | ||
235 | return fmt.Errorf("error mapping field(%s): %v", fieldName, err) | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | return nil | ||
240 | } | ||
241 | |||
242 | // MapTo maps section to given struct. | ||
243 | func (s *Section) MapTo(v interface{}) error { | ||
244 | typ := reflect.TypeOf(v) | ||
245 | val := reflect.ValueOf(v) | ||
246 | if typ.Kind() == reflect.Ptr { | ||
247 | typ = typ.Elem() | ||
248 | val = val.Elem() | ||
249 | } else { | ||
250 | return errors.New("cannot map to non-pointer struct") | ||
251 | } | ||
252 | |||
253 | return s.mapTo(val) | ||
254 | } | ||
255 | |||
256 | // MapTo maps file to given struct. | ||
257 | func (f *File) MapTo(v interface{}) error { | ||
258 | return f.Section("").MapTo(v) | ||
259 | } | ||
260 | |||
261 | // MapTo maps data sources to given struct with name mapper. | ||
262 | func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { | ||
263 | cfg, err := Load(source, others...) | ||
264 | if err != nil { | ||
265 | return err | ||
266 | } | ||
267 | cfg.NameMapper = mapper | ||
268 | return cfg.MapTo(v) | ||
269 | } | ||
270 | |||
271 | // MapTo maps data sources to given struct. | ||
272 | func MapTo(v, source interface{}, others ...interface{}) error { | ||
273 | return MapToWithMapper(v, nil, source, others...) | ||
274 | } | ||
275 | |||
276 | // reflectSliceWithProperType does the opposite thing as setSliceWithProperType. | ||
277 | func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error { | ||
278 | slice := field.Slice(0, field.Len()) | ||
279 | if field.Len() == 0 { | ||
280 | return nil | ||
281 | } | ||
282 | |||
283 | var buf bytes.Buffer | ||
284 | sliceOf := field.Type().Elem().Kind() | ||
285 | for i := 0; i < field.Len(); i++ { | ||
286 | switch sliceOf { | ||
287 | case reflect.String: | ||
288 | buf.WriteString(slice.Index(i).String()) | ||
289 | case reflect.Int, reflect.Int64: | ||
290 | buf.WriteString(fmt.Sprint(slice.Index(i).Int())) | ||
291 | case reflect.Uint, reflect.Uint64: | ||
292 | buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) | ||
293 | case reflect.Float64: | ||
294 | buf.WriteString(fmt.Sprint(slice.Index(i).Float())) | ||
295 | case reflectTime: | ||
296 | buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) | ||
297 | default: | ||
298 | return fmt.Errorf("unsupported type '[]%s'", sliceOf) | ||
299 | } | ||
300 | buf.WriteString(delim) | ||
301 | } | ||
302 | key.SetValue(buf.String()[:buf.Len()-1]) | ||
303 | return nil | ||
304 | } | ||
305 | |||
306 | // reflectWithProperType does the opposite thing as setWithProperType. | ||
307 | func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { | ||
308 | switch t.Kind() { | ||
309 | case reflect.String: | ||
310 | key.SetValue(field.String()) | ||
311 | case reflect.Bool: | ||
312 | key.SetValue(fmt.Sprint(field.Bool())) | ||
313 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
314 | key.SetValue(fmt.Sprint(field.Int())) | ||
315 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
316 | key.SetValue(fmt.Sprint(field.Uint())) | ||
317 | case reflect.Float32, reflect.Float64: | ||
318 | key.SetValue(fmt.Sprint(field.Float())) | ||
319 | case reflectTime: | ||
320 | key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339))) | ||
321 | case reflect.Slice: | ||
322 | return reflectSliceWithProperType(key, field, delim) | ||
323 | default: | ||
324 | return fmt.Errorf("unsupported type '%s'", t) | ||
325 | } | ||
326 | return nil | ||
327 | } | ||
328 | |||
329 | // CR: copied from encoding/json/encode.go with modifications of time.Time support. | ||
330 | // TODO: add more test coverage. | ||
331 | func isEmptyValue(v reflect.Value) bool { | ||
332 | switch v.Kind() { | ||
333 | case reflect.Array, reflect.Map, reflect.Slice, reflect.String: | ||
334 | return v.Len() == 0 | ||
335 | case reflect.Bool: | ||
336 | return !v.Bool() | ||
337 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
338 | return v.Int() == 0 | ||
339 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||
340 | return v.Uint() == 0 | ||
341 | case reflect.Float32, reflect.Float64: | ||
342 | return v.Float() == 0 | ||
343 | case reflectTime: | ||
344 | return v.Interface().(time.Time).IsZero() | ||
345 | case reflect.Interface, reflect.Ptr: | ||
346 | return v.IsNil() | ||
347 | } | ||
348 | return false | ||
349 | } | ||
350 | |||
351 | func (s *Section) reflectFrom(val reflect.Value) error { | ||
352 | if val.Kind() == reflect.Ptr { | ||
353 | val = val.Elem() | ||
354 | } | ||
355 | typ := val.Type() | ||
356 | |||
357 | for i := 0; i < typ.NumField(); i++ { | ||
358 | field := val.Field(i) | ||
359 | tpField := typ.Field(i) | ||
360 | |||
361 | tag := tpField.Tag.Get("ini") | ||
362 | if tag == "-" { | ||
363 | continue | ||
364 | } | ||
365 | |||
366 | opts := strings.SplitN(tag, ",", 2) | ||
367 | if len(opts) == 2 && opts[1] == "omitempty" && isEmptyValue(field) { | ||
368 | continue | ||
369 | } | ||
370 | |||
371 | fieldName := s.parseFieldName(tpField.Name, opts[0]) | ||
372 | if len(fieldName) == 0 || !field.CanSet() { | ||
373 | continue | ||
374 | } | ||
375 | |||
376 | if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) || | ||
377 | (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") { | ||
378 | // Note: The only error here is section doesn't exist. | ||
379 | sec, err := s.f.GetSection(fieldName) | ||
380 | if err != nil { | ||
381 | // Note: fieldName can never be empty here, ignore error. | ||
382 | sec, _ = s.f.NewSection(fieldName) | ||
383 | } | ||
384 | if err = sec.reflectFrom(field); err != nil { | ||
385 | return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) | ||
386 | } | ||
387 | continue | ||
388 | } | ||
389 | |||
390 | // Note: Same reason as secion. | ||
391 | key, err := s.GetKey(fieldName) | ||
392 | if err != nil { | ||
393 | key, _ = s.NewKey(fieldName, "") | ||
394 | } | ||
395 | if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { | ||
396 | return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) | ||
397 | } | ||
398 | |||
399 | } | ||
400 | return nil | ||
401 | } | ||
402 | |||
403 | // ReflectFrom reflects secion from given struct. | ||
404 | func (s *Section) ReflectFrom(v interface{}) error { | ||
405 | typ := reflect.TypeOf(v) | ||
406 | val := reflect.ValueOf(v) | ||
407 | if typ.Kind() == reflect.Ptr { | ||
408 | typ = typ.Elem() | ||
409 | val = val.Elem() | ||
410 | } else { | ||
411 | return errors.New("cannot reflect from non-pointer struct") | ||
412 | } | ||
413 | |||
414 | return s.reflectFrom(val) | ||
415 | } | ||
416 | |||
417 | // ReflectFrom reflects file from given struct. | ||
418 | func (f *File) ReflectFrom(v interface{}) error { | ||
419 | return f.Section("").ReflectFrom(v) | ||
420 | } | ||
421 | |||
422 | // ReflectFrom reflects data sources from given struct with name mapper. | ||
423 | func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error { | ||
424 | cfg.NameMapper = mapper | ||
425 | return cfg.ReflectFrom(v) | ||
426 | } | ||
427 | |||
428 | // ReflectFrom reflects data sources from given struct. | ||
429 | func ReflectFrom(cfg *File, v interface{}) error { | ||
430 | return ReflectFromWithMapper(cfg, v, nil) | ||
431 | } | ||