github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/typeexpr/type_type.go (about)

     1  package typeexpr
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	"github.com/hashicorp/hcl/v2"
     8  	"github.com/hashicorp/hcl/v2/ext/customdecode"
     9  	"github.com/zclconf/go-cty/cty"
    10  	"github.com/zclconf/go-cty/cty/convert"
    11  	"github.com/zclconf/go-cty/cty/function"
    12  )
    13  
    14  // TypeConstraintType is a cty capsule type that allows cty type constraints to
    15  // be used as values.
    16  //
    17  // If TypeConstraintType is used in a context supporting the
    18  // customdecode.CustomExpressionDecoder extension then it will implement
    19  // expression decoding using the TypeConstraint function, thus allowing
    20  // type expressions to be used in contexts where value expressions might
    21  // normally be expected, such as in arguments to function calls.
    22  var TypeConstraintType cty.Type
    23  
    24  // TypeConstraintVal constructs a cty.Value whose type is
    25  // TypeConstraintType.
    26  func TypeConstraintVal(ty cty.Type) cty.Value {
    27  	return cty.CapsuleVal(TypeConstraintType, &ty)
    28  }
    29  
    30  // TypeConstraintFromVal extracts the type from a cty.Value of
    31  // TypeConstraintType that was previously constructed using TypeConstraintVal.
    32  //
    33  // If the given value isn't a known, non-null value of TypeConstraintType
    34  // then this function will panic.
    35  func TypeConstraintFromVal(v cty.Value) cty.Type {
    36  	if !v.Type().Equals(TypeConstraintType) {
    37  		panic("value is not of TypeConstraintType")
    38  	}
    39  	ptr := v.EncapsulatedValue().(*cty.Type)
    40  	return *ptr
    41  }
    42  
    43  // ConvertFunc is a cty function that implements type conversions.
    44  //
    45  // Its signature is as follows:
    46  //     convert(value, type_constraint)
    47  //
    48  // ...where type_constraint is a type constraint expression as defined by
    49  // typeexpr.TypeConstraint.
    50  //
    51  // It relies on HCL's customdecode extension and so it's not suitable for use
    52  // in non-HCL contexts or if you are using a HCL syntax implementation that
    53  // does not support customdecode for function arguments. However, it _is_
    54  // supported for function calls in the HCL native expression syntax.
    55  var ConvertFunc function.Function
    56  
    57  func init() {
    58  	TypeConstraintType = cty.CapsuleWithOps("type constraint", reflect.TypeOf(cty.Type{}), &cty.CapsuleOps{
    59  		ExtensionData: func(key interface{}) interface{} {
    60  			switch key {
    61  			case customdecode.CustomExpressionDecoder:
    62  				return customdecode.CustomExpressionDecoderFunc(
    63  					func(expr hcl.Expression, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
    64  						ty, diags := TypeConstraint(expr)
    65  						if diags.HasErrors() {
    66  							return cty.NilVal, diags
    67  						}
    68  						return TypeConstraintVal(ty), nil
    69  					},
    70  				)
    71  			default:
    72  				return nil
    73  			}
    74  		},
    75  		TypeGoString: func(_ reflect.Type) string {
    76  			return "typeexpr.TypeConstraintType"
    77  		},
    78  		GoString: func(raw interface{}) string {
    79  			tyPtr := raw.(*cty.Type)
    80  			return fmt.Sprintf("typeexpr.TypeConstraintVal(%#v)", *tyPtr)
    81  		},
    82  		RawEquals: func(a, b interface{}) bool {
    83  			aPtr := a.(*cty.Type)
    84  			bPtr := b.(*cty.Type)
    85  			return (*aPtr).Equals(*bPtr)
    86  		},
    87  	})
    88  
    89  	ConvertFunc = function.New(&function.Spec{
    90  		Params: []function.Parameter{
    91  			{
    92  				Name:             "value",
    93  				Type:             cty.DynamicPseudoType,
    94  				AllowNull:        true,
    95  				AllowDynamicType: true,
    96  			},
    97  			{
    98  				Name: "type",
    99  				Type: TypeConstraintType,
   100  			},
   101  		},
   102  		Type: func(args []cty.Value) (cty.Type, error) {
   103  			wantTypePtr := args[1].EncapsulatedValue().(*cty.Type)
   104  			got, err := convert.Convert(args[0], *wantTypePtr)
   105  			if err != nil {
   106  				return cty.NilType, function.NewArgError(0, err)
   107  			}
   108  			return got.Type(), nil
   109  		},
   110  		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
   111  			v, err := convert.Convert(args[0], retType)
   112  			if err != nil {
   113  				return cty.NilVal, function.NewArgError(0, err)
   114  			}
   115  			return v, nil
   116  		},
   117  	})
   118  }