]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/zclconf/go-cty/cty/path.go
update vendor and go.mod
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / path.go
CommitLineData
15c0b25d
AP
1package cty
2
3import (
4 "errors"
5 "fmt"
6)
7
8// A Path is a sequence of operations to locate a nested value within a
9// data structure.
10//
11// The empty Path represents the given item. Any PathSteps within represent
12// taking a single step down into a data structure.
13//
14// Path has some convenience methods for gradually constructing a path,
15// but callers can also feel free to just produce a slice of PathStep manually
16// and convert to this type, which may be more appropriate in environments
17// where memory pressure is a concern.
107c1cdb
ND
18//
19// Although a Path is technically mutable, by convention callers should not
20// mutate a path once it has been built and passed to some other subsystem.
21// Instead, use Copy and then mutate the copy before using it.
15c0b25d
AP
22type Path []PathStep
23
24// PathStep represents a single step down into a data structure, as part
25// of a Path. PathStep is a closed interface, meaning that the only
26// permitted implementations are those within this package.
27type PathStep interface {
28 pathStepSigil() pathStepImpl
29 Apply(Value) (Value, error)
30}
31
32// embed pathImpl into a struct to declare it a PathStep implementation
33type pathStepImpl struct{}
34
35func (p pathStepImpl) pathStepSigil() pathStepImpl {
36 return p
37}
38
39// Index returns a new Path that is the reciever with an IndexStep appended
40// to the end.
41//
42// This is provided as a convenient way to construct paths, but each call
43// will create garbage so it should not be used where memory pressure is a
44// concern.
45func (p Path) Index(v Value) Path {
46 ret := make(Path, len(p)+1)
47 copy(ret, p)
48 ret[len(p)] = IndexStep{
49 Key: v,
50 }
51 return ret
52}
53
107c1cdb
ND
54// IndexPath is a convenience method to start a new Path with an IndexStep.
55func IndexPath(v Value) Path {
56 return Path{}.Index(v)
57}
58
15c0b25d
AP
59// GetAttr returns a new Path that is the reciever with a GetAttrStep appended
60// to the end.
61//
62// This is provided as a convenient way to construct paths, but each call
63// will create garbage so it should not be used where memory pressure is a
64// concern.
65func (p Path) GetAttr(name string) Path {
66 ret := make(Path, len(p)+1)
67 copy(ret, p)
68 ret[len(p)] = GetAttrStep{
69 Name: name,
70 }
71 return ret
72}
73
863486a6
AG
74// Equals compares 2 Paths for exact equality.
75func (p Path) Equals(other Path) bool {
76 if len(p) != len(other) {
77 return false
78 }
79
80 for i := range p {
81 pv := p[i]
82 switch pv := pv.(type) {
83 case GetAttrStep:
84 ov, ok := other[i].(GetAttrStep)
85 if !ok || pv != ov {
86 return false
87 }
88 case IndexStep:
89 ov, ok := other[i].(IndexStep)
90 if !ok {
91 return false
92 }
93
94 if !pv.Key.RawEquals(ov.Key) {
95 return false
96 }
97 default:
98 // Any invalid steps default to evaluating false.
99 return false
100 }
101 }
102
103 return true
104
105}
106
107// HasPrefix determines if the path p contains the provided prefix.
108func (p Path) HasPrefix(prefix Path) bool {
109 if len(prefix) > len(p) {
110 return false
111 }
112
113 return p[:len(prefix)].Equals(prefix)
114}
115
107c1cdb
ND
116// GetAttrPath is a convenience method to start a new Path with a GetAttrStep.
117func GetAttrPath(name string) Path {
118 return Path{}.GetAttr(name)
119}
120
15c0b25d
AP
121// Apply applies each of the steps in turn to successive values starting with
122// the given value, and returns the result. If any step returns an error,
123// the whole operation returns an error.
124func (p Path) Apply(val Value) (Value, error) {
125 var err error
126 for i, step := range p {
127 val, err = step.Apply(val)
128 if err != nil {
129 return NilVal, fmt.Errorf("at step %d: %s", i, err)
130 }
131 }
132 return val, nil
133}
134
135// LastStep applies the given path up to the last step and then returns
136// the resulting value and the final step.
137//
138// This is useful when dealing with assignment operations, since in that
139// case the *value* of the last step is not important (and may not, in fact,
140// present at all) and we care only about its location.
141//
142// Since LastStep applies all steps except the last, it will return errors
143// for those steps in the same way as Apply does.
144//
145// If the path has *no* steps then the returned PathStep will be nil,
146// representing that any operation should be applied directly to the
147// given value.
148func (p Path) LastStep(val Value) (Value, PathStep, error) {
149 var err error
150
151 if len(p) == 0 {
152 return val, nil, nil
153 }
154
155 journey := p[:len(p)-1]
156 val, err = journey.Apply(val)
157 if err != nil {
158 return NilVal, nil, err
159 }
160 return val, p[len(p)-1], nil
161}
162
163// Copy makes a shallow copy of the receiver. Often when paths are passed to
164// caller code they come with the constraint that they are valid only until
165// the caller returns, due to how they are constructed internally. Callers
166// can use Copy to conveniently produce a copy of the value that _they_ control
167// the validity of.
168func (p Path) Copy() Path {
169 ret := make(Path, len(p))
170 copy(ret, p)
171 return ret
172}
173
174// IndexStep is a Step implementation representing applying the index operation
175// to a value, which must be of either a list, map, or set type.
176//
177// When describing a path through a *type* rather than a concrete value,
178// the Key may be an unknown value, indicating that the step applies to
179// *any* key of the given type.
180//
181// When indexing into a set, the Key is actually the element being accessed
182// itself, since in sets elements are their own identity.
183type IndexStep struct {
184 pathStepImpl
185 Key Value
186}
187
188// Apply returns the value resulting from indexing the given value with
189// our key value.
190func (s IndexStep) Apply(val Value) (Value, error) {
107c1cdb
ND
191 if val == NilVal || val.IsNull() {
192 return NilVal, errors.New("cannot index a null value")
193 }
194
15c0b25d
AP
195 switch s.Key.Type() {
196 case Number:
107c1cdb 197 if !(val.Type().IsListType() || val.Type().IsTupleType()) {
15c0b25d
AP
198 return NilVal, errors.New("not a list type")
199 }
200 case String:
201 if !val.Type().IsMapType() {
202 return NilVal, errors.New("not a map type")
203 }
204 default:
205 return NilVal, errors.New("key value not number or string")
206 }
207
208 has := val.HasIndex(s.Key)
209 if !has.IsKnown() {
210 return UnknownVal(val.Type().ElementType()), nil
211 }
212 if !has.True() {
213 return NilVal, errors.New("value does not have given index key")
214 }
215
216 return val.Index(s.Key), nil
217}
218
219func (s IndexStep) GoString() string {
220 return fmt.Sprintf("cty.IndexStep{Key:%#v}", s.Key)
221}
222
223// GetAttrStep is a Step implementation representing retrieving an attribute
224// from a value, which must be of an object type.
225type GetAttrStep struct {
226 pathStepImpl
227 Name string
228}
229
230// Apply returns the value of our named attribute from the given value, which
231// must be of an object type that has a value of that name.
232func (s GetAttrStep) Apply(val Value) (Value, error) {
107c1cdb
ND
233 if val == NilVal || val.IsNull() {
234 return NilVal, errors.New("cannot access attributes on a null value")
235 }
236
15c0b25d
AP
237 if !val.Type().IsObjectType() {
238 return NilVal, errors.New("not an object type")
239 }
240
241 if !val.Type().HasAttribute(s.Name) {
242 return NilVal, fmt.Errorf("object has no attribute %q", s.Name)
243 }
244
245 return val.GetAttr(s.Name), nil
246}
247
248func (s GetAttrStep) GoString() string {
249 return fmt.Sprintf("cty.GetAttrStep{Name:%q}", s.Name)
250}