aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/zclconf/go-cty/cty/json/marshal.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/zclconf/go-cty/cty/json/marshal.go')
-rw-r--r--vendor/github.com/zclconf/go-cty/cty/json/marshal.go189
1 files changed, 189 insertions, 0 deletions
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 @@
1package json
2
3import (
4 "bytes"
5 "encoding/json"
6 "sort"
7
8 "github.com/zclconf/go-cty/cty"
9)
10
11func 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.
178func 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}