mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-16 19:52:49 -06:00
034e944070
This is part of a general effort to move all of Terraform's non-library package surface under internal in order to reinforce that these are for internal use within Terraform only. If you were previously importing packages under this prefix into an external codebase, you could pin to an earlier release tag as an interim solution until you've make a plan to achieve the same functionality some other way.
97 lines
3.7 KiB
Go
97 lines
3.7 KiB
Go
package plans
|
|
|
|
import (
|
|
"github.com/zclconf/go-cty/cty"
|
|
ctymsgpack "github.com/zclconf/go-cty/cty/msgpack"
|
|
)
|
|
|
|
// DynamicValue is the representation in the plan of a value whose type cannot
|
|
// be determined at compile time, such as because it comes from a schema
|
|
// defined in a plugin.
|
|
//
|
|
// This type is used as an indirection so that the overall plan structure can
|
|
// be decoded without schema available, and then the dynamic values accessed
|
|
// at a later time once the appropriate schema has been determined.
|
|
//
|
|
// Internally, DynamicValue is a serialized version of a cty.Value created
|
|
// against a particular type constraint. Callers should not access directly
|
|
// the serialized form, whose format may change in future. Values of this
|
|
// type must always be created by calling NewDynamicValue.
|
|
//
|
|
// The zero value of DynamicValue is nil, and represents the absense of a
|
|
// value within the Go type system. This is distinct from a cty.NullVal
|
|
// result, which represents the absense of a value within the cty type system.
|
|
type DynamicValue []byte
|
|
|
|
// NewDynamicValue creates a DynamicValue by serializing the given value
|
|
// against the given type constraint. The value must conform to the type
|
|
// constraint, or the result is undefined.
|
|
//
|
|
// If the value to be encoded has no predefined schema (for example, for
|
|
// module output values and input variables), set the type constraint to
|
|
// cty.DynamicPseudoType in order to save type information as part of the
|
|
// value, and then also pass cty.DynamicPseudoType to method Decode to recover
|
|
// the original value.
|
|
//
|
|
// cty.NilVal can be used to represent the absense of a value, but callers
|
|
// must be careful to distinguish values that are absent at the Go layer
|
|
// (cty.NilVal) vs. values that are absent at the cty layer (cty.NullVal
|
|
// results).
|
|
func NewDynamicValue(val cty.Value, ty cty.Type) (DynamicValue, error) {
|
|
// If we're given cty.NilVal (the zero value of cty.Value, which is
|
|
// distinct from a typed null value created by cty.NullVal) then we'll
|
|
// assume the caller is trying to represent the _absense_ of a value,
|
|
// and so we'll return a nil DynamicValue.
|
|
if val == cty.NilVal {
|
|
return DynamicValue(nil), nil
|
|
}
|
|
|
|
// Currently our internal encoding is msgpack, via ctymsgpack.
|
|
buf, err := ctymsgpack.Marshal(val, ty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return DynamicValue(buf), nil
|
|
}
|
|
|
|
// Decode retrieves the effective value from the receiever by interpreting the
|
|
// serialized form against the given type constraint. For correct results,
|
|
// the type constraint must match (or be consistent with) the one that was
|
|
// used to create the receiver.
|
|
//
|
|
// A nil DynamicValue decodes to cty.NilVal, which is not a valid value and
|
|
// instead represents the absense of a value.
|
|
func (v DynamicValue) Decode(ty cty.Type) (cty.Value, error) {
|
|
if v == nil {
|
|
return cty.NilVal, nil
|
|
}
|
|
|
|
return ctymsgpack.Unmarshal([]byte(v), ty)
|
|
}
|
|
|
|
// ImpliedType returns the type implied by the serialized structure of the
|
|
// receiving value.
|
|
//
|
|
// This will not necessarily be exactly the type that was given when the
|
|
// value was encoded, and in particular must not be used for values that
|
|
// were encoded with their static type given as cty.DynamicPseudoType.
|
|
// It is however safe to use this method for values that were encoded using
|
|
// their runtime type as the conforming type, with the result being
|
|
// semantically equivalent but with all lists and sets represented as tuples,
|
|
// and maps as objects, due to ambiguities of the serialization.
|
|
func (v DynamicValue) ImpliedType() (cty.Type, error) {
|
|
return ctymsgpack.ImpliedType([]byte(v))
|
|
}
|
|
|
|
// Copy produces a copy of the receiver with a distinct backing array.
|
|
func (v DynamicValue) Copy() DynamicValue {
|
|
if v == nil {
|
|
return nil
|
|
}
|
|
|
|
ret := make(DynamicValue, len(v))
|
|
copy(ret, v)
|
|
return ret
|
|
}
|