66 lines
2.2 KiB
Go
66 lines
2.2 KiB
Go
|
package json
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
|
||
|
"github.com/zclconf/go-cty/cty"
|
||
|
"github.com/zclconf/go-cty/cty/convert"
|
||
|
)
|
||
|
|
||
|
// Marshal produces a JSON representation of the given value that can later
|
||
|
// be decoded into a value of the given type.
|
||
|
//
|
||
|
// A type is specified separately to allow for the given type to include
|
||
|
// cty.DynamicPseudoType to represent situations where any type is permitted
|
||
|
// and so type information must be included to allow recovery of the stored
|
||
|
// structure when decoding.
|
||
|
//
|
||
|
// The given type will also be used to attempt automatic conversions of any
|
||
|
// non-conformant types in the given value, although this will not always
|
||
|
// be possible. If the value cannot be made to be conformant then an error is
|
||
|
// returned, which may be a cty.PathError.
|
||
|
//
|
||
|
// Capsule-typed values can be marshalled, but with some caveats. Since
|
||
|
// capsule values are compared by pointer equality, it is impossible to recover
|
||
|
// a value that will compare equal to the original value. Additionally,
|
||
|
// it's not possible to JSON-serialize the capsule type itself, so it's not
|
||
|
// valid to use capsule types within parts of the value that are conformed to
|
||
|
// cty.DynamicPseudoType. Otherwise, a capsule value can be used as long as
|
||
|
// the encapsulated type itself is serializable with the Marshal function
|
||
|
// in encoding/json.
|
||
|
func Marshal(val cty.Value, t cty.Type) ([]byte, error) {
|
||
|
errs := val.Type().TestConformance(t)
|
||
|
if errs != nil {
|
||
|
// Attempt a conversion
|
||
|
var err error
|
||
|
val, err = convert.Convert(val, t)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// From this point onward, val can be assumed to be conforming to t.
|
||
|
|
||
|
buf := &bytes.Buffer{}
|
||
|
var path cty.Path
|
||
|
err := marshal(val, t, path, buf)
|
||
|
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return buf.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
// Unmarshal decodes a JSON representation of the given value into a cty Value
|
||
|
// conforming to the given type.
|
||
|
//
|
||
|
// While decoding, type conversions will be done where possible to make
|
||
|
// the result conformant even if the types given in JSON are not exactly
|
||
|
// correct. If conversion isn't possible then an error is returned, which
|
||
|
// may be a cty.PathError.
|
||
|
func Unmarshal(buf []byte, t cty.Type) (cty.Value, error) {
|
||
|
var path cty.Path
|
||
|
return unmarshal(buf, t, path)
|
||
|
}
|