github.com/hernad/nomad@v1.6.112/helper/pluginutils/hclspecutils/type_expr.go (about)

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