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 }