]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | package stdlib |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | ||
6 | "github.com/zclconf/go-cty/cty" | |
7 | "github.com/zclconf/go-cty/cty/function" | |
8 | "github.com/zclconf/go-cty/cty/gocty" | |
9 | ) | |
10 | ||
11 | var HasIndexFunc = function.New(&function.Spec{ | |
12 | Params: []function.Parameter{ | |
13 | { | |
14 | Name: "collection", | |
15 | Type: cty.DynamicPseudoType, | |
16 | AllowDynamicType: true, | |
17 | }, | |
18 | { | |
19 | Name: "key", | |
20 | Type: cty.DynamicPseudoType, | |
21 | AllowDynamicType: true, | |
22 | }, | |
23 | }, | |
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") | |
28 | } | |
29 | return cty.Bool, nil | |
30 | }, | |
31 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | |
32 | return args[0].HasIndex(args[1]), nil | |
33 | }, | |
34 | }) | |
35 | ||
36 | var IndexFunc = function.New(&function.Spec{ | |
37 | Params: []function.Parameter{ | |
38 | { | |
39 | Name: "collection", | |
40 | Type: cty.DynamicPseudoType, | |
41 | }, | |
42 | { | |
43 | Name: "key", | |
44 | Type: cty.DynamicPseudoType, | |
45 | AllowDynamicType: true, | |
46 | }, | |
47 | }, | |
48 | Type: func(args []cty.Value) (ret cty.Type, err error) { | |
49 | collTy := args[0].Type() | |
50 | key := args[1] | |
51 | keyTy := key.Type() | |
52 | switch { | |
53 | case collTy.IsTupleType(): | |
54 | if keyTy != cty.Number && keyTy != cty.DynamicPseudoType { | |
55 | return cty.NilType, fmt.Errorf("key for tuple must be number") | |
56 | } | |
57 | if !key.IsKnown() { | |
58 | return cty.DynamicPseudoType, nil | |
59 | } | |
60 | var idx int | |
61 | err := gocty.FromCtyValue(key, &idx) | |
62 | if err != nil { | |
63 | return cty.NilType, fmt.Errorf("invalid key for tuple: %s", err) | |
64 | } | |
65 | ||
66 | etys := collTy.TupleElementTypes() | |
67 | ||
68 | if idx >= len(etys) || idx < 0 { | |
69 | return cty.NilType, fmt.Errorf("key must be between 0 and %d inclusive", len(etys)) | |
70 | } | |
71 | ||
72 | return etys[idx], nil | |
73 | ||
74 | case collTy.IsListType(): | |
75 | if keyTy != cty.Number && keyTy != cty.DynamicPseudoType { | |
76 | return cty.NilType, fmt.Errorf("key for list must be number") | |
77 | } | |
78 | ||
79 | return collTy.ElementType(), nil | |
80 | ||
81 | case collTy.IsMapType(): | |
82 | if keyTy != cty.String && keyTy != cty.DynamicPseudoType { | |
83 | return cty.NilType, fmt.Errorf("key for map must be string") | |
84 | } | |
85 | ||
86 | return collTy.ElementType(), nil | |
87 | ||
88 | default: | |
89 | return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple") | |
90 | } | |
91 | }, | |
92 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | |
93 | has, err := HasIndex(args[0], args[1]) | |
94 | if err != nil { | |
95 | return cty.NilVal, err | |
96 | } | |
97 | if has.False() { // safe because collection and key are guaranteed known here | |
98 | return cty.NilVal, fmt.Errorf("invalid index") | |
99 | } | |
100 | ||
101 | return args[0].Index(args[1]), nil | |
102 | }, | |
103 | }) | |
104 | ||
105 | var LengthFunc = function.New(&function.Spec{ | |
106 | Params: []function.Parameter{ | |
107 | { | |
108 | Name: "collection", | |
109 | Type: cty.DynamicPseudoType, | |
110 | AllowDynamicType: true, | |
111 | }, | |
112 | }, | |
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") | |
117 | } | |
118 | return cty.Number, nil | |
119 | }, | |
120 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | |
121 | return args[0].Length(), nil | |
122 | }, | |
123 | }) | |
124 | ||
125 | // HasIndex determines whether the given collection can be indexed with the | |
126 | // given key. | |
127 | func HasIndex(collection cty.Value, key cty.Value) (cty.Value, error) { | |
128 | return HasIndexFunc.Call([]cty.Value{collection, key}) | |
129 | } | |
130 | ||
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}) | |
135 | } | |
136 | ||
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}) | |
140 | } |