]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/hil/convert.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / hil / convert.go
1 package hil
2
3 import (
4 "fmt"
5 "reflect"
6
7 "github.com/hashicorp/hil/ast"
8 "github.com/mitchellh/mapstructure"
9 )
10
11 // UnknownValue is a sentinel value that can be used to denote
12 // that a value of a variable (or map element, list element, etc.)
13 // is unknown. This will always have the type ast.TypeUnknown.
14 const UnknownValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
15
16 var hilMapstructureDecodeHookSlice []interface{}
17 var hilMapstructureDecodeHookStringSlice []string
18 var hilMapstructureDecodeHookMap map[string]interface{}
19
20 // hilMapstructureWeakDecode behaves in the same way as mapstructure.WeakDecode
21 // but has a DecodeHook which defeats the backward compatibility mode of mapstructure
22 // which WeakDecodes []interface{}{} into an empty map[string]interface{}. This
23 // allows us to use WeakDecode (desirable), but not fail on empty lists.
24 func hilMapstructureWeakDecode(m interface{}, rawVal interface{}) error {
25 config := &mapstructure.DecoderConfig{
26 DecodeHook: func(source reflect.Type, target reflect.Type, val interface{}) (interface{}, error) {
27 sliceType := reflect.TypeOf(hilMapstructureDecodeHookSlice)
28 stringSliceType := reflect.TypeOf(hilMapstructureDecodeHookStringSlice)
29 mapType := reflect.TypeOf(hilMapstructureDecodeHookMap)
30
31 if (source == sliceType || source == stringSliceType) && target == mapType {
32 return nil, fmt.Errorf("Cannot convert %s into a %s", source, target)
33 }
34
35 return val, nil
36 },
37 WeaklyTypedInput: true,
38 Result: rawVal,
39 }
40
41 decoder, err := mapstructure.NewDecoder(config)
42 if err != nil {
43 return err
44 }
45
46 return decoder.Decode(m)
47 }
48
49 func InterfaceToVariable(input interface{}) (ast.Variable, error) {
50 if iv, ok := input.(ast.Variable); ok {
51 return iv, nil
52 }
53
54 // This is just to maintain backward compatibility
55 // after https://github.com/mitchellh/mapstructure/pull/98
56 if v, ok := input.([]ast.Variable); ok {
57 return ast.Variable{
58 Type: ast.TypeList,
59 Value: v,
60 }, nil
61 }
62 if v, ok := input.(map[string]ast.Variable); ok {
63 return ast.Variable{
64 Type: ast.TypeMap,
65 Value: v,
66 }, nil
67 }
68
69 var stringVal string
70 if err := hilMapstructureWeakDecode(input, &stringVal); err == nil {
71 // Special case the unknown value to turn into "unknown"
72 if stringVal == UnknownValue {
73 return ast.Variable{Value: UnknownValue, Type: ast.TypeUnknown}, nil
74 }
75
76 // Otherwise return the string value
77 return ast.Variable{
78 Type: ast.TypeString,
79 Value: stringVal,
80 }, nil
81 }
82
83 var mapVal map[string]interface{}
84 if err := hilMapstructureWeakDecode(input, &mapVal); err == nil {
85 elements := make(map[string]ast.Variable)
86 for i, element := range mapVal {
87 varElement, err := InterfaceToVariable(element)
88 if err != nil {
89 return ast.Variable{}, err
90 }
91 elements[i] = varElement
92 }
93
94 return ast.Variable{
95 Type: ast.TypeMap,
96 Value: elements,
97 }, nil
98 }
99
100 var sliceVal []interface{}
101 if err := hilMapstructureWeakDecode(input, &sliceVal); err == nil {
102 elements := make([]ast.Variable, len(sliceVal))
103 for i, element := range sliceVal {
104 varElement, err := InterfaceToVariable(element)
105 if err != nil {
106 return ast.Variable{}, err
107 }
108 elements[i] = varElement
109 }
110
111 return ast.Variable{
112 Type: ast.TypeList,
113 Value: elements,
114 }, nil
115 }
116
117 return ast.Variable{}, fmt.Errorf("value for conversion must be a string, interface{} or map[string]interface: got %T", input)
118 }
119
120 func VariableToInterface(input ast.Variable) (interface{}, error) {
121 if input.Type == ast.TypeString {
122 if inputStr, ok := input.Value.(string); ok {
123 return inputStr, nil
124 } else {
125 return nil, fmt.Errorf("ast.Variable with type string has value which is not a string")
126 }
127 }
128
129 if input.Type == ast.TypeList {
130 inputList, ok := input.Value.([]ast.Variable)
131 if !ok {
132 return nil, fmt.Errorf("ast.Variable with type list has value which is not a []ast.Variable")
133 }
134
135 result := make([]interface{}, 0)
136 if len(inputList) == 0 {
137 return result, nil
138 }
139
140 for _, element := range inputList {
141 if convertedElement, err := VariableToInterface(element); err == nil {
142 result = append(result, convertedElement)
143 } else {
144 return nil, err
145 }
146 }
147
148 return result, nil
149 }
150
151 if input.Type == ast.TypeMap {
152 inputMap, ok := input.Value.(map[string]ast.Variable)
153 if !ok {
154 return nil, fmt.Errorf("ast.Variable with type map has value which is not a map[string]ast.Variable")
155 }
156
157 result := make(map[string]interface{}, 0)
158 if len(inputMap) == 0 {
159 return result, nil
160 }
161
162 for key, value := range inputMap {
163 if convertedValue, err := VariableToInterface(value); err == nil {
164 result[key] = convertedValue
165 } else {
166 return nil, err
167 }
168 }
169
170 return result, nil
171 }
172
173 return nil, fmt.Errorf("unknown input type: %s", input.Type)
174 }