]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/zclconf/go-cty/cty/msgpack/type_implied.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / msgpack / type_implied.go
1 package msgpack
2
3 import (
4 "bytes"
5 "fmt"
6 "io"
7
8 "github.com/vmihailenco/msgpack"
9 msgpackcodes "github.com/vmihailenco/msgpack/codes"
10 "github.com/zclconf/go-cty/cty"
11 )
12
13 // ImpliedType returns the cty Type implied by the structure of the given
14 // msgpack-compliant buffer. This function implements the default type mapping
15 // behavior used when decoding arbitrary msgpack without explicit cty Type
16 // information.
17 //
18 // The rules are as follows:
19 //
20 // msgpack strings, numbers and bools map to their equivalent primitive type in
21 // cty.
22 //
23 // msgpack maps become cty object types, with the attributes defined by the
24 // map keys and the types of their values.
25 //
26 // msgpack arrays become cty tuple types, with the elements defined by the
27 // types of the array members.
28 //
29 // Any nulls are typed as DynamicPseudoType, so callers of this function
30 // must be prepared to deal with this. Callers that do not wish to deal with
31 // dynamic typing should not use this function and should instead describe
32 // their required types explicitly with a cty.Type instance when decoding.
33 //
34 // Any unknown values are similarly typed as DynamicPseudoType, because these
35 // do not carry type information on the wire.
36 //
37 // Any parse errors will be returned as an error, and the type will be the
38 // invalid value cty.NilType.
39 func ImpliedType(buf []byte) (cty.Type, error) {
40 r := bytes.NewReader(buf)
41 dec := msgpack.NewDecoder(r)
42
43 ty, err := impliedType(dec)
44 if err != nil {
45 return cty.NilType, err
46 }
47
48 // We must now be at the end of the buffer
49 err = dec.Skip()
50 if err != io.EOF {
51 return ty, fmt.Errorf("extra bytes after msgpack value")
52 }
53
54 return ty, nil
55 }
56
57 func impliedType(dec *msgpack.Decoder) (cty.Type, error) {
58 // If this function returns with a nil error then it must have already
59 // consumed the next value from the decoder, since when called recursively
60 // the caller will be expecting to find a following value here.
61
62 code, err := dec.PeekCode()
63 if err != nil {
64 return cty.NilType, err
65 }
66
67 switch {
68
69 case code == msgpackcodes.Nil || msgpackcodes.IsExt(code):
70 err := dec.Skip()
71 return cty.DynamicPseudoType, err
72
73 case code == msgpackcodes.True || code == msgpackcodes.False:
74 _, err := dec.DecodeBool()
75 return cty.Bool, err
76
77 case msgpackcodes.IsFixedNum(code):
78 _, err := dec.DecodeInt64()
79 return cty.Number, err
80
81 case code == msgpackcodes.Int8 || code == msgpackcodes.Int16 || code == msgpackcodes.Int32 || code == msgpackcodes.Int64:
82 _, err := dec.DecodeInt64()
83 return cty.Number, err
84
85 case code == msgpackcodes.Uint8 || code == msgpackcodes.Uint16 || code == msgpackcodes.Uint32 || code == msgpackcodes.Uint64:
86 _, err := dec.DecodeUint64()
87 return cty.Number, err
88
89 case code == msgpackcodes.Float || code == msgpackcodes.Double:
90 _, err := dec.DecodeFloat64()
91 return cty.Number, err
92
93 case msgpackcodes.IsString(code):
94 _, err := dec.DecodeString()
95 return cty.String, err
96
97 case msgpackcodes.IsFixedMap(code) || code == msgpackcodes.Map16 || code == msgpackcodes.Map32:
98 return impliedObjectType(dec)
99
100 case msgpackcodes.IsFixedArray(code) || code == msgpackcodes.Array16 || code == msgpackcodes.Array32:
101 return impliedTupleType(dec)
102
103 default:
104 return cty.NilType, fmt.Errorf("unsupported msgpack code %#v", code)
105 }
106 }
107
108 func impliedObjectType(dec *msgpack.Decoder) (cty.Type, error) {
109 // If we get in here then we've already peeked the next code and know
110 // it's some sort of map.
111 l, err := dec.DecodeMapLen()
112 if err != nil {
113 return cty.DynamicPseudoType, nil
114 }
115
116 var atys map[string]cty.Type
117
118 for i := 0; i < l; i++ {
119 // Read the map key first. We require maps to be strings, but msgpack
120 // doesn't so we're prepared to error here if not.
121 k, err := dec.DecodeString()
122 if err != nil {
123 return cty.DynamicPseudoType, err
124 }
125
126 aty, err := impliedType(dec)
127 if err != nil {
128 return cty.DynamicPseudoType, err
129 }
130
131 if atys == nil {
132 atys = make(map[string]cty.Type)
133 }
134 atys[k] = aty
135 }
136
137 if len(atys) == 0 {
138 return cty.EmptyObject, nil
139 }
140
141 return cty.Object(atys), nil
142 }
143
144 func impliedTupleType(dec *msgpack.Decoder) (cty.Type, error) {
145 // If we get in here then we've already peeked the next code and know
146 // it's some sort of array.
147 l, err := dec.DecodeArrayLen()
148 if err != nil {
149 return cty.DynamicPseudoType, nil
150 }
151
152 if l == 0 {
153 return cty.EmptyTuple, nil
154 }
155
156 etys := make([]cty.Type, l)
157
158 for i := 0; i < l; i++ {
159 ety, err := impliedType(dec)
160 if err != nil {
161 return cty.DynamicPseudoType, err
162 }
163 etys[i] = ety
164 }
165
166 return cty.Tuple(etys), nil
167 }