github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/helper/pluginutils/hclspecutils/type_expr.go (about)

     1  package hclspecutils
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	"github.com/hashicorp/hcl2/hcl"
     8  	"github.com/zclconf/go-cty/cty"
     9  	"github.com/zclconf/go-cty/cty/function"
    10  )
    11  
    12  var typeType = cty.Capsule("type", reflect.TypeOf(cty.NilType))
    13  
    14  var typeEvalCtx = &hcl.EvalContext{
    15  	Variables: map[string]cty.Value{
    16  		"string": wrapTypeType(cty.String),
    17  		"bool":   wrapTypeType(cty.Bool),
    18  		"number": wrapTypeType(cty.Number),
    19  		"any":    wrapTypeType(cty.DynamicPseudoType),
    20  	},
    21  	Functions: map[string]function.Function{
    22  		"list": function.New(&function.Spec{
    23  			Params: []function.Parameter{
    24  				{
    25  					Name: "element_type",
    26  					Type: typeType,
    27  				},
    28  			},
    29  			Type: function.StaticReturnType(typeType),
    30  			Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
    31  				ety := unwrapTypeType(args[0])
    32  				ty := cty.List(ety)
    33  				return wrapTypeType(ty), nil
    34  			},
    35  		}),
    36  		"set": function.New(&function.Spec{
    37  			Params: []function.Parameter{
    38  				{
    39  					Name: "element_type",
    40  					Type: typeType,
    41  				},
    42  			},
    43  			Type: function.StaticReturnType(typeType),
    44  			Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
    45  				ety := unwrapTypeType(args[0])
    46  				ty := cty.Set(ety)
    47  				return wrapTypeType(ty), nil
    48  			},
    49  		}),
    50  		"map": function.New(&function.Spec{
    51  			Params: []function.Parameter{
    52  				{
    53  					Name: "element_type",
    54  					Type: typeType,
    55  				},
    56  			},
    57  			Type: function.StaticReturnType(typeType),
    58  			Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
    59  				ety := unwrapTypeType(args[0])
    60  				ty := cty.Map(ety)
    61  				return wrapTypeType(ty), nil
    62  			},
    63  		}),
    64  		"tuple": function.New(&function.Spec{
    65  			Params: []function.Parameter{
    66  				{
    67  					Name: "element_types",
    68  					Type: cty.List(typeType),
    69  				},
    70  			},
    71  			Type: function.StaticReturnType(typeType),
    72  			Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
    73  				etysVal := args[0]
    74  				etys := make([]cty.Type, 0, etysVal.LengthInt())
    75  				for it := etysVal.ElementIterator(); it.Next(); {
    76  					_, wrapEty := it.Element()
    77  					etys = append(etys, unwrapTypeType(wrapEty))
    78  				}
    79  				ty := cty.Tuple(etys)
    80  				return wrapTypeType(ty), nil
    81  			},
    82  		}),
    83  		"object": function.New(&function.Spec{
    84  			Params: []function.Parameter{
    85  				{
    86  					Name: "attribute_types",
    87  					Type: cty.Map(typeType),
    88  				},
    89  			},
    90  			Type: function.StaticReturnType(typeType),
    91  			Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
    92  				atysVal := args[0]
    93  				atys := make(map[string]cty.Type)
    94  				for it := atysVal.ElementIterator(); it.Next(); {
    95  					nameVal, wrapAty := it.Element()
    96  					name := nameVal.AsString()
    97  					atys[name] = unwrapTypeType(wrapAty)
    98  				}
    99  				ty := cty.Object(atys)
   100  				return wrapTypeType(ty), nil
   101  			},
   102  		}),
   103  	},
   104  }
   105  
   106  func evalTypeExpr(expr hcl.Expression) (cty.Type, hcl.Diagnostics) {
   107  	result, diags := expr.Value(typeEvalCtx)
   108  	if result.IsNull() {
   109  		return cty.DynamicPseudoType, diags
   110  	}
   111  	if !result.Type().Equals(typeType) {
   112  		diags = append(diags, &hcl.Diagnostic{
   113  			Severity: hcl.DiagError,
   114  			Summary:  "Invalid type expression",
   115  			Detail:   fmt.Sprintf("A type is required, not %s.", result.Type().FriendlyName()),
   116  		})
   117  		return cty.DynamicPseudoType, diags
   118  	}
   119  
   120  	return unwrapTypeType(result), diags
   121  }
   122  
   123  func wrapTypeType(ty cty.Type) cty.Value {
   124  	return cty.CapsuleVal(typeType, &ty)
   125  }
   126  
   127  func unwrapTypeType(val cty.Value) cty.Type {
   128  	return *(val.EncapsulatedValue().(*cty.Type))
   129  }