]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/zclconf/go-cty/cty/json/type_implied.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / json / type_implied.go
CommitLineData
15c0b25d
AP
1package json
2
3import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7
8 "github.com/zclconf/go-cty/cty"
9)
10
11// ImpliedType returns the cty Type implied by the structure of the given
12// JSON-compliant buffer. This function implements the default type mapping
13// behavior used when decoding arbitrary JSON without explicit cty Type
14// information.
15//
16// The rules are as follows:
17//
18// JSON strings, numbers and bools map to their equivalent primitive type in
19// cty.
20//
21// JSON objects map to cty object types, with the attributes defined by the
22// object keys and the types of their values.
23//
24// JSON arrays map to cty tuple types, with the elements defined by the
25// types of the array members.
26//
27// Any nulls are typed as DynamicPseudoType, so callers of this function
28// must be prepared to deal with this. Callers that do not wish to deal with
29// dynamic typing should not use this function and should instead describe
30// their required types explicitly with a cty.Type instance when decoding.
31//
32// Any JSON syntax errors will be returned as an error, and the type will
33// be the invalid value cty.NilType.
34func ImpliedType(buf []byte) (cty.Type, error) {
35 r := bytes.NewReader(buf)
36 dec := json.NewDecoder(r)
37 dec.UseNumber()
38
39 ty, err := impliedType(dec)
40 if err != nil {
41 return cty.NilType, err
42 }
43
44 if dec.More() {
45 return cty.NilType, fmt.Errorf("extraneous data after JSON object")
46 }
47
48 return ty, nil
49}
50
51func impliedType(dec *json.Decoder) (cty.Type, error) {
52 tok, err := dec.Token()
53 if err != nil {
54 return cty.NilType, err
55 }
56
57 return impliedTypeForTok(tok, dec)
58}
59
60func impliedTypeForTok(tok json.Token, dec *json.Decoder) (cty.Type, error) {
61 if tok == nil {
62 return cty.DynamicPseudoType, nil
63 }
64
65 switch ttok := tok.(type) {
66 case bool:
67 return cty.Bool, nil
68
69 case json.Number:
70 return cty.Number, nil
71
72 case string:
73 return cty.String, nil
74
75 case json.Delim:
76
77 switch rune(ttok) {
78 case '{':
79 return impliedObjectType(dec)
80 case '[':
81 return impliedTupleType(dec)
82 default:
83 return cty.NilType, fmt.Errorf("unexpected token %q", ttok)
84 }
85
86 default:
87 return cty.NilType, fmt.Errorf("unsupported JSON token %#v", tok)
88 }
89}
90
91func impliedObjectType(dec *json.Decoder) (cty.Type, error) {
92 // By the time we get in here, we've already consumed the { delimiter
93 // and so our next token should be the first object key.
94
95 var atys map[string]cty.Type
96
97 for {
98 // Read the object key first
99 tok, err := dec.Token()
100 if err != nil {
101 return cty.NilType, err
102 }
103
104 if ttok, ok := tok.(json.Delim); ok {
105 if rune(ttok) != '}' {
106 return cty.NilType, fmt.Errorf("unexpected delimiter %q", ttok)
107 }
108 break
109 }
110
111 key, ok := tok.(string)
112 if !ok {
113 return cty.NilType, fmt.Errorf("expected string but found %T", tok)
114 }
115
116 // Now read the value
117 tok, err = dec.Token()
118 if err != nil {
119 return cty.NilType, err
120 }
121
122 aty, err := impliedTypeForTok(tok, dec)
123 if err != nil {
124 return cty.NilType, err
125 }
126
127 if atys == nil {
128 atys = make(map[string]cty.Type)
129 }
130 atys[key] = aty
131 }
132
133 if len(atys) == 0 {
134 return cty.EmptyObject, nil
135 }
136
137 return cty.Object(atys), nil
138}
139
140func impliedTupleType(dec *json.Decoder) (cty.Type, error) {
107c1cdb 141 // By the time we get in here, we've already consumed the [ delimiter
15c0b25d
AP
142 // and so our next token should be the first value.
143
144 var etys []cty.Type
145
146 for {
147 tok, err := dec.Token()
148 if err != nil {
149 return cty.NilType, err
150 }
151
152 if ttok, ok := tok.(json.Delim); ok {
107c1cdb
ND
153 if rune(ttok) == ']' {
154 break
15c0b25d 155 }
15c0b25d
AP
156 }
157
158 ety, err := impliedTypeForTok(tok, dec)
159 if err != nil {
160 return cty.NilType, err
161 }
162 etys = append(etys, ety)
163 }
164
165 if len(etys) == 0 {
166 return cty.EmptyTuple, nil
167 }
168
169 return cty.Tuple(etys), nil
170}