summaryrefslogtreecommitdiff
path: root/vendor/github.com/hashicorp/hil/convert.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/hil/convert.go')
-rw-r--r--vendor/github.com/hashicorp/hil/convert.go159
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 00000000..f2024d01
--- /dev/null
+++ b/vendor/github.com/hashicorp/hil/convert.go
@@ -0,0 +1,159 @@
+package hil
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/hashicorp/hil/ast"
+ "github.com/mitchellh/mapstructure"
+)
+
+// UnknownValue is a sentinel value that can be used to denote
+// that a value of a variable (or map element, list element, etc.)
+// is unknown. This will always have the type ast.TypeUnknown.
+const UnknownValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
+
+var hilMapstructureDecodeHookSlice []interface{}
+var hilMapstructureDecodeHookStringSlice []string
+var hilMapstructureDecodeHookMap map[string]interface{}
+
+// hilMapstructureWeakDecode behaves in the same way as mapstructure.WeakDecode
+// but has a DecodeHook which defeats the backward compatibility mode of mapstructure
+// which WeakDecodes []interface{}{} into an empty map[string]interface{}. This
+// allows us to use WeakDecode (desirable), but not fail on empty lists.
+func hilMapstructureWeakDecode(m interface{}, rawVal interface{}) error {
+ config := &mapstructure.DecoderConfig{
+ DecodeHook: func(source reflect.Type, target reflect.Type, val interface{}) (interface{}, error) {
+ sliceType := reflect.TypeOf(hilMapstructureDecodeHookSlice)
+ stringSliceType := reflect.TypeOf(hilMapstructureDecodeHookStringSlice)
+ mapType := reflect.TypeOf(hilMapstructureDecodeHookMap)
+
+ if (source == sliceType || source == stringSliceType) && target == mapType {
+ return nil, fmt.Errorf("Cannot convert %s into a %s", source, target)
+ }
+
+ return val, nil
+ },
+ WeaklyTypedInput: true,
+ Result: rawVal,
+ }
+
+ decoder, err := mapstructure.NewDecoder(config)
+ if err != nil {
+ return err
+ }
+
+ return decoder.Decode(m)
+}
+
+func InterfaceToVariable(input interface{}) (ast.Variable, error) {
+ if inputVariable, ok := input.(ast.Variable); ok {
+ return inputVariable, nil
+ }
+
+ var stringVal string
+ if err := hilMapstructureWeakDecode(input, &stringVal); err == nil {
+ // Special case the unknown value to turn into "unknown"
+ if stringVal == UnknownValue {
+ return ast.Variable{Value: UnknownValue, Type: ast.TypeUnknown}, nil
+ }
+
+ // Otherwise return the string value
+ return ast.Variable{
+ Type: ast.TypeString,
+ Value: stringVal,
+ }, nil
+ }
+
+ var mapVal map[string]interface{}
+ if err := hilMapstructureWeakDecode(input, &mapVal); err == nil {
+ elements := make(map[string]ast.Variable)
+ for i, element := range mapVal {
+ varElement, err := InterfaceToVariable(element)
+ if err != nil {
+ return ast.Variable{}, err
+ }
+ elements[i] = varElement
+ }
+
+ return ast.Variable{
+ Type: ast.TypeMap,
+ Value: elements,
+ }, nil
+ }
+
+ var sliceVal []interface{}
+ if err := hilMapstructureWeakDecode(input, &sliceVal); err == nil {
+ elements := make([]ast.Variable, len(sliceVal))
+ for i, element := range sliceVal {
+ varElement, err := InterfaceToVariable(element)
+ if err != nil {
+ return ast.Variable{}, err
+ }
+ elements[i] = varElement
+ }
+
+ return ast.Variable{
+ Type: ast.TypeList,
+ Value: elements,
+ }, nil
+ }
+
+ return ast.Variable{}, fmt.Errorf("value for conversion must be a string, interface{} or map[string]interface: got %T", input)
+}
+
+func VariableToInterface(input ast.Variable) (interface{}, error) {
+ if input.Type == ast.TypeString {
+ if inputStr, ok := input.Value.(string); ok {
+ return inputStr, nil
+ } else {
+ return nil, fmt.Errorf("ast.Variable with type string has value which is not a string")
+ }
+ }
+
+ if input.Type == ast.TypeList {
+ inputList, ok := input.Value.([]ast.Variable)
+ if !ok {
+ return nil, fmt.Errorf("ast.Variable with type list has value which is not a []ast.Variable")
+ }
+
+ result := make([]interface{}, 0)
+ if len(inputList) == 0 {
+ return result, nil
+ }
+
+ for _, element := range inputList {
+ if convertedElement, err := VariableToInterface(element); err == nil {
+ result = append(result, convertedElement)
+ } else {
+ return nil, err
+ }
+ }
+
+ return result, nil
+ }
+
+ if input.Type == ast.TypeMap {
+ inputMap, ok := input.Value.(map[string]ast.Variable)
+ if !ok {
+ return nil, fmt.Errorf("ast.Variable with type map has value which is not a map[string]ast.Variable")
+ }
+
+ result := make(map[string]interface{}, 0)
+ if len(inputMap) == 0 {
+ return result, nil
+ }
+
+ for key, value := range inputMap {
+ if convertedValue, err := VariableToInterface(value); err == nil {
+ result[key] = convertedValue
+ } else {
+ return nil, err
+ }
+ }
+
+ return result, nil
+ }
+
+ return nil, fmt.Errorf("unknown input type: %s", input.Type)
+}