diff options
Diffstat (limited to 'vendor/github.com/zclconf/go-cty/cty/json')
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/json/doc.go | 11 | ||||
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/json/marshal.go | 189 | ||||
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/json/simple.go | 41 | ||||
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/json/type.go | 23 | ||||
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/json/type_implied.go | 171 | ||||
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go | 459 | ||||
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/json/value.go | 65 |
7 files changed, 959 insertions, 0 deletions
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/doc.go b/vendor/github.com/zclconf/go-cty/cty/json/doc.go new file mode 100644 index 0000000..8916513 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/doc.go | |||
@@ -0,0 +1,11 @@ | |||
1 | // Package json provides functions for serializing cty types and values in | ||
2 | // JSON format, and for decoding them again. | ||
3 | // | ||
4 | // Since the cty type system is a superset of the JSON type system, | ||
5 | // round-tripping through JSON is lossy unless type information is provided | ||
6 | // both at encoding time and decoding time. Callers of this package are | ||
7 | // therefore suggested to define their expected structure as a cty.Type | ||
8 | // and pass it in consistently both when encoding and when decoding, though | ||
9 | // default (type-lossy) behavior is provided for situations where the precise | ||
10 | // representation of the data is not significant. | ||
11 | package json | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/marshal.go b/vendor/github.com/zclconf/go-cty/cty/json/marshal.go new file mode 100644 index 0000000..f7bea1a --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/marshal.go | |||
@@ -0,0 +1,189 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/json" | ||
6 | "sort" | ||
7 | |||
8 | "github.com/zclconf/go-cty/cty" | ||
9 | ) | ||
10 | |||
11 | func marshal(val cty.Value, t cty.Type, path cty.Path, b *bytes.Buffer) error { | ||
12 | // If we're going to decode as DynamicPseudoType then we need to save | ||
13 | // dynamic type information to recover the real type. | ||
14 | if t == cty.DynamicPseudoType && val.Type() != cty.DynamicPseudoType { | ||
15 | return marshalDynamic(val, path, b) | ||
16 | } | ||
17 | |||
18 | if val.IsNull() { | ||
19 | b.WriteString("null") | ||
20 | return nil | ||
21 | } | ||
22 | |||
23 | if !val.IsKnown() { | ||
24 | return path.NewErrorf("value is not known") | ||
25 | } | ||
26 | |||
27 | // The caller should've guaranteed that the given val is conformant with | ||
28 | // the given type t, so we'll proceed under that assumption here. | ||
29 | |||
30 | switch { | ||
31 | case t.IsPrimitiveType(): | ||
32 | switch t { | ||
33 | case cty.String: | ||
34 | json, err := json.Marshal(val.AsString()) | ||
35 | if err != nil { | ||
36 | return path.NewErrorf("failed to serialize value: %s", err) | ||
37 | } | ||
38 | b.Write(json) | ||
39 | return nil | ||
40 | case cty.Number: | ||
41 | if val.RawEquals(cty.PositiveInfinity) || val.RawEquals(cty.NegativeInfinity) { | ||
42 | return path.NewErrorf("cannot serialize infinity as JSON") | ||
43 | } | ||
44 | b.WriteString(val.AsBigFloat().Text('f', -1)) | ||
45 | return nil | ||
46 | case cty.Bool: | ||
47 | if val.True() { | ||
48 | b.WriteString("true") | ||
49 | } else { | ||
50 | b.WriteString("false") | ||
51 | } | ||
52 | return nil | ||
53 | default: | ||
54 | panic("unsupported primitive type") | ||
55 | } | ||
56 | case t.IsListType(), t.IsSetType(): | ||
57 | b.WriteRune('[') | ||
58 | first := true | ||
59 | ety := t.ElementType() | ||
60 | it := val.ElementIterator() | ||
61 | path := append(path, nil) // local override of 'path' with extra element | ||
62 | for it.Next() { | ||
63 | if !first { | ||
64 | b.WriteRune(',') | ||
65 | } | ||
66 | ek, ev := it.Element() | ||
67 | path[len(path)-1] = cty.IndexStep{ | ||
68 | Key: ek, | ||
69 | } | ||
70 | err := marshal(ev, ety, path, b) | ||
71 | if err != nil { | ||
72 | return err | ||
73 | } | ||
74 | first = false | ||
75 | } | ||
76 | b.WriteRune(']') | ||
77 | return nil | ||
78 | case t.IsMapType(): | ||
79 | b.WriteRune('{') | ||
80 | first := true | ||
81 | ety := t.ElementType() | ||
82 | it := val.ElementIterator() | ||
83 | path := append(path, nil) // local override of 'path' with extra element | ||
84 | for it.Next() { | ||
85 | if !first { | ||
86 | b.WriteRune(',') | ||
87 | } | ||
88 | ek, ev := it.Element() | ||
89 | path[len(path)-1] = cty.IndexStep{ | ||
90 | Key: ek, | ||
91 | } | ||
92 | var err error | ||
93 | err = marshal(ek, ek.Type(), path, b) | ||
94 | if err != nil { | ||
95 | return err | ||
96 | } | ||
97 | b.WriteRune(':') | ||
98 | err = marshal(ev, ety, path, b) | ||
99 | if err != nil { | ||
100 | return err | ||
101 | } | ||
102 | first = false | ||
103 | } | ||
104 | b.WriteRune('}') | ||
105 | return nil | ||
106 | case t.IsTupleType(): | ||
107 | b.WriteRune('[') | ||
108 | etys := t.TupleElementTypes() | ||
109 | it := val.ElementIterator() | ||
110 | path := append(path, nil) // local override of 'path' with extra element | ||
111 | i := 0 | ||
112 | for it.Next() { | ||
113 | if i > 0 { | ||
114 | b.WriteRune(',') | ||
115 | } | ||
116 | ety := etys[i] | ||
117 | ek, ev := it.Element() | ||
118 | path[len(path)-1] = cty.IndexStep{ | ||
119 | Key: ek, | ||
120 | } | ||
121 | err := marshal(ev, ety, path, b) | ||
122 | if err != nil { | ||
123 | return err | ||
124 | } | ||
125 | i++ | ||
126 | } | ||
127 | b.WriteRune(']') | ||
128 | return nil | ||
129 | case t.IsObjectType(): | ||
130 | b.WriteRune('{') | ||
131 | atys := t.AttributeTypes() | ||
132 | path := append(path, nil) // local override of 'path' with extra element | ||
133 | |||
134 | names := make([]string, 0, len(atys)) | ||
135 | for k := range atys { | ||
136 | names = append(names, k) | ||
137 | } | ||
138 | sort.Strings(names) | ||
139 | |||
140 | for i, k := range names { | ||
141 | aty := atys[k] | ||
142 | if i > 0 { | ||
143 | b.WriteRune(',') | ||
144 | } | ||
145 | av := val.GetAttr(k) | ||
146 | path[len(path)-1] = cty.GetAttrStep{ | ||
147 | Name: k, | ||
148 | } | ||
149 | var err error | ||
150 | err = marshal(cty.StringVal(k), cty.String, path, b) | ||
151 | if err != nil { | ||
152 | return err | ||
153 | } | ||
154 | b.WriteRune(':') | ||
155 | err = marshal(av, aty, path, b) | ||
156 | if err != nil { | ||
157 | return err | ||
158 | } | ||
159 | } | ||
160 | b.WriteRune('}') | ||
161 | return nil | ||
162 | case t.IsCapsuleType(): | ||
163 | rawVal := val.EncapsulatedValue() | ||
164 | jsonVal, err := json.Marshal(rawVal) | ||
165 | if err != nil { | ||
166 | return path.NewError(err) | ||
167 | } | ||
168 | b.Write(jsonVal) | ||
169 | return nil | ||
170 | default: | ||
171 | // should never happen | ||
172 | return path.NewErrorf("cannot JSON-serialize %s", t.FriendlyName()) | ||
173 | } | ||
174 | } | ||
175 | |||
176 | // marshalDynamic adds an extra wrapping object containing dynamic type | ||
177 | // information for the given value. | ||
178 | func marshalDynamic(val cty.Value, path cty.Path, b *bytes.Buffer) error { | ||
179 | typeJSON, err := MarshalType(val.Type()) | ||
180 | if err != nil { | ||
181 | return path.NewErrorf("failed to serialize type: %s", err) | ||
182 | } | ||
183 | b.WriteString(`{"value":`) | ||
184 | marshal(val, val.Type(), path, b) | ||
185 | b.WriteString(`,"type":`) | ||
186 | b.Write(typeJSON) | ||
187 | b.WriteRune('}') | ||
188 | return nil | ||
189 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/simple.go b/vendor/github.com/zclconf/go-cty/cty/json/simple.go new file mode 100644 index 0000000..507c9cc --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/simple.go | |||
@@ -0,0 +1,41 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // SimpleJSONValue is a wrapper around cty.Value that adds implementations of | ||
8 | // json.Marshaler and json.Unmarshaler for simple-but-type-lossy automatic | ||
9 | // encoding and decoding of values. | ||
10 | // | ||
11 | // The couplet Marshal and Unmarshal both take extra type information to | ||
12 | // inform the encoding and decoding process so that all of the cty types | ||
13 | // can be represented even though JSON's type system is a subset. | ||
14 | // | ||
15 | // SimpleJSONValue instead takes the approach of discarding the value's type | ||
16 | // information and then deriving a new type from the stored structure when | ||
17 | // decoding. This results in the same data being returned but not necessarily | ||
18 | // with exactly the same type. | ||
19 | // | ||
20 | // For information on how types are inferred when decoding, see the | ||
21 | // documentation of the function ImpliedType. | ||
22 | type SimpleJSONValue struct { | ||
23 | cty.Value | ||
24 | } | ||
25 | |||
26 | // MarshalJSON is an implementation of json.Marshaler. See the documentation | ||
27 | // of SimpleJSONValue for more information. | ||
28 | func (v SimpleJSONValue) MarshalJSON() ([]byte, error) { | ||
29 | return Marshal(v.Value, v.Type()) | ||
30 | } | ||
31 | |||
32 | // UnmarshalJSON is an implementation of json.Unmarshaler. See the | ||
33 | // documentation of SimpleJSONValue for more information. | ||
34 | func (v *SimpleJSONValue) UnmarshalJSON(buf []byte) error { | ||
35 | t, err := ImpliedType(buf) | ||
36 | if err != nil { | ||
37 | return err | ||
38 | } | ||
39 | v.Value, err = Unmarshal(buf, t) | ||
40 | return err | ||
41 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/type.go b/vendor/github.com/zclconf/go-cty/cty/json/type.go new file mode 100644 index 0000000..9131c6c --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/type.go | |||
@@ -0,0 +1,23 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // MarshalType returns a JSON serialization of the given type. | ||
8 | // | ||
9 | // This is just a thin wrapper around t.MarshalJSON, for symmetry with | ||
10 | // UnmarshalType. | ||
11 | func MarshalType(t cty.Type) ([]byte, error) { | ||
12 | return t.MarshalJSON() | ||
13 | } | ||
14 | |||
15 | // UnmarshalType decodes a JSON serialization of the given type as produced | ||
16 | // by either Type.MarshalJSON or MarshalType. | ||
17 | // | ||
18 | // This is a convenience wrapper around Type.UnmarshalJSON. | ||
19 | func UnmarshalType(buf []byte) (cty.Type, error) { | ||
20 | var t cty.Type | ||
21 | err := t.UnmarshalJSON(buf) | ||
22 | return t, err | ||
23 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go b/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go new file mode 100644 index 0000000..1a97306 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go | |||
@@ -0,0 +1,171 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
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. | ||
34 | func 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 | |||
51 | func 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 | |||
60 | func 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 | |||
91 | func 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 | |||
140 | func impliedTupleType(dec *json.Decoder) (cty.Type, error) { | ||
141 | // By the time we get in here, we've already consumed the { delimiter | ||
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 { | ||
153 | if rune(ttok) != ']' { | ||
154 | return cty.NilType, fmt.Errorf("unexpected delimiter %q", ttok) | ||
155 | } | ||
156 | break | ||
157 | } | ||
158 | |||
159 | ety, err := impliedTypeForTok(tok, dec) | ||
160 | if err != nil { | ||
161 | return cty.NilType, err | ||
162 | } | ||
163 | etys = append(etys, ety) | ||
164 | } | ||
165 | |||
166 | if len(etys) == 0 { | ||
167 | return cty.EmptyTuple, nil | ||
168 | } | ||
169 | |||
170 | return cty.Tuple(etys), nil | ||
171 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go b/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go new file mode 100644 index 0000000..155f0b8 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go | |||
@@ -0,0 +1,459 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/json" | ||
6 | "fmt" | ||
7 | "reflect" | ||
8 | |||
9 | "github.com/zclconf/go-cty/cty" | ||
10 | "github.com/zclconf/go-cty/cty/convert" | ||
11 | ) | ||
12 | |||
13 | func unmarshal(buf []byte, t cty.Type, path cty.Path) (cty.Value, error) { | ||
14 | dec := bufDecoder(buf) | ||
15 | |||
16 | tok, err := dec.Token() | ||
17 | if err != nil { | ||
18 | return cty.NilVal, path.NewError(err) | ||
19 | } | ||
20 | |||
21 | if tok == nil { | ||
22 | return cty.NullVal(t), nil | ||
23 | } | ||
24 | |||
25 | if t == cty.DynamicPseudoType { | ||
26 | return unmarshalDynamic(buf, path) | ||
27 | } | ||
28 | |||
29 | switch { | ||
30 | case t.IsPrimitiveType(): | ||
31 | val, err := unmarshalPrimitive(tok, t, path) | ||
32 | if err != nil { | ||
33 | return cty.NilVal, err | ||
34 | } | ||
35 | return val, nil | ||
36 | case t.IsListType(): | ||
37 | return unmarshalList(buf, t.ElementType(), path) | ||
38 | case t.IsSetType(): | ||
39 | return unmarshalSet(buf, t.ElementType(), path) | ||
40 | case t.IsMapType(): | ||
41 | return unmarshalMap(buf, t.ElementType(), path) | ||
42 | case t.IsTupleType(): | ||
43 | return unmarshalTuple(buf, t.TupleElementTypes(), path) | ||
44 | case t.IsObjectType(): | ||
45 | return unmarshalObject(buf, t.AttributeTypes(), path) | ||
46 | case t.IsCapsuleType(): | ||
47 | return unmarshalCapsule(buf, t, path) | ||
48 | default: | ||
49 | return cty.NilVal, path.NewErrorf("unsupported type %s", t.FriendlyName()) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | func unmarshalPrimitive(tok json.Token, t cty.Type, path cty.Path) (cty.Value, error) { | ||
54 | |||
55 | switch t { | ||
56 | case cty.Bool: | ||
57 | switch v := tok.(type) { | ||
58 | case bool: | ||
59 | return cty.BoolVal(v), nil | ||
60 | case string: | ||
61 | val, err := convert.Convert(cty.StringVal(v), t) | ||
62 | if err != nil { | ||
63 | return cty.NilVal, path.NewError(err) | ||
64 | } | ||
65 | return val, nil | ||
66 | default: | ||
67 | return cty.NilVal, path.NewErrorf("bool is required") | ||
68 | } | ||
69 | case cty.Number: | ||
70 | if v, ok := tok.(json.Number); ok { | ||
71 | tok = string(v) | ||
72 | } | ||
73 | switch v := tok.(type) { | ||
74 | case string: | ||
75 | val, err := convert.Convert(cty.StringVal(v), t) | ||
76 | if err != nil { | ||
77 | return cty.NilVal, path.NewError(err) | ||
78 | } | ||
79 | return val, nil | ||
80 | default: | ||
81 | return cty.NilVal, path.NewErrorf("number is required") | ||
82 | } | ||
83 | case cty.String: | ||
84 | switch v := tok.(type) { | ||
85 | case string: | ||
86 | return cty.StringVal(v), nil | ||
87 | case json.Number: | ||
88 | return cty.StringVal(string(v)), nil | ||
89 | case bool: | ||
90 | val, err := convert.Convert(cty.BoolVal(v), t) | ||
91 | if err != nil { | ||
92 | return cty.NilVal, path.NewError(err) | ||
93 | } | ||
94 | return val, nil | ||
95 | default: | ||
96 | return cty.NilVal, path.NewErrorf("string is required") | ||
97 | } | ||
98 | default: | ||
99 | // should never happen | ||
100 | panic("unsupported primitive type") | ||
101 | } | ||
102 | } | ||
103 | |||
104 | func unmarshalList(buf []byte, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
105 | dec := bufDecoder(buf) | ||
106 | if err := requireDelim(dec, '['); err != nil { | ||
107 | return cty.NilVal, path.NewError(err) | ||
108 | } | ||
109 | |||
110 | var vals []cty.Value | ||
111 | |||
112 | { | ||
113 | path := append(path, nil) | ||
114 | var idx int64 | ||
115 | |||
116 | for dec.More() { | ||
117 | path[len(path)-1] = cty.IndexStep{ | ||
118 | Key: cty.NumberIntVal(idx), | ||
119 | } | ||
120 | idx++ | ||
121 | |||
122 | rawVal, err := readRawValue(dec) | ||
123 | if err != nil { | ||
124 | return cty.NilVal, path.NewErrorf("failed to read list value: %s", err) | ||
125 | } | ||
126 | |||
127 | el, err := unmarshal(rawVal, ety, path) | ||
128 | if err != nil { | ||
129 | return cty.NilVal, err | ||
130 | } | ||
131 | |||
132 | vals = append(vals, el) | ||
133 | } | ||
134 | } | ||
135 | |||
136 | if err := requireDelim(dec, ']'); err != nil { | ||
137 | return cty.NilVal, path.NewError(err) | ||
138 | } | ||
139 | |||
140 | if len(vals) == 0 { | ||
141 | return cty.ListValEmpty(ety), nil | ||
142 | } | ||
143 | |||
144 | return cty.ListVal(vals), nil | ||
145 | } | ||
146 | |||
147 | func unmarshalSet(buf []byte, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
148 | dec := bufDecoder(buf) | ||
149 | if err := requireDelim(dec, '['); err != nil { | ||
150 | return cty.NilVal, path.NewError(err) | ||
151 | } | ||
152 | |||
153 | var vals []cty.Value | ||
154 | |||
155 | { | ||
156 | path := append(path, nil) | ||
157 | |||
158 | for dec.More() { | ||
159 | path[len(path)-1] = cty.IndexStep{ | ||
160 | Key: cty.UnknownVal(ety), | ||
161 | } | ||
162 | |||
163 | rawVal, err := readRawValue(dec) | ||
164 | if err != nil { | ||
165 | return cty.NilVal, path.NewErrorf("failed to read set value: %s", err) | ||
166 | } | ||
167 | |||
168 | el, err := unmarshal(rawVal, ety, path) | ||
169 | if err != nil { | ||
170 | return cty.NilVal, err | ||
171 | } | ||
172 | |||
173 | vals = append(vals, el) | ||
174 | } | ||
175 | } | ||
176 | |||
177 | if err := requireDelim(dec, ']'); err != nil { | ||
178 | return cty.NilVal, path.NewError(err) | ||
179 | } | ||
180 | |||
181 | if len(vals) == 0 { | ||
182 | return cty.SetValEmpty(ety), nil | ||
183 | } | ||
184 | |||
185 | return cty.SetVal(vals), nil | ||
186 | } | ||
187 | |||
188 | func unmarshalMap(buf []byte, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
189 | dec := bufDecoder(buf) | ||
190 | if err := requireDelim(dec, '{'); err != nil { | ||
191 | return cty.NilVal, path.NewError(err) | ||
192 | } | ||
193 | |||
194 | vals := make(map[string]cty.Value) | ||
195 | |||
196 | { | ||
197 | path := append(path, nil) | ||
198 | |||
199 | for dec.More() { | ||
200 | path[len(path)-1] = cty.IndexStep{ | ||
201 | Key: cty.UnknownVal(cty.String), | ||
202 | } | ||
203 | |||
204 | var err error | ||
205 | |||
206 | k, err := requireObjectKey(dec) | ||
207 | if err != nil { | ||
208 | return cty.NilVal, path.NewErrorf("failed to read map key: %s", err) | ||
209 | } | ||
210 | |||
211 | path[len(path)-1] = cty.IndexStep{ | ||
212 | Key: cty.StringVal(k), | ||
213 | } | ||
214 | |||
215 | rawVal, err := readRawValue(dec) | ||
216 | if err != nil { | ||
217 | return cty.NilVal, path.NewErrorf("failed to read map value: %s", err) | ||
218 | } | ||
219 | |||
220 | el, err := unmarshal(rawVal, ety, path) | ||
221 | if err != nil { | ||
222 | return cty.NilVal, err | ||
223 | } | ||
224 | |||
225 | vals[k] = el | ||
226 | } | ||
227 | } | ||
228 | |||
229 | if err := requireDelim(dec, '}'); err != nil { | ||
230 | return cty.NilVal, path.NewError(err) | ||
231 | } | ||
232 | |||
233 | if len(vals) == 0 { | ||
234 | return cty.MapValEmpty(ety), nil | ||
235 | } | ||
236 | |||
237 | return cty.MapVal(vals), nil | ||
238 | } | ||
239 | |||
240 | func unmarshalTuple(buf []byte, etys []cty.Type, path cty.Path) (cty.Value, error) { | ||
241 | dec := bufDecoder(buf) | ||
242 | if err := requireDelim(dec, '['); err != nil { | ||
243 | return cty.NilVal, path.NewError(err) | ||
244 | } | ||
245 | |||
246 | var vals []cty.Value | ||
247 | |||
248 | { | ||
249 | path := append(path, nil) | ||
250 | var idx int | ||
251 | |||
252 | for dec.More() { | ||
253 | if idx >= len(etys) { | ||
254 | return cty.NilVal, path[:len(path)-1].NewErrorf("too many tuple elements (need %d)", len(etys)) | ||
255 | } | ||
256 | |||
257 | path[len(path)-1] = cty.IndexStep{ | ||
258 | Key: cty.NumberIntVal(int64(idx)), | ||
259 | } | ||
260 | ety := etys[idx] | ||
261 | idx++ | ||
262 | |||
263 | rawVal, err := readRawValue(dec) | ||
264 | if err != nil { | ||
265 | return cty.NilVal, path.NewErrorf("failed to read tuple value: %s", err) | ||
266 | } | ||
267 | |||
268 | el, err := unmarshal(rawVal, ety, path) | ||
269 | if err != nil { | ||
270 | return cty.NilVal, err | ||
271 | } | ||
272 | |||
273 | vals = append(vals, el) | ||
274 | } | ||
275 | } | ||
276 | |||
277 | if err := requireDelim(dec, ']'); err != nil { | ||
278 | return cty.NilVal, path.NewError(err) | ||
279 | } | ||
280 | |||
281 | if len(vals) != len(etys) { | ||
282 | return cty.NilVal, path[:len(path)-1].NewErrorf("not enough tuple elements (need %d)", len(etys)) | ||
283 | } | ||
284 | |||
285 | if len(vals) == 0 { | ||
286 | return cty.EmptyTupleVal, nil | ||
287 | } | ||
288 | |||
289 | return cty.TupleVal(vals), nil | ||
290 | } | ||
291 | |||
292 | func unmarshalObject(buf []byte, atys map[string]cty.Type, path cty.Path) (cty.Value, error) { | ||
293 | dec := bufDecoder(buf) | ||
294 | if err := requireDelim(dec, '{'); err != nil { | ||
295 | return cty.NilVal, path.NewError(err) | ||
296 | } | ||
297 | |||
298 | vals := make(map[string]cty.Value) | ||
299 | |||
300 | { | ||
301 | objPath := path // some errors report from the object's perspective | ||
302 | path := append(path, nil) // path to a specific attribute | ||
303 | |||
304 | for dec.More() { | ||
305 | |||
306 | var err error | ||
307 | |||
308 | k, err := requireObjectKey(dec) | ||
309 | if err != nil { | ||
310 | return cty.NilVal, path.NewErrorf("failed to read object key: %s", err) | ||
311 | } | ||
312 | |||
313 | aty, ok := atys[k] | ||
314 | if !ok { | ||
315 | return cty.NilVal, objPath.NewErrorf("unsupported attribute %q", k) | ||
316 | } | ||
317 | |||
318 | path[len(path)-1] = cty.GetAttrStep{ | ||
319 | Name: k, | ||
320 | } | ||
321 | |||
322 | rawVal, err := readRawValue(dec) | ||
323 | if err != nil { | ||
324 | return cty.NilVal, path.NewErrorf("failed to read object value: %s", err) | ||
325 | } | ||
326 | |||
327 | el, err := unmarshal(rawVal, aty, path) | ||
328 | if err != nil { | ||
329 | return cty.NilVal, err | ||
330 | } | ||
331 | |||
332 | vals[k] = el | ||
333 | } | ||
334 | } | ||
335 | |||
336 | if err := requireDelim(dec, '}'); err != nil { | ||
337 | return cty.NilVal, path.NewError(err) | ||
338 | } | ||
339 | |||
340 | // Make sure we have a value for every attribute | ||
341 | for k, aty := range atys { | ||
342 | if _, exists := vals[k]; !exists { | ||
343 | vals[k] = cty.NullVal(aty) | ||
344 | } | ||
345 | } | ||
346 | |||
347 | if len(vals) == 0 { | ||
348 | return cty.EmptyObjectVal, nil | ||
349 | } | ||
350 | |||
351 | return cty.ObjectVal(vals), nil | ||
352 | } | ||
353 | |||
354 | func unmarshalCapsule(buf []byte, t cty.Type, path cty.Path) (cty.Value, error) { | ||
355 | rawType := t.EncapsulatedType() | ||
356 | ptrPtr := reflect.New(reflect.PtrTo(rawType)) | ||
357 | ptrPtr.Elem().Set(reflect.New(rawType)) | ||
358 | ptr := ptrPtr.Elem().Interface() | ||
359 | err := json.Unmarshal(buf, ptr) | ||
360 | if err != nil { | ||
361 | return cty.NilVal, path.NewError(err) | ||
362 | } | ||
363 | |||
364 | return cty.CapsuleVal(t, ptr), nil | ||
365 | } | ||
366 | |||
367 | func unmarshalDynamic(buf []byte, path cty.Path) (cty.Value, error) { | ||
368 | dec := bufDecoder(buf) | ||
369 | if err := requireDelim(dec, '{'); err != nil { | ||
370 | return cty.NilVal, path.NewError(err) | ||
371 | } | ||
372 | |||
373 | var t cty.Type | ||
374 | var valBody []byte // defer actual decoding until we know the type | ||
375 | |||
376 | for dec.More() { | ||
377 | var err error | ||
378 | |||
379 | key, err := requireObjectKey(dec) | ||
380 | if err != nil { | ||
381 | return cty.NilVal, path.NewErrorf("failed to read dynamic type descriptor key: %s", err) | ||
382 | } | ||
383 | |||
384 | rawVal, err := readRawValue(dec) | ||
385 | if err != nil { | ||
386 | return cty.NilVal, path.NewErrorf("failed to read dynamic type descriptor value: %s", err) | ||
387 | } | ||
388 | |||
389 | switch key { | ||
390 | case "type": | ||
391 | err := json.Unmarshal(rawVal, &t) | ||
392 | if err != nil { | ||
393 | return cty.NilVal, path.NewErrorf("failed to decode type for dynamic value: %s", err) | ||
394 | } | ||
395 | case "value": | ||
396 | valBody = rawVal | ||
397 | default: | ||
398 | return cty.NilVal, path.NewErrorf("invalid key %q in dynamically-typed value", key) | ||
399 | } | ||
400 | |||
401 | } | ||
402 | |||
403 | if err := requireDelim(dec, '}'); err != nil { | ||
404 | return cty.NilVal, path.NewError(err) | ||
405 | } | ||
406 | |||
407 | if t == cty.NilType { | ||
408 | return cty.NilVal, path.NewErrorf("missing type in dynamically-typed value") | ||
409 | } | ||
410 | if valBody == nil { | ||
411 | return cty.NilVal, path.NewErrorf("missing value in dynamically-typed value") | ||
412 | } | ||
413 | |||
414 | val, err := Unmarshal([]byte(valBody), t) | ||
415 | if err != nil { | ||
416 | return cty.NilVal, path.NewError(err) | ||
417 | } | ||
418 | return val, nil | ||
419 | } | ||
420 | |||
421 | func requireDelim(dec *json.Decoder, d rune) error { | ||
422 | tok, err := dec.Token() | ||
423 | if err != nil { | ||
424 | return err | ||
425 | } | ||
426 | |||
427 | if tok != json.Delim(d) { | ||
428 | return fmt.Errorf("missing expected %c", d) | ||
429 | } | ||
430 | |||
431 | return nil | ||
432 | } | ||
433 | |||
434 | func requireObjectKey(dec *json.Decoder) (string, error) { | ||
435 | tok, err := dec.Token() | ||
436 | if err != nil { | ||
437 | return "", err | ||
438 | } | ||
439 | if s, ok := tok.(string); ok { | ||
440 | return s, nil | ||
441 | } | ||
442 | return "", fmt.Errorf("missing expected object key") | ||
443 | } | ||
444 | |||
445 | func readRawValue(dec *json.Decoder) ([]byte, error) { | ||
446 | var rawVal json.RawMessage | ||
447 | err := dec.Decode(&rawVal) | ||
448 | if err != nil { | ||
449 | return nil, err | ||
450 | } | ||
451 | return []byte(rawVal), nil | ||
452 | } | ||
453 | |||
454 | func bufDecoder(buf []byte) *json.Decoder { | ||
455 | r := bytes.NewReader(buf) | ||
456 | dec := json.NewDecoder(r) | ||
457 | dec.UseNumber() | ||
458 | return dec | ||
459 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/value.go b/vendor/github.com/zclconf/go-cty/cty/json/value.go new file mode 100644 index 0000000..f2f7dd5 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/value.go | |||
@@ -0,0 +1,65 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | "github.com/zclconf/go-cty/cty/convert" | ||
8 | ) | ||
9 | |||
10 | // Marshal produces a JSON representation of the given value that can later | ||
11 | // be decoded into a value of the given type. | ||
12 | // | ||
13 | // A type is specified separately to allow for the given type to include | ||
14 | // cty.DynamicPseudoType to represent situations where any type is permitted | ||
15 | // and so type information must be included to allow recovery of the stored | ||
16 | // structure when decoding. | ||
17 | // | ||
18 | // The given type will also be used to attempt automatic conversions of any | ||
19 | // non-conformant types in the given value, although this will not always | ||
20 | // be possible. If the value cannot be made to be conformant then an error is | ||
21 | // returned, which may be a cty.PathError. | ||
22 | // | ||
23 | // Capsule-typed values can be marshalled, but with some caveats. Since | ||
24 | // capsule values are compared by pointer equality, it is impossible to recover | ||
25 | // a value that will compare equal to the original value. Additionally, | ||
26 | // it's not possible to JSON-serialize the capsule type itself, so it's not | ||
27 | // valid to use capsule types within parts of the value that are conformed to | ||
28 | // cty.DynamicPseudoType. Otherwise, a capsule value can be used as long as | ||
29 | // the encapsulated type itself is serializable with the Marshal function | ||
30 | // in encoding/json. | ||
31 | func Marshal(val cty.Value, t cty.Type) ([]byte, error) { | ||
32 | errs := val.Type().TestConformance(t) | ||
33 | if errs != nil { | ||
34 | // Attempt a conversion | ||
35 | var err error | ||
36 | val, err = convert.Convert(val, t) | ||
37 | if err != nil { | ||
38 | return nil, err | ||
39 | } | ||
40 | } | ||
41 | |||
42 | // From this point onward, val can be assumed to be conforming to t. | ||
43 | |||
44 | buf := &bytes.Buffer{} | ||
45 | var path cty.Path | ||
46 | err := marshal(val, t, path, buf) | ||
47 | |||
48 | if err != nil { | ||
49 | return nil, err | ||
50 | } | ||
51 | |||
52 | return buf.Bytes(), nil | ||
53 | } | ||
54 | |||
55 | // Unmarshal decodes a JSON representation of the given value into a cty Value | ||
56 | // conforming to the given type. | ||
57 | // | ||
58 | // While decoding, type conversions will be done where possible to make | ||
59 | // the result conformant even if the types given in JSON are not exactly | ||
60 | // correct. If conversion isn't possible then an error is returned, which | ||
61 | // may be a cty.PathError. | ||
62 | func Unmarshal(buf []byte, t cty.Type) (cty.Value, error) { | ||
63 | var path cty.Path | ||
64 | return unmarshal(buf, t, path) | ||
65 | } | ||