diff options
Diffstat (limited to 'vendor/github.com/hashicorp/hil/convert.go')
-rw-r--r-- | vendor/github.com/hashicorp/hil/convert.go | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hil/convert.go b/vendor/github.com/hashicorp/hil/convert.go new file mode 100644 index 0000000..f2024d0 --- /dev/null +++ b/vendor/github.com/hashicorp/hil/convert.go | |||
@@ -0,0 +1,159 @@ | |||
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 inputVariable, ok := input.(ast.Variable); ok { | ||
51 | return inputVariable, nil | ||
52 | } | ||
53 | |||
54 | var stringVal string | ||
55 | if err := hilMapstructureWeakDecode(input, &stringVal); err == nil { | ||
56 | // Special case the unknown value to turn into "unknown" | ||
57 | if stringVal == UnknownValue { | ||
58 | return ast.Variable{Value: UnknownValue, Type: ast.TypeUnknown}, nil | ||
59 | } | ||
60 | |||
61 | // Otherwise return the string value | ||
62 | return ast.Variable{ | ||
63 | Type: ast.TypeString, | ||
64 | Value: stringVal, | ||
65 | }, nil | ||
66 | } | ||
67 | |||
68 | var mapVal map[string]interface{} | ||
69 | if err := hilMapstructureWeakDecode(input, &mapVal); err == nil { | ||
70 | elements := make(map[string]ast.Variable) | ||
71 | for i, element := range mapVal { | ||
72 | varElement, err := InterfaceToVariable(element) | ||
73 | if err != nil { | ||
74 | return ast.Variable{}, err | ||
75 | } | ||
76 | elements[i] = varElement | ||
77 | } | ||
78 | |||
79 | return ast.Variable{ | ||
80 | Type: ast.TypeMap, | ||
81 | Value: elements, | ||
82 | }, nil | ||
83 | } | ||
84 | |||
85 | var sliceVal []interface{} | ||
86 | if err := hilMapstructureWeakDecode(input, &sliceVal); err == nil { | ||
87 | elements := make([]ast.Variable, len(sliceVal)) | ||
88 | for i, element := range sliceVal { | ||
89 | varElement, err := InterfaceToVariable(element) | ||
90 | if err != nil { | ||
91 | return ast.Variable{}, err | ||
92 | } | ||
93 | elements[i] = varElement | ||
94 | } | ||
95 | |||
96 | return ast.Variable{ | ||
97 | Type: ast.TypeList, | ||
98 | Value: elements, | ||
99 | }, nil | ||
100 | } | ||
101 | |||
102 | return ast.Variable{}, fmt.Errorf("value for conversion must be a string, interface{} or map[string]interface: got %T", input) | ||
103 | } | ||
104 | |||
105 | func VariableToInterface(input ast.Variable) (interface{}, error) { | ||
106 | if input.Type == ast.TypeString { | ||
107 | if inputStr, ok := input.Value.(string); ok { | ||
108 | return inputStr, nil | ||
109 | } else { | ||
110 | return nil, fmt.Errorf("ast.Variable with type string has value which is not a string") | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if input.Type == ast.TypeList { | ||
115 | inputList, ok := input.Value.([]ast.Variable) | ||
116 | if !ok { | ||
117 | return nil, fmt.Errorf("ast.Variable with type list has value which is not a []ast.Variable") | ||
118 | } | ||
119 | |||
120 | result := make([]interface{}, 0) | ||
121 | if len(inputList) == 0 { | ||
122 | return result, nil | ||
123 | } | ||
124 | |||
125 | for _, element := range inputList { | ||
126 | if convertedElement, err := VariableToInterface(element); err == nil { | ||
127 | result = append(result, convertedElement) | ||
128 | } else { | ||
129 | return nil, err | ||
130 | } | ||
131 | } | ||
132 | |||
133 | return result, nil | ||
134 | } | ||
135 | |||
136 | if input.Type == ast.TypeMap { | ||
137 | inputMap, ok := input.Value.(map[string]ast.Variable) | ||
138 | if !ok { | ||
139 | return nil, fmt.Errorf("ast.Variable with type map has value which is not a map[string]ast.Variable") | ||
140 | } | ||
141 | |||
142 | result := make(map[string]interface{}, 0) | ||
143 | if len(inputMap) == 0 { | ||
144 | return result, nil | ||
145 | } | ||
146 | |||
147 | for key, value := range inputMap { | ||
148 | if convertedValue, err := VariableToInterface(value); err == nil { | ||
149 | result[key] = convertedValue | ||
150 | } else { | ||
151 | return nil, err | ||
152 | } | ||
153 | } | ||
154 | |||
155 | return result, nil | ||
156 | } | ||
157 | |||
158 | return nil, fmt.Errorf("unknown input type: %s", input.Type) | ||
159 | } | ||