6 "github.com/zclconf/go-cty/cty"
7 "github.com/zclconf/go-cty/cty/function"
8 "github.com/zclconf/go-cty/cty/gocty"
11 var HasIndexFunc = function.New(&function.Spec{
12 Params: []function.Parameter{
15 Type: cty.DynamicPseudoType,
16 AllowDynamicType: true,
20 Type: cty.DynamicPseudoType,
21 AllowDynamicType: true,
24 Type: func(args []cty.Value) (ret cty.Type, err error) {
25 collTy := args[0].Type()
26 if !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy == cty.DynamicPseudoType) {
27 return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple")
31 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
32 return args[0].HasIndex(args[1]), nil
36 var IndexFunc = function.New(&function.Spec{
37 Params: []function.Parameter{
40 Type: cty.DynamicPseudoType,
44 Type: cty.DynamicPseudoType,
45 AllowDynamicType: true,
48 Type: func(args []cty.Value) (ret cty.Type, err error) {
49 collTy := args[0].Type()
53 case collTy.IsTupleType():
54 if keyTy != cty.Number && keyTy != cty.DynamicPseudoType {
55 return cty.NilType, fmt.Errorf("key for tuple must be number")
58 return cty.DynamicPseudoType, nil
61 err := gocty.FromCtyValue(key, &idx)
63 return cty.NilType, fmt.Errorf("invalid key for tuple: %s", err)
66 etys := collTy.TupleElementTypes()
68 if idx >= len(etys) || idx < 0 {
69 return cty.NilType, fmt.Errorf("key must be between 0 and %d inclusive", len(etys))
74 case collTy.IsListType():
75 if keyTy != cty.Number && keyTy != cty.DynamicPseudoType {
76 return cty.NilType, fmt.Errorf("key for list must be number")
79 return collTy.ElementType(), nil
81 case collTy.IsMapType():
82 if keyTy != cty.String && keyTy != cty.DynamicPseudoType {
83 return cty.NilType, fmt.Errorf("key for map must be string")
86 return collTy.ElementType(), nil
89 return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple")
92 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
93 has, err := HasIndex(args[0], args[1])
95 return cty.NilVal, err
97 if has.False() { // safe because collection and key are guaranteed known here
98 return cty.NilVal, fmt.Errorf("invalid index")
101 return args[0].Index(args[1]), nil
105 var LengthFunc = function.New(&function.Spec{
106 Params: []function.Parameter{
109 Type: cty.DynamicPseudoType,
110 AllowDynamicType: true,
113 Type: func(args []cty.Value) (ret cty.Type, err error) {
114 collTy := args[0].Type()
115 if !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType) {
116 return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple")
118 return cty.Number, nil
120 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
121 return args[0].Length(), nil
125 // HasIndex determines whether the given collection can be indexed with the
127 func HasIndex(collection cty.Value, key cty.Value) (cty.Value, error) {
128 return HasIndexFunc.Call([]cty.Value{collection, key})
131 // Index returns an element from the given collection using the given key,
132 // or returns an error if there is no element for the given key.
133 func Index(collection cty.Value, key cty.Value) (cty.Value, error) {
134 return IndexFunc.Call([]cty.Value{collection, key})
137 // Length returns the number of elements in the given collection.
138 func Length(collection cty.Value) (cty.Value, error) {
139 return LengthFunc.Call([]cty.Value{collection})