diff options
Diffstat (limited to 'vendor/github.com/zclconf/go-cty/cty/path.go')
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/path.go | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/vendor/github.com/zclconf/go-cty/cty/path.go b/vendor/github.com/zclconf/go-cty/cty/path.go new file mode 100644 index 0000000..84a9de0 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/path.go | |||
@@ -0,0 +1,186 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
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. | ||
18 | type Path []PathStep | ||
19 | |||
20 | // PathStep represents a single step down into a data structure, as part | ||
21 | // of a Path. PathStep is a closed interface, meaning that the only | ||
22 | // permitted implementations are those within this package. | ||
23 | type PathStep interface { | ||
24 | pathStepSigil() pathStepImpl | ||
25 | Apply(Value) (Value, error) | ||
26 | } | ||
27 | |||
28 | // embed pathImpl into a struct to declare it a PathStep implementation | ||
29 | type pathStepImpl struct{} | ||
30 | |||
31 | func (p pathStepImpl) pathStepSigil() pathStepImpl { | ||
32 | return p | ||
33 | } | ||
34 | |||
35 | // Index returns a new Path that is the reciever with an IndexStep appended | ||
36 | // to the end. | ||
37 | // | ||
38 | // This is provided as a convenient way to construct paths, but each call | ||
39 | // will create garbage so it should not be used where memory pressure is a | ||
40 | // concern. | ||
41 | func (p Path) Index(v Value) Path { | ||
42 | ret := make(Path, len(p)+1) | ||
43 | copy(ret, p) | ||
44 | ret[len(p)] = IndexStep{ | ||
45 | Key: v, | ||
46 | } | ||
47 | return ret | ||
48 | } | ||
49 | |||
50 | // GetAttr returns a new Path that is the reciever with a GetAttrStep appended | ||
51 | // to the end. | ||
52 | // | ||
53 | // This is provided as a convenient way to construct paths, but each call | ||
54 | // will create garbage so it should not be used where memory pressure is a | ||
55 | // concern. | ||
56 | func (p Path) GetAttr(name string) Path { | ||
57 | ret := make(Path, len(p)+1) | ||
58 | copy(ret, p) | ||
59 | ret[len(p)] = GetAttrStep{ | ||
60 | Name: name, | ||
61 | } | ||
62 | return ret | ||
63 | } | ||
64 | |||
65 | // Apply applies each of the steps in turn to successive values starting with | ||
66 | // the given value, and returns the result. If any step returns an error, | ||
67 | // the whole operation returns an error. | ||
68 | func (p Path) Apply(val Value) (Value, error) { | ||
69 | var err error | ||
70 | for i, step := range p { | ||
71 | val, err = step.Apply(val) | ||
72 | if err != nil { | ||
73 | return NilVal, fmt.Errorf("at step %d: %s", i, err) | ||
74 | } | ||
75 | } | ||
76 | return val, nil | ||
77 | } | ||
78 | |||
79 | // LastStep applies the given path up to the last step and then returns | ||
80 | // the resulting value and the final step. | ||
81 | // | ||
82 | // This is useful when dealing with assignment operations, since in that | ||
83 | // case the *value* of the last step is not important (and may not, in fact, | ||
84 | // present at all) and we care only about its location. | ||
85 | // | ||
86 | // Since LastStep applies all steps except the last, it will return errors | ||
87 | // for those steps in the same way as Apply does. | ||
88 | // | ||
89 | // If the path has *no* steps then the returned PathStep will be nil, | ||
90 | // representing that any operation should be applied directly to the | ||
91 | // given value. | ||
92 | func (p Path) LastStep(val Value) (Value, PathStep, error) { | ||
93 | var err error | ||
94 | |||
95 | if len(p) == 0 { | ||
96 | return val, nil, nil | ||
97 | } | ||
98 | |||
99 | journey := p[:len(p)-1] | ||
100 | val, err = journey.Apply(val) | ||
101 | if err != nil { | ||
102 | return NilVal, nil, err | ||
103 | } | ||
104 | return val, p[len(p)-1], nil | ||
105 | } | ||
106 | |||
107 | // Copy makes a shallow copy of the receiver. Often when paths are passed to | ||
108 | // caller code they come with the constraint that they are valid only until | ||
109 | // the caller returns, due to how they are constructed internally. Callers | ||
110 | // can use Copy to conveniently produce a copy of the value that _they_ control | ||
111 | // the validity of. | ||
112 | func (p Path) Copy() Path { | ||
113 | ret := make(Path, len(p)) | ||
114 | copy(ret, p) | ||
115 | return ret | ||
116 | } | ||
117 | |||
118 | // IndexStep is a Step implementation representing applying the index operation | ||
119 | // to a value, which must be of either a list, map, or set type. | ||
120 | // | ||
121 | // When describing a path through a *type* rather than a concrete value, | ||
122 | // the Key may be an unknown value, indicating that the step applies to | ||
123 | // *any* key of the given type. | ||
124 | // | ||
125 | // When indexing into a set, the Key is actually the element being accessed | ||
126 | // itself, since in sets elements are their own identity. | ||
127 | type IndexStep struct { | ||
128 | pathStepImpl | ||
129 | Key Value | ||
130 | } | ||
131 | |||
132 | // Apply returns the value resulting from indexing the given value with | ||
133 | // our key value. | ||
134 | func (s IndexStep) Apply(val Value) (Value, error) { | ||
135 | switch s.Key.Type() { | ||
136 | case Number: | ||
137 | if !val.Type().IsListType() { | ||
138 | return NilVal, errors.New("not a list type") | ||
139 | } | ||
140 | case String: | ||
141 | if !val.Type().IsMapType() { | ||
142 | return NilVal, errors.New("not a map type") | ||
143 | } | ||
144 | default: | ||
145 | return NilVal, errors.New("key value not number or string") | ||
146 | } | ||
147 | |||
148 | has := val.HasIndex(s.Key) | ||
149 | if !has.IsKnown() { | ||
150 | return UnknownVal(val.Type().ElementType()), nil | ||
151 | } | ||
152 | if !has.True() { | ||
153 | return NilVal, errors.New("value does not have given index key") | ||
154 | } | ||
155 | |||
156 | return val.Index(s.Key), nil | ||
157 | } | ||
158 | |||
159 | func (s IndexStep) GoString() string { | ||
160 | return fmt.Sprintf("cty.IndexStep{Key:%#v}", s.Key) | ||
161 | } | ||
162 | |||
163 | // GetAttrStep is a Step implementation representing retrieving an attribute | ||
164 | // from a value, which must be of an object type. | ||
165 | type GetAttrStep struct { | ||
166 | pathStepImpl | ||
167 | Name string | ||
168 | } | ||
169 | |||
170 | // Apply returns the value of our named attribute from the given value, which | ||
171 | // must be of an object type that has a value of that name. | ||
172 | func (s GetAttrStep) Apply(val Value) (Value, error) { | ||
173 | if !val.Type().IsObjectType() { | ||
174 | return NilVal, errors.New("not an object type") | ||
175 | } | ||
176 | |||
177 | if !val.Type().HasAttribute(s.Name) { | ||
178 | return NilVal, fmt.Errorf("object has no attribute %q", s.Name) | ||
179 | } | ||
180 | |||
181 | return val.GetAttr(s.Name), nil | ||
182 | } | ||
183 | |||
184 | func (s GetAttrStep) GoString() string { | ||
185 | return fmt.Sprintf("cty.GetAttrStep{Name:%q}", s.Name) | ||
186 | } | ||