]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blobdiff - vendor/github.com/hashicorp/hil/convert.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / hil / convert.go
diff --git a/vendor/github.com/hashicorp/hil/convert.go b/vendor/github.com/hashicorp/hil/convert.go
new file mode 100644 (file)
index 0000000..f2024d0
--- /dev/null
@@ -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)
+}