9 "github.com/zclconf/go-cty/cty"
10 "github.com/zclconf/go-cty/cty/convert"
13 func unmarshal(buf []byte, t cty.Type, path cty.Path) (cty.Value, error) {
14 dec := bufDecoder(buf)
16 tok, err := dec.Token()
18 return cty.NilVal, path.NewError(err)
22 return cty.NullVal(t), nil
25 if t == cty.DynamicPseudoType {
26 return unmarshalDynamic(buf, path)
30 case t.IsPrimitiveType():
31 val, err := unmarshalPrimitive(tok, t, path)
33 return cty.NilVal, err
37 return unmarshalList(buf, t.ElementType(), path)
39 return unmarshalSet(buf, t.ElementType(), path)
41 return unmarshalMap(buf, t.ElementType(), path)
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)
49 return cty.NilVal, path.NewErrorf("unsupported type %s", t.FriendlyName())
53 func unmarshalPrimitive(tok json.Token, t cty.Type, path cty.Path) (cty.Value, error) {
57 switch v := tok.(type) {
59 return cty.BoolVal(v), nil
61 val, err := convert.Convert(cty.StringVal(v), t)
63 return cty.NilVal, path.NewError(err)
67 return cty.NilVal, path.NewErrorf("bool is required")
70 if v, ok := tok.(json.Number); ok {
73 switch v := tok.(type) {
75 val, err := cty.ParseNumberVal(v)
77 return cty.NilVal, path.NewError(err)
81 return cty.NilVal, path.NewErrorf("number is required")
84 switch v := tok.(type) {
86 return cty.StringVal(v), nil
88 return cty.StringVal(string(v)), nil
90 val, err := convert.Convert(cty.BoolVal(v), t)
92 return cty.NilVal, path.NewError(err)
96 return cty.NilVal, path.NewErrorf("string is required")
99 // should never happen
100 panic("unsupported primitive type")
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)
113 path := append(path, nil)
117 path[len(path)-1] = cty.IndexStep{
118 Key: cty.NumberIntVal(idx),
122 rawVal, err := readRawValue(dec)
124 return cty.NilVal, path.NewErrorf("failed to read list value: %s", err)
127 el, err := unmarshal(rawVal, ety, path)
129 return cty.NilVal, err
132 vals = append(vals, el)
136 if err := requireDelim(dec, ']'); err != nil {
137 return cty.NilVal, path.NewError(err)
141 return cty.ListValEmpty(ety), nil
144 return cty.ListVal(vals), nil
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)
156 path := append(path, nil)
159 path[len(path)-1] = cty.IndexStep{
160 Key: cty.UnknownVal(ety),
163 rawVal, err := readRawValue(dec)
165 return cty.NilVal, path.NewErrorf("failed to read set value: %s", err)
168 el, err := unmarshal(rawVal, ety, path)
170 return cty.NilVal, err
173 vals = append(vals, el)
177 if err := requireDelim(dec, ']'); err != nil {
178 return cty.NilVal, path.NewError(err)
182 return cty.SetValEmpty(ety), nil
185 return cty.SetVal(vals), nil
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)
194 vals := make(map[string]cty.Value)
197 path := append(path, nil)
200 path[len(path)-1] = cty.IndexStep{
201 Key: cty.UnknownVal(cty.String),
206 k, err := requireObjectKey(dec)
208 return cty.NilVal, path.NewErrorf("failed to read map key: %s", err)
211 path[len(path)-1] = cty.IndexStep{
212 Key: cty.StringVal(k),
215 rawVal, err := readRawValue(dec)
217 return cty.NilVal, path.NewErrorf("failed to read map value: %s", err)
220 el, err := unmarshal(rawVal, ety, path)
222 return cty.NilVal, err
229 if err := requireDelim(dec, '}'); err != nil {
230 return cty.NilVal, path.NewError(err)
234 return cty.MapValEmpty(ety), nil
237 return cty.MapVal(vals), nil
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)
249 path := append(path, nil)
253 if idx >= len(etys) {
254 return cty.NilVal, path[:len(path)-1].NewErrorf("too many tuple elements (need %d)", len(etys))
257 path[len(path)-1] = cty.IndexStep{
258 Key: cty.NumberIntVal(int64(idx)),
263 rawVal, err := readRawValue(dec)
265 return cty.NilVal, path.NewErrorf("failed to read tuple value: %s", err)
268 el, err := unmarshal(rawVal, ety, path)
270 return cty.NilVal, err
273 vals = append(vals, el)
277 if err := requireDelim(dec, ']'); err != nil {
278 return cty.NilVal, path.NewError(err)
281 if len(vals) != len(etys) {
282 return cty.NilVal, path[:len(path)-1].NewErrorf("not enough tuple elements (need %d)", len(etys))
286 return cty.EmptyTupleVal, nil
289 return cty.TupleVal(vals), nil
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)
298 vals := make(map[string]cty.Value)
301 objPath := path // some errors report from the object's perspective
302 path := append(path, nil) // path to a specific attribute
308 k, err := requireObjectKey(dec)
310 return cty.NilVal, path.NewErrorf("failed to read object key: %s", err)
315 return cty.NilVal, objPath.NewErrorf("unsupported attribute %q", k)
318 path[len(path)-1] = cty.GetAttrStep{
322 rawVal, err := readRawValue(dec)
324 return cty.NilVal, path.NewErrorf("failed to read object value: %s", err)
327 el, err := unmarshal(rawVal, aty, path)
329 return cty.NilVal, err
336 if err := requireDelim(dec, '}'); err != nil {
337 return cty.NilVal, path.NewError(err)
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)
348 return cty.EmptyObjectVal, nil
351 return cty.ObjectVal(vals), nil
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)
361 return cty.NilVal, path.NewError(err)
364 return cty.CapsuleVal(t, ptr), nil
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)
374 var valBody []byte // defer actual decoding until we know the type
379 key, err := requireObjectKey(dec)
381 return cty.NilVal, path.NewErrorf("failed to read dynamic type descriptor key: %s", err)
384 rawVal, err := readRawValue(dec)
386 return cty.NilVal, path.NewErrorf("failed to read dynamic type descriptor value: %s", err)
391 err := json.Unmarshal(rawVal, &t)
393 return cty.NilVal, path.NewErrorf("failed to decode type for dynamic value: %s", err)
398 return cty.NilVal, path.NewErrorf("invalid key %q in dynamically-typed value", key)
403 if err := requireDelim(dec, '}'); err != nil {
404 return cty.NilVal, path.NewError(err)
407 if t == cty.NilType {
408 return cty.NilVal, path.NewErrorf("missing type in dynamically-typed value")
411 return cty.NilVal, path.NewErrorf("missing value in dynamically-typed value")
414 val, err := Unmarshal([]byte(valBody), t)
416 return cty.NilVal, path.NewError(err)
421 func requireDelim(dec *json.Decoder, d rune) error {
422 tok, err := dec.Token()
427 if tok != json.Delim(d) {
428 return fmt.Errorf("missing expected %c", d)
434 func requireObjectKey(dec *json.Decoder) (string, error) {
435 tok, err := dec.Token()
439 if s, ok := tok.(string); ok {
442 return "", fmt.Errorf("missing expected object key")
445 func readRawValue(dec *json.Decoder) ([]byte, error) {
446 var rawVal json.RawMessage
447 err := dec.Decode(&rawVal)
451 return []byte(rawVal), nil
454 func bufDecoder(buf []byte) *json.Decoder {
455 r := bytes.NewReader(buf)
456 dec := json.NewDecoder(r)