]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/zclconf/go-cty/cty/msgpack/unmarshal.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / msgpack / unmarshal.go
1 package msgpack
2
3 import (
4 "bytes"
5
6 "github.com/vmihailenco/msgpack"
7 msgpackCodes "github.com/vmihailenco/msgpack/codes"
8 "github.com/zclconf/go-cty/cty"
9 )
10
11 // Unmarshal interprets the given bytes as a msgpack-encoded cty Value of
12 // the given type, returning the result.
13 //
14 // If an error is returned, the error is written with a hypothetical
15 // end-user that wrote the msgpack file as its audience, using cty type
16 // system concepts rather than Go type system concepts.
17 func Unmarshal(b []byte, ty cty.Type) (cty.Value, error) {
18 r := bytes.NewReader(b)
19 dec := msgpack.NewDecoder(r)
20
21 var path cty.Path
22 return unmarshal(dec, ty, path)
23 }
24
25 func unmarshal(dec *msgpack.Decoder, ty cty.Type, path cty.Path) (cty.Value, error) {
26 peek, err := dec.PeekCode()
27 if err != nil {
28 return cty.DynamicVal, path.NewError(err)
29 }
30 if msgpackCodes.IsExt(peek) {
31 // We just assume _all_ extensions are unknown values,
32 // since we don't have any other extensions.
33 dec.Skip() // skip what we've peeked
34 return cty.UnknownVal(ty), nil
35 }
36 if ty == cty.DynamicPseudoType {
37 return unmarshalDynamic(dec, path)
38 }
39 if peek == msgpackCodes.Nil {
40 dec.Skip() // skip what we've peeked
41 return cty.NullVal(ty), nil
42 }
43
44 switch {
45 case ty.IsPrimitiveType():
46 val, err := unmarshalPrimitive(dec, ty, path)
47 if err != nil {
48 return cty.NilVal, err
49 }
50 return val, nil
51 case ty.IsListType():
52 return unmarshalList(dec, ty.ElementType(), path)
53 case ty.IsSetType():
54 return unmarshalSet(dec, ty.ElementType(), path)
55 case ty.IsMapType():
56 return unmarshalMap(dec, ty.ElementType(), path)
57 case ty.IsTupleType():
58 return unmarshalTuple(dec, ty.TupleElementTypes(), path)
59 case ty.IsObjectType():
60 return unmarshalObject(dec, ty.AttributeTypes(), path)
61 default:
62 return cty.NilVal, path.NewErrorf("unsupported type %s", ty.FriendlyName())
63 }
64 }
65
66 func unmarshalPrimitive(dec *msgpack.Decoder, ty cty.Type, path cty.Path) (cty.Value, error) {
67 switch ty {
68 case cty.Bool:
69 rv, err := dec.DecodeBool()
70 if err != nil {
71 return cty.DynamicVal, path.NewErrorf("bool is required")
72 }
73 return cty.BoolVal(rv), nil
74 case cty.Number:
75 // Marshal will try int and float first, if the value can be
76 // losslessly represented in these encodings, and then fall
77 // back on a string if the number is too large or too precise.
78 peek, err := dec.PeekCode()
79 if err != nil {
80 return cty.DynamicVal, path.NewErrorf("number is required")
81 }
82
83 if msgpackCodes.IsFixedNum(peek) {
84 rv, err := dec.DecodeInt64()
85 if err != nil {
86 return cty.DynamicVal, path.NewErrorf("number is required")
87 }
88 return cty.NumberIntVal(rv), nil
89 }
90
91 switch peek {
92 case msgpackCodes.Int8, msgpackCodes.Int16, msgpackCodes.Int32, msgpackCodes.Int64:
93 rv, err := dec.DecodeInt64()
94 if err != nil {
95 return cty.DynamicVal, path.NewErrorf("number is required")
96 }
97 return cty.NumberIntVal(rv), nil
98 case msgpackCodes.Uint8, msgpackCodes.Uint16, msgpackCodes.Uint32, msgpackCodes.Uint64:
99 rv, err := dec.DecodeUint64()
100 if err != nil {
101 return cty.DynamicVal, path.NewErrorf("number is required")
102 }
103 return cty.NumberUIntVal(rv), nil
104 case msgpackCodes.Float, msgpackCodes.Double:
105 rv, err := dec.DecodeFloat64()
106 if err != nil {
107 return cty.DynamicVal, path.NewErrorf("number is required")
108 }
109 return cty.NumberFloatVal(rv), nil
110 default:
111 rv, err := dec.DecodeString()
112 if err != nil {
113 return cty.DynamicVal, path.NewErrorf("number is required")
114 }
115 v, err := cty.ParseNumberVal(rv)
116 if err != nil {
117 return cty.DynamicVal, path.NewErrorf("number is required")
118 }
119 return v, nil
120 }
121 case cty.String:
122 rv, err := dec.DecodeString()
123 if err != nil {
124 return cty.DynamicVal, path.NewErrorf("string is required")
125 }
126 return cty.StringVal(rv), nil
127 default:
128 // should never happen
129 panic("unsupported primitive type")
130 }
131 }
132
133 func unmarshalList(dec *msgpack.Decoder, ety cty.Type, path cty.Path) (cty.Value, error) {
134 length, err := dec.DecodeArrayLen()
135 if err != nil {
136 return cty.DynamicVal, path.NewErrorf("a list is required")
137 }
138
139 switch {
140 case length < 0:
141 return cty.NullVal(cty.List(ety)), nil
142 case length == 0:
143 return cty.ListValEmpty(ety), nil
144 }
145
146 vals := make([]cty.Value, 0, length)
147 path = append(path, nil)
148 for i := 0; i < length; i++ {
149 path[len(path)-1] = cty.IndexStep{
150 Key: cty.NumberIntVal(int64(i)),
151 }
152
153 val, err := unmarshal(dec, ety, path)
154 if err != nil {
155 return cty.DynamicVal, err
156 }
157
158 vals = append(vals, val)
159 }
160
161 return cty.ListVal(vals), nil
162 }
163
164 func unmarshalSet(dec *msgpack.Decoder, ety cty.Type, path cty.Path) (cty.Value, error) {
165 length, err := dec.DecodeArrayLen()
166 if err != nil {
167 return cty.DynamicVal, path.NewErrorf("a set is required")
168 }
169
170 switch {
171 case length < 0:
172 return cty.NullVal(cty.Set(ety)), nil
173 case length == 0:
174 return cty.SetValEmpty(ety), nil
175 }
176
177 vals := make([]cty.Value, 0, length)
178 path = append(path, nil)
179 for i := 0; i < length; i++ {
180 path[len(path)-1] = cty.IndexStep{
181 Key: cty.NumberIntVal(int64(i)),
182 }
183
184 val, err := unmarshal(dec, ety, path)
185 if err != nil {
186 return cty.DynamicVal, err
187 }
188
189 vals = append(vals, val)
190 }
191
192 return cty.SetVal(vals), nil
193 }
194
195 func unmarshalMap(dec *msgpack.Decoder, ety cty.Type, path cty.Path) (cty.Value, error) {
196 length, err := dec.DecodeMapLen()
197 if err != nil {
198 return cty.DynamicVal, path.NewErrorf("a map is required")
199 }
200
201 switch {
202 case length < 0:
203 return cty.NullVal(cty.Map(ety)), nil
204 case length == 0:
205 return cty.MapValEmpty(ety), nil
206 }
207
208 vals := make(map[string]cty.Value, length)
209 path = append(path, nil)
210 for i := 0; i < length; i++ {
211 key, err := dec.DecodeString()
212 if err != nil {
213 path[:len(path)-1].NewErrorf("non-string key in map")
214 }
215
216 path[len(path)-1] = cty.IndexStep{
217 Key: cty.StringVal(key),
218 }
219
220 val, err := unmarshal(dec, ety, path)
221 if err != nil {
222 return cty.DynamicVal, err
223 }
224
225 vals[key] = val
226 }
227
228 return cty.MapVal(vals), nil
229 }
230
231 func unmarshalTuple(dec *msgpack.Decoder, etys []cty.Type, path cty.Path) (cty.Value, error) {
232 length, err := dec.DecodeArrayLen()
233 if err != nil {
234 return cty.DynamicVal, path.NewErrorf("a tuple is required")
235 }
236
237 switch {
238 case length < 0:
239 return cty.NullVal(cty.Tuple(etys)), nil
240 case length == 0:
241 return cty.TupleVal(nil), nil
242 case length != len(etys):
243 return cty.DynamicVal, path.NewErrorf("a tuple of length %d is required", len(etys))
244 }
245
246 vals := make([]cty.Value, 0, length)
247 path = append(path, nil)
248 for i := 0; i < length; i++ {
249 path[len(path)-1] = cty.IndexStep{
250 Key: cty.NumberIntVal(int64(i)),
251 }
252 ety := etys[i]
253
254 val, err := unmarshal(dec, ety, path)
255 if err != nil {
256 return cty.DynamicVal, err
257 }
258
259 vals = append(vals, val)
260 }
261
262 return cty.TupleVal(vals), nil
263 }
264
265 func unmarshalObject(dec *msgpack.Decoder, atys map[string]cty.Type, path cty.Path) (cty.Value, error) {
266 length, err := dec.DecodeMapLen()
267 if err != nil {
268 return cty.DynamicVal, path.NewErrorf("an object is required")
269 }
270
271 switch {
272 case length < 0:
273 return cty.NullVal(cty.Object(atys)), nil
274 case length == 0:
275 return cty.ObjectVal(nil), nil
276 case length != len(atys):
277 return cty.DynamicVal, path.NewErrorf("an object with %d attributes is required (%d given)",
278 len(atys), length)
279 }
280
281 vals := make(map[string]cty.Value, length)
282 path = append(path, nil)
283 for i := 0; i < length; i++ {
284 key, err := dec.DecodeString()
285 if err != nil {
286 return cty.DynamicVal, path[:len(path)-1].NewErrorf("all keys must be strings")
287 }
288
289 path[len(path)-1] = cty.IndexStep{
290 Key: cty.StringVal(key),
291 }
292 aty, exists := atys[key]
293 if !exists {
294 return cty.DynamicVal, path.NewErrorf("unsupported attribute")
295 }
296
297 val, err := unmarshal(dec, aty, path)
298 if err != nil {
299 return cty.DynamicVal, err
300 }
301
302 vals[key] = val
303 }
304
305 return cty.ObjectVal(vals), nil
306 }
307
308 func unmarshalDynamic(dec *msgpack.Decoder, path cty.Path) (cty.Value, error) {
309 length, err := dec.DecodeArrayLen()
310 if err != nil {
311 return cty.DynamicVal, path.NewError(err)
312 }
313
314 switch {
315 case length == -1:
316 return cty.NullVal(cty.DynamicPseudoType), nil
317 case length != 2:
318 return cty.DynamicVal, path.NewErrorf(
319 "dynamic value array must have exactly two elements",
320 )
321 }
322
323 typeJSON, err := dec.DecodeBytes()
324 if err != nil {
325 return cty.DynamicVal, path.NewError(err)
326 }
327 var ty cty.Type
328 err = (&ty).UnmarshalJSON(typeJSON)
329 if err != nil {
330 return cty.DynamicVal, path.NewError(err)
331 }
332
333 return unmarshal(dec, ty, path)
334 }