mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-09 21:17:09 +08:00
21
vendor/github.com/zclconf/go-cty/LICENSE
generated
vendored
Normal file
21
vendor/github.com/zclconf/go-cty/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018 Martin Atkins
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
128
vendor/github.com/zclconf/go-cty/cty/capsule.go
generated
vendored
Normal file
128
vendor/github.com/zclconf/go-cty/cty/capsule.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type capsuleType struct {
|
||||
typeImplSigil
|
||||
Name string
|
||||
GoType reflect.Type
|
||||
Ops *CapsuleOps
|
||||
}
|
||||
|
||||
func (t *capsuleType) Equals(other Type) bool {
|
||||
if otherP, ok := other.typeImpl.(*capsuleType); ok {
|
||||
// capsule types compare by pointer identity
|
||||
return otherP == t
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *capsuleType) FriendlyName(mode friendlyTypeNameMode) string {
|
||||
return t.Name
|
||||
}
|
||||
|
||||
func (t *capsuleType) GoString() string {
|
||||
impl := t.Ops.TypeGoString
|
||||
if impl == nil {
|
||||
// To get a useful representation of our native type requires some
|
||||
// shenanigans.
|
||||
victimVal := reflect.Zero(t.GoType)
|
||||
if t.Ops == noCapsuleOps {
|
||||
return fmt.Sprintf("cty.Capsule(%q, reflect.TypeOf(%#v))", t.Name, victimVal.Interface())
|
||||
} else {
|
||||
// Including the operations in the output will make this _very_ long,
|
||||
// so in practice any capsule type with ops ought to provide a
|
||||
// TypeGoString function to override this with something more
|
||||
// reasonable.
|
||||
return fmt.Sprintf("cty.CapsuleWithOps(%q, reflect.TypeOf(%#v), %#v)", t.Name, victimVal.Interface(), t.Ops)
|
||||
}
|
||||
}
|
||||
return impl(t.GoType)
|
||||
}
|
||||
|
||||
// Capsule creates a new Capsule type.
|
||||
//
|
||||
// A Capsule type is a special type that can be used to transport arbitrary
|
||||
// Go native values of a given type through the cty type system. A language
|
||||
// that uses cty as its type system might, for example, provide functions
|
||||
// that return capsule-typed values and then other functions that operate
|
||||
// on those values.
|
||||
//
|
||||
// From cty's perspective, Capsule types have a few interesting characteristics,
|
||||
// described in the following paragraphs.
|
||||
//
|
||||
// Each capsule type has an associated Go native type that it is able to
|
||||
// transport. Capsule types compare by identity, so each call to the
|
||||
// Capsule function creates an entirely-distinct cty Type, even if two calls
|
||||
// use the same native type.
|
||||
//
|
||||
// Each capsule-typed value contains a pointer to a value of the given native
|
||||
// type. A capsule-typed value by default supports no operations except
|
||||
// equality, and equality is implemented by pointer identity of the
|
||||
// encapsulated pointer. A capsule type can optionally have its own
|
||||
// implementations of certain operations if it is created with CapsuleWithOps
|
||||
// instead of Capsule.
|
||||
//
|
||||
// The given name is used as the new type's "friendly name". This can be any
|
||||
// string in principle, but will usually be a short, all-lowercase name aimed
|
||||
// at users of the embedding language (i.e. not mention Go-specific details)
|
||||
// and will ideally not create ambiguity with any predefined cty type.
|
||||
//
|
||||
// Capsule types are never introduced by any standard cty operation, so a
|
||||
// calling application opts in to including them within its own type system
|
||||
// by creating them and introducing them via its own functions. At that point,
|
||||
// the application is responsible for dealing with any capsule-typed values
|
||||
// that might be returned.
|
||||
func Capsule(name string, nativeType reflect.Type) Type {
|
||||
return Type{
|
||||
&capsuleType{
|
||||
Name: name,
|
||||
GoType: nativeType,
|
||||
Ops: noCapsuleOps,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CapsuleWithOps is like Capsule except the caller may provide an object
|
||||
// representing some overloaded operation implementations to associate with
|
||||
// the given capsule type.
|
||||
//
|
||||
// All of the other caveats and restrictions for capsule types still apply, but
|
||||
// overloaded operations can potentially help a capsule type participate better
|
||||
// in cty operations.
|
||||
func CapsuleWithOps(name string, nativeType reflect.Type, ops *CapsuleOps) Type {
|
||||
// Copy the operations to make sure the caller can't modify them after
|
||||
// we're constructed.
|
||||
ourOps := *ops
|
||||
ourOps.assertValid()
|
||||
|
||||
return Type{
|
||||
&capsuleType{
|
||||
Name: name,
|
||||
GoType: nativeType,
|
||||
Ops: &ourOps,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// IsCapsuleType returns true if this type is a capsule type, as created
|
||||
// by cty.Capsule .
|
||||
func (t Type) IsCapsuleType() bool {
|
||||
_, ok := t.typeImpl.(*capsuleType)
|
||||
return ok
|
||||
}
|
||||
|
||||
// EncapsulatedType returns the encapsulated native type of a capsule type,
|
||||
// or panics if the receiver is not a Capsule type.
|
||||
//
|
||||
// Is IsCapsuleType to determine if this method is safe to call.
|
||||
func (t Type) EncapsulatedType() reflect.Type {
|
||||
impl, ok := t.typeImpl.(*capsuleType)
|
||||
if !ok {
|
||||
panic("not a capsule type")
|
||||
}
|
||||
return impl.GoType
|
||||
}
|
132
vendor/github.com/zclconf/go-cty/cty/capsule_ops.go
generated
vendored
Normal file
132
vendor/github.com/zclconf/go-cty/cty/capsule_ops.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// CapsuleOps represents a set of overloaded operations for a capsule type.
|
||||
//
|
||||
// Each field is a reference to a function that can either be nil or can be
|
||||
// set to an implementation of the corresponding operation. If an operation
|
||||
// function is nil then it isn't supported for the given capsule type.
|
||||
type CapsuleOps struct {
|
||||
// GoString provides the GoString implementation for values of the
|
||||
// corresponding type. Conventionally this should return a string
|
||||
// representation of an expression that would produce an equivalent
|
||||
// value.
|
||||
GoString func(val interface{}) string
|
||||
|
||||
// TypeGoString provides the GoString implementation for the corresponding
|
||||
// capsule type itself.
|
||||
TypeGoString func(goTy reflect.Type) string
|
||||
|
||||
// Equals provides the implementation of the Equals operation. This is
|
||||
// called only with known, non-null values of the corresponding type,
|
||||
// but if the corresponding type is a compound type then it must be
|
||||
// ready to detect and handle nested unknown or null values, usually
|
||||
// by recursively calling Value.Equals on those nested values.
|
||||
//
|
||||
// The result value must always be of type cty.Bool, or the Equals
|
||||
// operation will panic.
|
||||
//
|
||||
// If RawEquals is set without also setting Equals, the RawEquals
|
||||
// implementation will be used as a fallback implementation. That fallback
|
||||
// is appropriate only for leaf types that do not contain any nested
|
||||
// cty.Value that would need to distinguish Equals vs. RawEquals for their
|
||||
// own equality.
|
||||
//
|
||||
// If RawEquals is nil then Equals must also be nil, selecting the default
|
||||
// pointer-identity comparison instead.
|
||||
Equals func(a, b interface{}) Value
|
||||
|
||||
// RawEquals provides the implementation of the RawEquals operation.
|
||||
// This is called only with known, non-null values of the corresponding
|
||||
// type, but if the corresponding type is a compound type then it must be
|
||||
// ready to detect and handle nested unknown or null values, usually
|
||||
// by recursively calling Value.RawEquals on those nested values.
|
||||
//
|
||||
// If RawEquals is nil, values of the corresponding type are compared by
|
||||
// pointer identity of the encapsulated value.
|
||||
RawEquals func(a, b interface{}) bool
|
||||
|
||||
// ConversionFrom can provide conversions from the corresponding type to
|
||||
// some other type when values of the corresponding type are used with
|
||||
// the "convert" package. (The main cty package does not use this operation.)
|
||||
//
|
||||
// This function itself returns a function, allowing it to switch its
|
||||
// behavior depending on the given source type. Return nil to indicate
|
||||
// that no such conversion is available.
|
||||
ConversionFrom func(src Type) func(interface{}, Path) (Value, error)
|
||||
|
||||
// ConversionTo can provide conversions to the corresponding type from
|
||||
// some other type when values of the corresponding type are used with
|
||||
// the "convert" package. (The main cty package does not use this operation.)
|
||||
//
|
||||
// This function itself returns a function, allowing it to switch its
|
||||
// behavior depending on the given destination type. Return nil to indicate
|
||||
// that no such conversion is available.
|
||||
ConversionTo func(dst Type) func(Value, Path) (interface{}, error)
|
||||
|
||||
// ExtensionData is an extension point for applications that wish to
|
||||
// create their own extension features using capsule types.
|
||||
//
|
||||
// The key argument is any value that can be compared with Go's ==
|
||||
// operator, but should be of a named type in a package belonging to the
|
||||
// application defining the key. An ExtensionData implementation must
|
||||
// check to see if the given key is familar to it, and if so return a
|
||||
// suitable value for the key.
|
||||
//
|
||||
// If the given key is unrecognized, the ExtensionData function must
|
||||
// return a nil interface. (Importantly, not an interface containing a nil
|
||||
// pointer of some other type.)
|
||||
// The common implementation of ExtensionData is a single switch statement
|
||||
// over "key" which has a default case returning nil.
|
||||
//
|
||||
// The meaning of any given key is entirely up to the application that
|
||||
// defines it. Applications consuming ExtensionData from capsule types
|
||||
// should do so defensively: if the result of ExtensionData is not valid,
|
||||
// prefer to ignore it or gracefully produce an error rather than causing
|
||||
// a panic.
|
||||
ExtensionData func(key interface{}) interface{}
|
||||
}
|
||||
|
||||
// noCapsuleOps is a pointer to a CapsuleOps with no functions set, which
|
||||
// is used as the default operations value when a type is created using
|
||||
// the Capsule function.
|
||||
var noCapsuleOps = &CapsuleOps{}
|
||||
|
||||
func (ops *CapsuleOps) assertValid() {
|
||||
if ops.RawEquals == nil && ops.Equals != nil {
|
||||
panic("Equals cannot be set without RawEquals")
|
||||
}
|
||||
}
|
||||
|
||||
// CapsuleOps returns a pointer to the CapsuleOps value for a capsule type,
|
||||
// or panics if the receiver is not a capsule type.
|
||||
//
|
||||
// The caller must not modify the CapsuleOps.
|
||||
func (ty Type) CapsuleOps() *CapsuleOps {
|
||||
if !ty.IsCapsuleType() {
|
||||
panic("not a capsule-typed value")
|
||||
}
|
||||
|
||||
return ty.typeImpl.(*capsuleType).Ops
|
||||
}
|
||||
|
||||
// CapsuleExtensionData is a convenience interface to the ExtensionData
|
||||
// function that can be optionally implemented for a capsule type. It will
|
||||
// check to see if the underlying type implements ExtensionData and call it
|
||||
// if so. If not, it will return nil to indicate that the given key is not
|
||||
// supported.
|
||||
//
|
||||
// See the documentation for CapsuleOps.ExtensionData for more information
|
||||
// on the purpose of and usage of this mechanism.
|
||||
//
|
||||
// If CapsuleExtensionData is called on a non-capsule type then it will panic.
|
||||
func (ty Type) CapsuleExtensionData(key interface{}) interface{} {
|
||||
ops := ty.CapsuleOps()
|
||||
if ops.ExtensionData == nil {
|
||||
return nil
|
||||
}
|
||||
return ops.ExtensionData(key)
|
||||
}
|
34
vendor/github.com/zclconf/go-cty/cty/collection.go
generated
vendored
Normal file
34
vendor/github.com/zclconf/go-cty/cty/collection.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type collectionTypeImpl interface {
|
||||
ElementType() Type
|
||||
}
|
||||
|
||||
// IsCollectionType returns true if the given type supports the operations
|
||||
// that are defined for all collection types.
|
||||
func (t Type) IsCollectionType() bool {
|
||||
_, ok := t.typeImpl.(collectionTypeImpl)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ElementType returns the element type of the receiver if it is a collection
|
||||
// type, or panics if it is not. Use IsCollectionType first to test whether
|
||||
// this method will succeed.
|
||||
func (t Type) ElementType() Type {
|
||||
if ct, ok := t.typeImpl.(collectionTypeImpl); ok {
|
||||
return ct.ElementType()
|
||||
}
|
||||
panic(errors.New("not a collection type"))
|
||||
}
|
||||
|
||||
// ElementCallback is a callback type used for iterating over elements of
|
||||
// collections and attributes of objects.
|
||||
//
|
||||
// The types of key and value depend on what type is being iterated over.
|
||||
// Return true to stop iterating after the current element, or false to
|
||||
// continue iterating.
|
||||
type ElementCallback func(key Value, val Value) (stop bool)
|
165
vendor/github.com/zclconf/go-cty/cty/convert/compare_types.go
generated
vendored
Normal file
165
vendor/github.com/zclconf/go-cty/cty/convert/compare_types.go
generated
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// compareTypes implements a preference order for unification.
|
||||
//
|
||||
// The result of this method is not useful for anything other than unification
|
||||
// preferences, since it assumes that the caller will verify that any suggested
|
||||
// conversion is actually possible and it is thus able to to make certain
|
||||
// optimistic assumptions.
|
||||
func compareTypes(a cty.Type, b cty.Type) int {
|
||||
|
||||
// DynamicPseudoType always has lowest preference, because anything can
|
||||
// convert to it (it acts as a placeholder for "any type") and we want
|
||||
// to optimistically assume that any dynamics will converge on matching
|
||||
// their neighbors.
|
||||
if a == cty.DynamicPseudoType || b == cty.DynamicPseudoType {
|
||||
if a != cty.DynamicPseudoType {
|
||||
return -1
|
||||
}
|
||||
if b != cty.DynamicPseudoType {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
if a.IsPrimitiveType() && b.IsPrimitiveType() {
|
||||
// String is a supertype of all primitive types, because we can
|
||||
// represent all primitive values as specially-formatted strings.
|
||||
if a == cty.String || b == cty.String {
|
||||
if a != cty.String {
|
||||
return 1
|
||||
}
|
||||
if b != cty.String {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
if a.IsListType() && b.IsListType() {
|
||||
return compareTypes(a.ElementType(), b.ElementType())
|
||||
}
|
||||
if a.IsSetType() && b.IsSetType() {
|
||||
return compareTypes(a.ElementType(), b.ElementType())
|
||||
}
|
||||
if a.IsMapType() && b.IsMapType() {
|
||||
return compareTypes(a.ElementType(), b.ElementType())
|
||||
}
|
||||
|
||||
// From this point on we may have swapped the two items in order to
|
||||
// simplify our cases. Therefore any non-zero return after this point
|
||||
// must be multiplied by "swap" to potentially invert the return value
|
||||
// if needed.
|
||||
swap := 1
|
||||
switch {
|
||||
case a.IsTupleType() && b.IsListType():
|
||||
fallthrough
|
||||
case a.IsObjectType() && b.IsMapType():
|
||||
fallthrough
|
||||
case a.IsSetType() && b.IsTupleType():
|
||||
fallthrough
|
||||
case a.IsSetType() && b.IsListType():
|
||||
a, b = b, a
|
||||
swap = -1
|
||||
}
|
||||
|
||||
if b.IsSetType() && (a.IsTupleType() || a.IsListType()) {
|
||||
// We'll just optimistically assume that the element types are
|
||||
// unifyable/convertible, and let a second recursive pass
|
||||
// figure out how to make that so.
|
||||
return -1 * swap
|
||||
}
|
||||
|
||||
if a.IsListType() && b.IsTupleType() {
|
||||
// We'll just optimistically assume that the tuple's element types
|
||||
// can be unified into something compatible with the list's element
|
||||
// type.
|
||||
return -1 * swap
|
||||
}
|
||||
|
||||
if a.IsMapType() && b.IsObjectType() {
|
||||
// We'll just optimistically assume that the object's attribute types
|
||||
// can be unified into something compatible with the map's element
|
||||
// type.
|
||||
return -1 * swap
|
||||
}
|
||||
|
||||
// For object and tuple types, comparing two types doesn't really tell
|
||||
// the whole story because it may be possible to construct a new type C
|
||||
// that is the supertype of both A and B by unifying each attribute/element
|
||||
// separately. That possibility is handled by Unify as a follow-up if
|
||||
// type sorting is insufficient to produce a valid result.
|
||||
//
|
||||
// Here we will take care of the simple possibilities where no new type
|
||||
// is needed.
|
||||
if a.IsObjectType() && b.IsObjectType() {
|
||||
atysA := a.AttributeTypes()
|
||||
atysB := b.AttributeTypes()
|
||||
|
||||
if len(atysA) != len(atysB) {
|
||||
return 0
|
||||
}
|
||||
|
||||
hasASuper := false
|
||||
hasBSuper := false
|
||||
for k := range atysA {
|
||||
if _, has := atysB[k]; !has {
|
||||
return 0
|
||||
}
|
||||
|
||||
cmp := compareTypes(atysA[k], atysB[k])
|
||||
if cmp < 0 {
|
||||
hasASuper = true
|
||||
} else if cmp > 0 {
|
||||
hasBSuper = true
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case hasASuper && hasBSuper:
|
||||
return 0
|
||||
case hasASuper:
|
||||
return -1 * swap
|
||||
case hasBSuper:
|
||||
return 1 * swap
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if a.IsTupleType() && b.IsTupleType() {
|
||||
etysA := a.TupleElementTypes()
|
||||
etysB := b.TupleElementTypes()
|
||||
|
||||
if len(etysA) != len(etysB) {
|
||||
return 0
|
||||
}
|
||||
|
||||
hasASuper := false
|
||||
hasBSuper := false
|
||||
for i := range etysA {
|
||||
cmp := compareTypes(etysA[i], etysB[i])
|
||||
if cmp < 0 {
|
||||
hasASuper = true
|
||||
} else if cmp > 0 {
|
||||
hasBSuper = true
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case hasASuper && hasBSuper:
|
||||
return 0
|
||||
case hasASuper:
|
||||
return -1 * swap
|
||||
case hasBSuper:
|
||||
return 1 * swap
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
181
vendor/github.com/zclconf/go-cty/cty/convert/conversion.go
generated
vendored
Normal file
181
vendor/github.com/zclconf/go-cty/cty/convert/conversion.go
generated
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// conversion is an internal variant of Conversion that carries around
|
||||
// a cty.Path to be used in error responses.
|
||||
type conversion func(cty.Value, cty.Path) (cty.Value, error)
|
||||
|
||||
func getConversion(in cty.Type, out cty.Type, unsafe bool) conversion {
|
||||
conv := getConversionKnown(in, out, unsafe)
|
||||
if conv == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wrap the conversion in some standard checks that we don't want to
|
||||
// have to repeat in every conversion function.
|
||||
var ret conversion
|
||||
ret = func(in cty.Value, path cty.Path) (cty.Value, error) {
|
||||
if in.IsMarked() {
|
||||
// We must unmark during the conversion and then re-apply the
|
||||
// same marks to the result.
|
||||
in, inMarks := in.Unmark()
|
||||
v, err := ret(in, path)
|
||||
if v != cty.NilVal {
|
||||
v = v.WithMarks(inMarks)
|
||||
}
|
||||
return v, err
|
||||
}
|
||||
|
||||
if out == cty.DynamicPseudoType {
|
||||
// Conversion to DynamicPseudoType always just passes through verbatim.
|
||||
return in, nil
|
||||
}
|
||||
if !in.IsKnown() {
|
||||
return cty.UnknownVal(out), nil
|
||||
}
|
||||
if in.IsNull() {
|
||||
// We'll pass through nulls, albeit type converted, and let
|
||||
// the caller deal with whatever handling they want to do in
|
||||
// case null values are considered valid in some applications.
|
||||
return cty.NullVal(out), nil
|
||||
}
|
||||
|
||||
return conv(in, path)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion {
|
||||
switch {
|
||||
|
||||
case out == cty.DynamicPseudoType:
|
||||
// Conversion *to* DynamicPseudoType means that the caller wishes
|
||||
// to allow any type in this position, so we'll produce a do-nothing
|
||||
// conversion that just passes through the value as-is.
|
||||
return dynamicPassthrough
|
||||
|
||||
case unsafe && in == cty.DynamicPseudoType:
|
||||
// Conversion *from* DynamicPseudoType means that we have a value
|
||||
// whose type isn't yet known during type checking. For these we will
|
||||
// assume that conversion will succeed and deal with any errors that
|
||||
// result (which is why we can only do this when "unsafe" is set).
|
||||
return dynamicFixup(out)
|
||||
|
||||
case in.IsPrimitiveType() && out.IsPrimitiveType():
|
||||
conv := primitiveConversionsSafe[in][out]
|
||||
if conv != nil {
|
||||
return conv
|
||||
}
|
||||
if unsafe {
|
||||
return primitiveConversionsUnsafe[in][out]
|
||||
}
|
||||
return nil
|
||||
|
||||
case out.IsObjectType() && in.IsObjectType():
|
||||
return conversionObjectToObject(in, out, unsafe)
|
||||
|
||||
case out.IsTupleType() && in.IsTupleType():
|
||||
return conversionTupleToTuple(in, out, unsafe)
|
||||
|
||||
case out.IsListType() && (in.IsListType() || in.IsSetType()):
|
||||
inEty := in.ElementType()
|
||||
outEty := out.ElementType()
|
||||
if inEty.Equals(outEty) {
|
||||
// This indicates that we're converting from list to set with
|
||||
// the same element type, so we don't need an element converter.
|
||||
return conversionCollectionToList(outEty, nil)
|
||||
}
|
||||
|
||||
convEty := getConversion(inEty, outEty, unsafe)
|
||||
if convEty == nil {
|
||||
return nil
|
||||
}
|
||||
return conversionCollectionToList(outEty, convEty)
|
||||
|
||||
case out.IsSetType() && (in.IsListType() || in.IsSetType()):
|
||||
if in.IsListType() && !unsafe {
|
||||
// Conversion from list to map is unsafe because it will lose
|
||||
// information: the ordering will not be preserved, and any
|
||||
// duplicate elements will be conflated.
|
||||
return nil
|
||||
}
|
||||
inEty := in.ElementType()
|
||||
outEty := out.ElementType()
|
||||
convEty := getConversion(inEty, outEty, unsafe)
|
||||
if inEty.Equals(outEty) {
|
||||
// This indicates that we're converting from set to list with
|
||||
// the same element type, so we don't need an element converter.
|
||||
return conversionCollectionToSet(outEty, nil)
|
||||
}
|
||||
|
||||
if convEty == nil {
|
||||
return nil
|
||||
}
|
||||
return conversionCollectionToSet(outEty, convEty)
|
||||
|
||||
case out.IsMapType() && in.IsMapType():
|
||||
inEty := in.ElementType()
|
||||
outEty := out.ElementType()
|
||||
convEty := getConversion(inEty, outEty, unsafe)
|
||||
if convEty == nil {
|
||||
return nil
|
||||
}
|
||||
return conversionCollectionToMap(outEty, convEty)
|
||||
|
||||
case out.IsListType() && in.IsTupleType():
|
||||
outEty := out.ElementType()
|
||||
return conversionTupleToList(in, outEty, unsafe)
|
||||
|
||||
case out.IsSetType() && in.IsTupleType():
|
||||
outEty := out.ElementType()
|
||||
return conversionTupleToSet(in, outEty, unsafe)
|
||||
|
||||
case out.IsMapType() && in.IsObjectType():
|
||||
outEty := out.ElementType()
|
||||
return conversionObjectToMap(in, outEty, unsafe)
|
||||
|
||||
case in.IsCapsuleType() || out.IsCapsuleType():
|
||||
if !unsafe {
|
||||
// Capsule types can only participate in "unsafe" conversions,
|
||||
// because we don't know enough about their conversion behaviors
|
||||
// to be sure that they will always be safe.
|
||||
return nil
|
||||
}
|
||||
if in.Equals(out) {
|
||||
// conversion to self is never allowed
|
||||
return nil
|
||||
}
|
||||
if out.IsCapsuleType() {
|
||||
if fn := out.CapsuleOps().ConversionTo; fn != nil {
|
||||
return conversionToCapsule(in, out, fn)
|
||||
}
|
||||
}
|
||||
if in.IsCapsuleType() {
|
||||
if fn := in.CapsuleOps().ConversionFrom; fn != nil {
|
||||
return conversionFromCapsule(in, out, fn)
|
||||
}
|
||||
}
|
||||
// No conversion operation is available, then.
|
||||
return nil
|
||||
|
||||
default:
|
||||
return nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// retConversion wraps a conversion (internal type) so it can be returned
|
||||
// as a Conversion (public type).
|
||||
func retConversion(conv conversion) Conversion {
|
||||
if conv == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(in cty.Value) (cty.Value, error) {
|
||||
return conv(in, cty.Path(nil))
|
||||
}
|
||||
}
|
31
vendor/github.com/zclconf/go-cty/cty/convert/conversion_capsule.go
generated
vendored
Normal file
31
vendor/github.com/zclconf/go-cty/cty/convert/conversion_capsule.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
func conversionToCapsule(inTy, outTy cty.Type, fn func(inTy cty.Type) func(cty.Value, cty.Path) (interface{}, error)) conversion {
|
||||
rawConv := fn(inTy)
|
||||
if rawConv == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(in cty.Value, path cty.Path) (cty.Value, error) {
|
||||
rawV, err := rawConv(in, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
return cty.CapsuleVal(outTy, rawV), nil
|
||||
}
|
||||
}
|
||||
|
||||
func conversionFromCapsule(inTy, outTy cty.Type, fn func(outTy cty.Type) func(interface{}, cty.Path) (cty.Value, error)) conversion {
|
||||
rawConv := fn(outTy)
|
||||
if rawConv == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(in cty.Value, path cty.Path) (cty.Value, error) {
|
||||
return rawConv(in.EncapsulatedValue(), path)
|
||||
}
|
||||
}
|
340
vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go
generated
vendored
Normal file
340
vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go
generated
vendored
Normal file
@ -0,0 +1,340 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// conversionCollectionToList returns a conversion that will apply the given
|
||||
// conversion to all of the elements of a collection (something that supports
|
||||
// ForEachElement and LengthInt) and then returns the result as a list.
|
||||
//
|
||||
// "conv" can be nil if the elements are expected to already be of the
|
||||
// correct type and just need to be re-wrapped into a list. (For example,
|
||||
// if we're converting from a set into a list of the same element type.)
|
||||
func conversionCollectionToList(ety cty.Type, conv conversion) conversion {
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make([]cty.Value, 0, val.LengthInt())
|
||||
i := int64(0)
|
||||
path = append(path, nil)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(i),
|
||||
}
|
||||
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
elems = append(elems, val)
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
if len(elems) == 0 {
|
||||
return cty.ListValEmpty(ety), nil
|
||||
}
|
||||
|
||||
return cty.ListVal(elems), nil
|
||||
}
|
||||
}
|
||||
|
||||
// conversionCollectionToSet returns a conversion that will apply the given
|
||||
// conversion to all of the elements of a collection (something that supports
|
||||
// ForEachElement and LengthInt) and then returns the result as a set.
|
||||
//
|
||||
// "conv" can be nil if the elements are expected to already be of the
|
||||
// correct type and just need to be re-wrapped into a set. (For example,
|
||||
// if we're converting from a list into a set of the same element type.)
|
||||
func conversionCollectionToSet(ety cty.Type, conv conversion) conversion {
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make([]cty.Value, 0, val.LengthInt())
|
||||
i := int64(0)
|
||||
path = append(path, nil)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(i),
|
||||
}
|
||||
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
elems = append(elems, val)
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
if len(elems) == 0 {
|
||||
return cty.SetValEmpty(ety), nil
|
||||
}
|
||||
|
||||
return cty.SetVal(elems), nil
|
||||
}
|
||||
}
|
||||
|
||||
// conversionCollectionToMap returns a conversion that will apply the given
|
||||
// conversion to all of the elements of a collection (something that supports
|
||||
// ForEachElement and LengthInt) and then returns the result as a map.
|
||||
//
|
||||
// "conv" can be nil if the elements are expected to already be of the
|
||||
// correct type and just need to be re-wrapped into a map.
|
||||
func conversionCollectionToMap(ety cty.Type, conv conversion) conversion {
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make(map[string]cty.Value, 0)
|
||||
path = append(path, nil)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
key, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: key,
|
||||
}
|
||||
|
||||
keyStr, err := Convert(key, cty.String)
|
||||
if err != nil {
|
||||
// Should never happen, because keys can only be numbers or
|
||||
// strings and both can convert to string.
|
||||
return cty.DynamicVal, path.NewErrorf("cannot convert key type %s to string for map", key.Type().FriendlyName())
|
||||
}
|
||||
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
|
||||
elems[keyStr.AsString()] = val
|
||||
}
|
||||
|
||||
if len(elems) == 0 {
|
||||
return cty.MapValEmpty(ety), nil
|
||||
}
|
||||
|
||||
return cty.MapVal(elems), nil
|
||||
}
|
||||
}
|
||||
|
||||
// conversionTupleToSet returns a conversion that will take a value of the
|
||||
// given tuple type and return a set of the given element type.
|
||||
//
|
||||
// Will panic if the given tupleType isn't actually a tuple type.
|
||||
func conversionTupleToSet(tupleType cty.Type, listEty cty.Type, unsafe bool) conversion {
|
||||
tupleEtys := tupleType.TupleElementTypes()
|
||||
|
||||
if len(tupleEtys) == 0 {
|
||||
// Empty tuple short-circuit
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
return cty.SetValEmpty(listEty), nil
|
||||
}
|
||||
}
|
||||
|
||||
if listEty == cty.DynamicPseudoType {
|
||||
// This is a special case where the caller wants us to find
|
||||
// a suitable single type that all elements can convert to, if
|
||||
// possible.
|
||||
listEty, _ = unify(tupleEtys, unsafe)
|
||||
if listEty == cty.NilType {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
elemConvs := make([]conversion, len(tupleEtys))
|
||||
for i, tupleEty := range tupleEtys {
|
||||
if tupleEty.Equals(listEty) {
|
||||
// no conversion required
|
||||
continue
|
||||
}
|
||||
|
||||
elemConvs[i] = getConversion(tupleEty, listEty, unsafe)
|
||||
if elemConvs[i] == nil {
|
||||
// If any of our element conversions are impossible, then the our
|
||||
// whole conversion is impossible.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// If we fall out here then a conversion is possible, using the
|
||||
// element conversions in elemConvs
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make([]cty.Value, 0, len(elemConvs))
|
||||
path = append(path, nil)
|
||||
i := int64(0)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(i),
|
||||
}
|
||||
|
||||
conv := elemConvs[i]
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
elems = append(elems, val)
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
return cty.SetVal(elems), nil
|
||||
}
|
||||
}
|
||||
|
||||
// conversionTupleToList returns a conversion that will take a value of the
|
||||
// given tuple type and return a list of the given element type.
|
||||
//
|
||||
// Will panic if the given tupleType isn't actually a tuple type.
|
||||
func conversionTupleToList(tupleType cty.Type, listEty cty.Type, unsafe bool) conversion {
|
||||
tupleEtys := tupleType.TupleElementTypes()
|
||||
|
||||
if len(tupleEtys) == 0 {
|
||||
// Empty tuple short-circuit
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
return cty.ListValEmpty(listEty), nil
|
||||
}
|
||||
}
|
||||
|
||||
if listEty == cty.DynamicPseudoType {
|
||||
// This is a special case where the caller wants us to find
|
||||
// a suitable single type that all elements can convert to, if
|
||||
// possible.
|
||||
listEty, _ = unify(tupleEtys, unsafe)
|
||||
if listEty == cty.NilType {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
elemConvs := make([]conversion, len(tupleEtys))
|
||||
for i, tupleEty := range tupleEtys {
|
||||
if tupleEty.Equals(listEty) {
|
||||
// no conversion required
|
||||
continue
|
||||
}
|
||||
|
||||
elemConvs[i] = getConversion(tupleEty, listEty, unsafe)
|
||||
if elemConvs[i] == nil {
|
||||
// If any of our element conversions are impossible, then the our
|
||||
// whole conversion is impossible.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// If we fall out here then a conversion is possible, using the
|
||||
// element conversions in elemConvs
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make([]cty.Value, 0, len(elemConvs))
|
||||
path = append(path, nil)
|
||||
i := int64(0)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(i),
|
||||
}
|
||||
|
||||
conv := elemConvs[i]
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
elems = append(elems, val)
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
return cty.ListVal(elems), nil
|
||||
}
|
||||
}
|
||||
|
||||
// conversionObjectToMap returns a conversion that will take a value of the
|
||||
// given object type and return a map of the given element type.
|
||||
//
|
||||
// Will panic if the given objectType isn't actually an object type.
|
||||
func conversionObjectToMap(objectType cty.Type, mapEty cty.Type, unsafe bool) conversion {
|
||||
objectAtys := objectType.AttributeTypes()
|
||||
|
||||
if len(objectAtys) == 0 {
|
||||
// Empty object short-circuit
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
return cty.MapValEmpty(mapEty), nil
|
||||
}
|
||||
}
|
||||
|
||||
if mapEty == cty.DynamicPseudoType {
|
||||
// This is a special case where the caller wants us to find
|
||||
// a suitable single type that all elements can convert to, if
|
||||
// possible.
|
||||
objectAtysList := make([]cty.Type, 0, len(objectAtys))
|
||||
for _, aty := range objectAtys {
|
||||
objectAtysList = append(objectAtysList, aty)
|
||||
}
|
||||
mapEty, _ = unify(objectAtysList, unsafe)
|
||||
if mapEty == cty.NilType {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
elemConvs := make(map[string]conversion, len(objectAtys))
|
||||
for name, objectAty := range objectAtys {
|
||||
if objectAty.Equals(mapEty) {
|
||||
// no conversion required
|
||||
continue
|
||||
}
|
||||
|
||||
elemConvs[name] = getConversion(objectAty, mapEty, unsafe)
|
||||
if elemConvs[name] == nil {
|
||||
// If any of our element conversions are impossible, then the our
|
||||
// whole conversion is impossible.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// If we fall out here then a conversion is possible, using the
|
||||
// element conversions in elemConvs
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make(map[string]cty.Value, len(elemConvs))
|
||||
path = append(path, nil)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
name, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: name,
|
||||
}
|
||||
|
||||
conv := elemConvs[name.AsString()]
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
elems[name.AsString()] = val
|
||||
}
|
||||
|
||||
return cty.MapVal(elems), nil
|
||||
}
|
||||
}
|
33
vendor/github.com/zclconf/go-cty/cty/convert/conversion_dynamic.go
generated
vendored
Normal file
33
vendor/github.com/zclconf/go-cty/cty/convert/conversion_dynamic.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// dynamicFixup deals with just-in-time conversions of values that were
|
||||
// input-typed as cty.DynamicPseudoType during analysis, ensuring that
|
||||
// we end up with the desired output type once the value is known, or
|
||||
// failing with an error if that is not possible.
|
||||
//
|
||||
// This is in the spirit of the cty philosophy of optimistically assuming that
|
||||
// DynamicPseudoType values will become the intended value eventually, and
|
||||
// dealing with any inconsistencies during final evaluation.
|
||||
func dynamicFixup(wantType cty.Type) conversion {
|
||||
return func(in cty.Value, path cty.Path) (cty.Value, error) {
|
||||
ret, err := Convert(in, wantType)
|
||||
if err != nil {
|
||||
// Re-wrap this error so that the returned path is relative
|
||||
// to the caller's original value, rather than relative to our
|
||||
// conversion value here.
|
||||
return cty.NilVal, path.NewError(err)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
// dynamicPassthrough is an identity conversion that is used when the
|
||||
// target type is DynamicPseudoType, indicating that the caller doesn't care
|
||||
// which type is returned.
|
||||
func dynamicPassthrough(in cty.Value, path cty.Path) (cty.Value, error) {
|
||||
return in, nil
|
||||
}
|
76
vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go
generated
vendored
Normal file
76
vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// conversionObjectToObject returns a conversion that will make the input
|
||||
// object type conform to the output object type, if possible.
|
||||
//
|
||||
// Conversion is possible only if the output type is a subset of the input
|
||||
// type, meaning that each attribute of the output type has a corresponding
|
||||
// attribute in the input type where a recursive conversion is available.
|
||||
//
|
||||
// Shallow object conversions work the same for both safe and unsafe modes,
|
||||
// but the safety flag is passed on to recursive conversions and may thus
|
||||
// limit the above definition of "subset".
|
||||
func conversionObjectToObject(in, out cty.Type, unsafe bool) conversion {
|
||||
inAtys := in.AttributeTypes()
|
||||
outAtys := out.AttributeTypes()
|
||||
attrConvs := make(map[string]conversion)
|
||||
|
||||
for name, outAty := range outAtys {
|
||||
inAty, exists := inAtys[name]
|
||||
if !exists {
|
||||
// No conversion is available, then.
|
||||
return nil
|
||||
}
|
||||
|
||||
if inAty.Equals(outAty) {
|
||||
// No conversion needed, but we'll still record the attribute
|
||||
// in our map for later reference.
|
||||
attrConvs[name] = nil
|
||||
continue
|
||||
}
|
||||
|
||||
attrConvs[name] = getConversion(inAty, outAty, unsafe)
|
||||
if attrConvs[name] == nil {
|
||||
// If a recursive conversion isn't available, then our top-level
|
||||
// configuration is impossible too.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here then a conversion is possible, using the attribute
|
||||
// conversions given in attrConvs.
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
attrVals := make(map[string]cty.Value, len(attrConvs))
|
||||
path = append(path, nil)
|
||||
pathStep := &path[len(path)-1]
|
||||
|
||||
for it := val.ElementIterator(); it.Next(); {
|
||||
nameVal, val := it.Element()
|
||||
var err error
|
||||
|
||||
name := nameVal.AsString()
|
||||
*pathStep = cty.GetAttrStep{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
conv, exists := attrConvs[name]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
|
||||
attrVals[name] = val
|
||||
}
|
||||
|
||||
return cty.ObjectVal(attrVals), nil
|
||||
}
|
||||
}
|
57
vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go
generated
vendored
Normal file
57
vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
var stringTrue = cty.StringVal("true")
|
||||
var stringFalse = cty.StringVal("false")
|
||||
|
||||
var primitiveConversionsSafe = map[cty.Type]map[cty.Type]conversion{
|
||||
cty.Number: {
|
||||
cty.String: func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
f := val.AsBigFloat()
|
||||
return cty.StringVal(f.Text('f', -1)), nil
|
||||
},
|
||||
},
|
||||
cty.Bool: {
|
||||
cty.String: func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
if val.True() {
|
||||
return stringTrue, nil
|
||||
} else {
|
||||
return stringFalse, nil
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var primitiveConversionsUnsafe = map[cty.Type]map[cty.Type]conversion{
|
||||
cty.String: {
|
||||
cty.Number: func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
v, err := cty.ParseNumberVal(val.AsString())
|
||||
if err != nil {
|
||||
return cty.NilVal, path.NewErrorf("a number is required")
|
||||
}
|
||||
return v, nil
|
||||
},
|
||||
cty.Bool: func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
switch val.AsString() {
|
||||
case "true", "1":
|
||||
return cty.True, nil
|
||||
case "false", "0":
|
||||
return cty.False, nil
|
||||
default:
|
||||
switch strings.ToLower(val.AsString()) {
|
||||
case "true":
|
||||
return cty.NilVal, path.NewErrorf("a bool is required; to convert from string, use lowercase \"true\"")
|
||||
case "false":
|
||||
return cty.NilVal, path.NewErrorf("a bool is required; to convert from string, use lowercase \"false\"")
|
||||
default:
|
||||
return cty.NilVal, path.NewErrorf("a bool is required")
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
71
vendor/github.com/zclconf/go-cty/cty/convert/conversion_tuple.go
generated
vendored
Normal file
71
vendor/github.com/zclconf/go-cty/cty/convert/conversion_tuple.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// conversionTupleToTuple returns a conversion that will make the input
|
||||
// tuple type conform to the output tuple type, if possible.
|
||||
//
|
||||
// Conversion is possible only if the two tuple types have the same number
|
||||
// of elements and the corresponding elements by index can be converted.
|
||||
//
|
||||
// Shallow tuple conversions work the same for both safe and unsafe modes,
|
||||
// but the safety flag is passed on to recursive conversions and may thus
|
||||
// limit which element type conversions are possible.
|
||||
func conversionTupleToTuple(in, out cty.Type, unsafe bool) conversion {
|
||||
inEtys := in.TupleElementTypes()
|
||||
outEtys := out.TupleElementTypes()
|
||||
|
||||
if len(inEtys) != len(outEtys) {
|
||||
return nil // no conversion is possible
|
||||
}
|
||||
|
||||
elemConvs := make([]conversion, len(inEtys))
|
||||
|
||||
for i, outEty := range outEtys {
|
||||
inEty := inEtys[i]
|
||||
|
||||
if inEty.Equals(outEty) {
|
||||
// No conversion needed, so we can leave this one nil.
|
||||
continue
|
||||
}
|
||||
|
||||
elemConvs[i] = getConversion(inEty, outEty, unsafe)
|
||||
if elemConvs[i] == nil {
|
||||
// If a recursive conversion isn't available, then our top-level
|
||||
// configuration is impossible too.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here then a conversion is possible, using the element
|
||||
// conversions given in elemConvs.
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elemVals := make([]cty.Value, len(elemConvs))
|
||||
path = append(path, nil)
|
||||
pathStep := &path[len(path)-1]
|
||||
|
||||
i := 0
|
||||
for it := val.ElementIterator(); it.Next(); i++ {
|
||||
_, val := it.Element()
|
||||
var err error
|
||||
|
||||
*pathStep = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(int64(i)),
|
||||
}
|
||||
|
||||
conv := elemConvs[i]
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
|
||||
elemVals[i] = val
|
||||
}
|
||||
|
||||
return cty.TupleVal(elemVals), nil
|
||||
}
|
||||
}
|
15
vendor/github.com/zclconf/go-cty/cty/convert/doc.go
generated
vendored
Normal file
15
vendor/github.com/zclconf/go-cty/cty/convert/doc.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// Package convert contains some routines for converting between cty types.
|
||||
// The intent of providing this package is to encourage applications using
|
||||
// cty to have consistent type conversion behavior for maximal interoperability
|
||||
// when Values pass from one application to another.
|
||||
//
|
||||
// The conversions are categorized into two categories. "Safe" conversions are
|
||||
// ones that are guaranteed to succeed if given a non-null value of the
|
||||
// appropriate source type. "Unsafe" conversions, on the other hand, are valid
|
||||
// for only a subset of input values, and thus may fail with an error when
|
||||
// called for values outside of that valid subset.
|
||||
//
|
||||
// The functions whose names end in Unsafe support all of the conversions that
|
||||
// are supported by the corresponding functions whose names do not have that
|
||||
// suffix, and then additional unsafe conversions as well.
|
||||
package convert
|
220
vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go
generated
vendored
Normal file
220
vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go
generated
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// MismatchMessage is a helper to return an English-language description of
|
||||
// the differences between got and want, phrased as a reason why got does
|
||||
// not conform to want.
|
||||
//
|
||||
// This function does not itself attempt conversion, and so it should generally
|
||||
// be used only after a conversion has failed, to report the conversion failure
|
||||
// to an English-speaking user. The result will be confusing got is actually
|
||||
// conforming to or convertable to want.
|
||||
//
|
||||
// The shorthand helper function Convert uses this function internally to
|
||||
// produce its error messages, so callers of that function do not need to
|
||||
// also use MismatchMessage.
|
||||
//
|
||||
// This function is similar to Type.TestConformance, but it is tailored to
|
||||
// describing conversion failures and so the messages it generates relate
|
||||
// specifically to the conversion rules implemented in this package.
|
||||
func MismatchMessage(got, want cty.Type) string {
|
||||
switch {
|
||||
|
||||
case got.IsObjectType() && want.IsObjectType():
|
||||
// If both types are object types then we may be able to say something
|
||||
// about their respective attributes.
|
||||
return mismatchMessageObjects(got, want)
|
||||
|
||||
case got.IsTupleType() && want.IsListType() && want.ElementType() == cty.DynamicPseudoType:
|
||||
// If conversion from tuple to list failed then it's because we couldn't
|
||||
// find a common type to convert all of the tuple elements to.
|
||||
return "all list elements must have the same type"
|
||||
|
||||
case got.IsTupleType() && want.IsSetType() && want.ElementType() == cty.DynamicPseudoType:
|
||||
// If conversion from tuple to set failed then it's because we couldn't
|
||||
// find a common type to convert all of the tuple elements to.
|
||||
return "all set elements must have the same type"
|
||||
|
||||
case got.IsObjectType() && want.IsMapType() && want.ElementType() == cty.DynamicPseudoType:
|
||||
// If conversion from object to map failed then it's because we couldn't
|
||||
// find a common type to convert all of the object attributes to.
|
||||
return "all map elements must have the same type"
|
||||
|
||||
case (got.IsTupleType() || got.IsObjectType()) && want.IsCollectionType():
|
||||
return mismatchMessageCollectionsFromStructural(got, want)
|
||||
|
||||
case got.IsCollectionType() && want.IsCollectionType():
|
||||
return mismatchMessageCollectionsFromCollections(got, want)
|
||||
|
||||
default:
|
||||
// If we have nothing better to say, we'll just state what was required.
|
||||
return want.FriendlyNameForConstraint() + " required"
|
||||
}
|
||||
}
|
||||
|
||||
func mismatchMessageObjects(got, want cty.Type) string {
|
||||
// Per our conversion rules, "got" is allowed to be a superset of "want",
|
||||
// and so we'll produce error messages here under that assumption.
|
||||
gotAtys := got.AttributeTypes()
|
||||
wantAtys := want.AttributeTypes()
|
||||
|
||||
// If we find missing attributes then we'll report those in preference,
|
||||
// but if not then we will report a maximum of one non-conforming
|
||||
// attribute, just to keep our messages relatively terse.
|
||||
// We'll also prefer to report a recursive type error from an _unsafe_
|
||||
// conversion over a safe one, because these are subjectively more
|
||||
// "serious".
|
||||
var missingAttrs []string
|
||||
var unsafeMismatchAttr string
|
||||
var safeMismatchAttr string
|
||||
|
||||
for name, wantAty := range wantAtys {
|
||||
gotAty, exists := gotAtys[name]
|
||||
if !exists {
|
||||
missingAttrs = append(missingAttrs, name)
|
||||
continue
|
||||
}
|
||||
|
||||
// We'll now try to convert these attributes in isolation and
|
||||
// see if we have a nested conversion error to report.
|
||||
// We'll try an unsafe conversion first, and then fall back on
|
||||
// safe if unsafe is possible.
|
||||
|
||||
// If we already have an unsafe mismatch attr error then we won't bother
|
||||
// hunting for another one.
|
||||
if unsafeMismatchAttr != "" {
|
||||
continue
|
||||
}
|
||||
if conv := GetConversionUnsafe(gotAty, wantAty); conv == nil {
|
||||
unsafeMismatchAttr = fmt.Sprintf("attribute %q: %s", name, MismatchMessage(gotAty, wantAty))
|
||||
}
|
||||
|
||||
// If we already have a safe mismatch attr error then we won't bother
|
||||
// hunting for another one.
|
||||
if safeMismatchAttr != "" {
|
||||
continue
|
||||
}
|
||||
if conv := GetConversion(gotAty, wantAty); conv == nil {
|
||||
safeMismatchAttr = fmt.Sprintf("attribute %q: %s", name, MismatchMessage(gotAty, wantAty))
|
||||
}
|
||||
}
|
||||
|
||||
// We should now have collected at least one problem. If we have more than
|
||||
// one then we'll use our preference order to decide what is most important
|
||||
// to report.
|
||||
switch {
|
||||
|
||||
case len(missingAttrs) != 0:
|
||||
sort.Strings(missingAttrs)
|
||||
switch len(missingAttrs) {
|
||||
case 1:
|
||||
return fmt.Sprintf("attribute %q is required", missingAttrs[0])
|
||||
case 2:
|
||||
return fmt.Sprintf("attributes %q and %q are required", missingAttrs[0], missingAttrs[1])
|
||||
default:
|
||||
sort.Strings(missingAttrs)
|
||||
var buf bytes.Buffer
|
||||
for _, name := range missingAttrs[:len(missingAttrs)-1] {
|
||||
fmt.Fprintf(&buf, "%q, ", name)
|
||||
}
|
||||
fmt.Fprintf(&buf, "and %q", missingAttrs[len(missingAttrs)-1])
|
||||
return fmt.Sprintf("attributes %s are required", buf.Bytes())
|
||||
}
|
||||
|
||||
case unsafeMismatchAttr != "":
|
||||
return unsafeMismatchAttr
|
||||
|
||||
case safeMismatchAttr != "":
|
||||
return safeMismatchAttr
|
||||
|
||||
default:
|
||||
// We should never get here, but if we do then we'll return
|
||||
// just a generic message.
|
||||
return "incorrect object attributes"
|
||||
}
|
||||
}
|
||||
|
||||
func mismatchMessageCollectionsFromStructural(got, want cty.Type) string {
|
||||
// First some straightforward cases where the kind is just altogether wrong.
|
||||
switch {
|
||||
case want.IsListType() && !got.IsTupleType():
|
||||
return want.FriendlyNameForConstraint() + " required"
|
||||
case want.IsSetType() && !got.IsTupleType():
|
||||
return want.FriendlyNameForConstraint() + " required"
|
||||
case want.IsMapType() && !got.IsObjectType():
|
||||
return want.FriendlyNameForConstraint() + " required"
|
||||
}
|
||||
|
||||
// If the kinds are matched well enough then we'll move on to checking
|
||||
// individual elements.
|
||||
wantEty := want.ElementType()
|
||||
switch {
|
||||
case got.IsTupleType():
|
||||
for i, gotEty := range got.TupleElementTypes() {
|
||||
if gotEty.Equals(wantEty) {
|
||||
continue // exact match, so no problem
|
||||
}
|
||||
if conv := getConversion(gotEty, wantEty, true); conv != nil {
|
||||
continue // conversion is available, so no problem
|
||||
}
|
||||
return fmt.Sprintf("element %d: %s", i, MismatchMessage(gotEty, wantEty))
|
||||
}
|
||||
|
||||
// If we get down here then something weird is going on but we'll
|
||||
// return a reasonable fallback message anyway.
|
||||
return fmt.Sprintf("all elements must be %s", wantEty.FriendlyNameForConstraint())
|
||||
|
||||
case got.IsObjectType():
|
||||
for name, gotAty := range got.AttributeTypes() {
|
||||
if gotAty.Equals(wantEty) {
|
||||
continue // exact match, so no problem
|
||||
}
|
||||
if conv := getConversion(gotAty, wantEty, true); conv != nil {
|
||||
continue // conversion is available, so no problem
|
||||
}
|
||||
return fmt.Sprintf("element %q: %s", name, MismatchMessage(gotAty, wantEty))
|
||||
}
|
||||
|
||||
// If we get down here then something weird is going on but we'll
|
||||
// return a reasonable fallback message anyway.
|
||||
return fmt.Sprintf("all elements must be %s", wantEty.FriendlyNameForConstraint())
|
||||
|
||||
default:
|
||||
// Should not be possible to get here since we only call this function
|
||||
// with got as structural types, but...
|
||||
return want.FriendlyNameForConstraint() + " required"
|
||||
}
|
||||
}
|
||||
|
||||
func mismatchMessageCollectionsFromCollections(got, want cty.Type) string {
|
||||
// First some straightforward cases where the kind is just altogether wrong.
|
||||
switch {
|
||||
case want.IsListType() && !(got.IsListType() || got.IsSetType()):
|
||||
return want.FriendlyNameForConstraint() + " required"
|
||||
case want.IsSetType() && !(got.IsListType() || got.IsSetType()):
|
||||
return want.FriendlyNameForConstraint() + " required"
|
||||
case want.IsMapType() && !got.IsMapType():
|
||||
return want.FriendlyNameForConstraint() + " required"
|
||||
}
|
||||
|
||||
// If the kinds are matched well enough then we'll check the element types.
|
||||
gotEty := got.ElementType()
|
||||
wantEty := want.ElementType()
|
||||
noun := "element type"
|
||||
switch {
|
||||
case want.IsListType():
|
||||
noun = "list element type"
|
||||
case want.IsSetType():
|
||||
noun = "set element type"
|
||||
case want.IsMapType():
|
||||
noun = "map element type"
|
||||
}
|
||||
return fmt.Sprintf("incorrect %s: %s", noun, MismatchMessage(gotEty, wantEty))
|
||||
}
|
83
vendor/github.com/zclconf/go-cty/cty/convert/public.go
generated
vendored
Normal file
83
vendor/github.com/zclconf/go-cty/cty/convert/public.go
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// This file contains the public interface of this package, which is intended
|
||||
// to be a small, convenient interface designed for easy integration into
|
||||
// a hypothetical language type checker and interpreter.
|
||||
|
||||
// Conversion is a named function type representing a conversion from a
|
||||
// value of one type to a value of another type.
|
||||
//
|
||||
// The source type for a conversion is always the source type given to
|
||||
// the function that returned the Conversion, but there is no way to recover
|
||||
// that from a Conversion value itself. If a Conversion is given a value
|
||||
// that is not of its expected type (with the exception of DynamicPseudoType,
|
||||
// which is always supported) then the function may panic or produce undefined
|
||||
// results.
|
||||
type Conversion func(in cty.Value) (out cty.Value, err error)
|
||||
|
||||
// GetConversion returns a Conversion between the given in and out Types if
|
||||
// a safe one is available, or returns nil otherwise.
|
||||
func GetConversion(in cty.Type, out cty.Type) Conversion {
|
||||
return retConversion(getConversion(in, out, false))
|
||||
}
|
||||
|
||||
// GetConversionUnsafe returns a Conversion between the given in and out Types
|
||||
// if either a safe or unsafe one is available, or returns nil otherwise.
|
||||
func GetConversionUnsafe(in cty.Type, out cty.Type) Conversion {
|
||||
return retConversion(getConversion(in, out, true))
|
||||
}
|
||||
|
||||
// Convert returns the result of converting the given value to the given type
|
||||
// if an safe or unsafe conversion is available, or returns an error if such a
|
||||
// conversion is impossible.
|
||||
//
|
||||
// This is a convenience wrapper around calling GetConversionUnsafe and then
|
||||
// immediately passing the given value to the resulting function.
|
||||
func Convert(in cty.Value, want cty.Type) (cty.Value, error) {
|
||||
if in.Type().Equals(want) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
conv := GetConversionUnsafe(in.Type(), want)
|
||||
if conv == nil {
|
||||
return cty.NilVal, errors.New(MismatchMessage(in.Type(), want))
|
||||
}
|
||||
return conv(in)
|
||||
}
|
||||
|
||||
// Unify attempts to find the most general type that can be converted from
|
||||
// all of the given types. If this is possible, that type is returned along
|
||||
// with a slice of necessary conversions for some of the given types.
|
||||
//
|
||||
// If no common supertype can be found, this function returns cty.NilType and
|
||||
// a nil slice.
|
||||
//
|
||||
// If a common supertype *can* be found, the returned slice will always be
|
||||
// non-nil and will contain a non-nil conversion for each given type that
|
||||
// needs to be converted, with indices corresponding to the input slice.
|
||||
// Any given type that does *not* need conversion (because it is already of
|
||||
// the appropriate type) will have a nil Conversion.
|
||||
//
|
||||
// cty.DynamicPseudoType is, as usual, a special case. If the given type list
|
||||
// contains a mixture of dynamic and non-dynamic types, the dynamic types are
|
||||
// disregarded for type selection and a conversion is returned for them that
|
||||
// will attempt a late conversion of the given value to the target type,
|
||||
// failing with a conversion error if the eventual concrete type is not
|
||||
// compatible. If *all* given types are DynamicPseudoType, or in the
|
||||
// degenerate case of an empty slice of types, the returned type is itself
|
||||
// cty.DynamicPseudoType and no conversions are attempted.
|
||||
func Unify(types []cty.Type) (cty.Type, []Conversion) {
|
||||
return unify(types, false)
|
||||
}
|
||||
|
||||
// UnifyUnsafe is the same as Unify except that it may return unsafe
|
||||
// conversions in situations where a safe conversion isn't also available.
|
||||
func UnifyUnsafe(types []cty.Type) (cty.Type, []Conversion) {
|
||||
return unify(types, true)
|
||||
}
|
69
vendor/github.com/zclconf/go-cty/cty/convert/sort_types.go
generated
vendored
Normal file
69
vendor/github.com/zclconf/go-cty/cty/convert/sort_types.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// sortTypes produces an ordering of the given types that serves as a
|
||||
// preference order for the result of unification of the given types.
|
||||
// The return value is a slice of indices into the given slice, and will
|
||||
// thus always be the same length as the given slice.
|
||||
//
|
||||
// The goal is that the most general of the given types will appear first
|
||||
// in the ordering. If there are uncomparable pairs of types in the list
|
||||
// then they will appear in an undefined order, and the unification pass
|
||||
// will presumably then fail.
|
||||
func sortTypes(tys []cty.Type) []int {
|
||||
l := len(tys)
|
||||
|
||||
// First we build a graph whose edges represent "more general than",
|
||||
// which we will then do a topological sort of.
|
||||
edges := make([][]int, l)
|
||||
for i := 0; i < (l - 1); i++ {
|
||||
for j := i + 1; j < l; j++ {
|
||||
cmp := compareTypes(tys[i], tys[j])
|
||||
switch {
|
||||
case cmp < 0:
|
||||
edges[i] = append(edges[i], j)
|
||||
case cmp > 0:
|
||||
edges[j] = append(edges[j], i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the in-degree of each node
|
||||
inDegree := make([]int, l)
|
||||
for _, outs := range edges {
|
||||
for _, j := range outs {
|
||||
inDegree[j]++
|
||||
}
|
||||
}
|
||||
|
||||
// The array backing our result will double as our queue for visiting
|
||||
// the nodes, with the queue slice moving along this array until it
|
||||
// is empty and positioned at the end of the array. Thus our visiting
|
||||
// order is also our result order.
|
||||
result := make([]int, l)
|
||||
queue := result[0:0]
|
||||
|
||||
// Initialize the queue with any item of in-degree 0, preserving
|
||||
// their relative order.
|
||||
for i, n := range inDegree {
|
||||
if n == 0 {
|
||||
queue = append(queue, i)
|
||||
}
|
||||
}
|
||||
|
||||
for len(queue) != 0 {
|
||||
i := queue[0]
|
||||
queue = queue[1:]
|
||||
for _, j := range edges[i] {
|
||||
inDegree[j]--
|
||||
if inDegree[j] == 0 {
|
||||
queue = append(queue, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
314
vendor/github.com/zclconf/go-cty/cty/convert/unify.go
generated
vendored
Normal file
314
vendor/github.com/zclconf/go-cty/cty/convert/unify.go
generated
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// The current unify implementation is somewhat inefficient, but we accept this
|
||||
// under the assumption that it will generally be used with small numbers of
|
||||
// types and with types of reasonable complexity. However, it does have a
|
||||
// "happy path" where all of the given types are equal.
|
||||
//
|
||||
// This function is likely to have poor performance in cases where any given
|
||||
// types are very complex (lots of deeply-nested structures) or if the list
|
||||
// of types itself is very large. In particular, it will walk the nested type
|
||||
// structure under the given types several times, especially when given a
|
||||
// list of types for which unification is not possible, since each permutation
|
||||
// will be tried to determine that result.
|
||||
func unify(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
|
||||
if len(types) == 0 {
|
||||
// Degenerate case
|
||||
return cty.NilType, nil
|
||||
}
|
||||
|
||||
// If all of the given types are of the same structural kind, we may be
|
||||
// able to construct a new type that they can all be unified to, even if
|
||||
// that is not one of the given types. We must try this before the general
|
||||
// behavior below because in unsafe mode we can convert an object type to
|
||||
// a subset of that type, which would be a much less useful conversion for
|
||||
// unification purposes.
|
||||
{
|
||||
objectCt := 0
|
||||
tupleCt := 0
|
||||
dynamicCt := 0
|
||||
for _, ty := range types {
|
||||
switch {
|
||||
case ty.IsObjectType():
|
||||
objectCt++
|
||||
case ty.IsTupleType():
|
||||
tupleCt++
|
||||
case ty == cty.DynamicPseudoType:
|
||||
dynamicCt++
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case objectCt > 0 && (objectCt+dynamicCt) == len(types):
|
||||
return unifyObjectTypes(types, unsafe, dynamicCt > 0)
|
||||
case tupleCt > 0 && (tupleCt+dynamicCt) == len(types):
|
||||
return unifyTupleTypes(types, unsafe, dynamicCt > 0)
|
||||
case objectCt > 0 && tupleCt > 0:
|
||||
// Can never unify object and tuple types since they have incompatible kinds
|
||||
return cty.NilType, nil
|
||||
}
|
||||
}
|
||||
|
||||
prefOrder := sortTypes(types)
|
||||
|
||||
// sortTypes gives us an order where earlier items are preferable as
|
||||
// our result type. We'll now walk through these and choose the first
|
||||
// one we encounter for which conversions exist for all source types.
|
||||
conversions := make([]Conversion, len(types))
|
||||
Preferences:
|
||||
for _, wantTypeIdx := range prefOrder {
|
||||
wantType := types[wantTypeIdx]
|
||||
for i, tryType := range types {
|
||||
if i == wantTypeIdx {
|
||||
// Don't need to convert our wanted type to itself
|
||||
conversions[i] = nil
|
||||
continue
|
||||
}
|
||||
|
||||
if tryType.Equals(wantType) {
|
||||
conversions[i] = nil
|
||||
continue
|
||||
}
|
||||
|
||||
if unsafe {
|
||||
conversions[i] = GetConversionUnsafe(tryType, wantType)
|
||||
} else {
|
||||
conversions[i] = GetConversion(tryType, wantType)
|
||||
}
|
||||
|
||||
if conversions[i] == nil {
|
||||
// wantType is not a suitable unification type, so we'll
|
||||
// try the next one in our preference order.
|
||||
continue Preferences
|
||||
}
|
||||
}
|
||||
|
||||
return wantType, conversions
|
||||
}
|
||||
|
||||
// If we fall out here, no unification is possible
|
||||
return cty.NilType, nil
|
||||
}
|
||||
|
||||
func unifyObjectTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) {
|
||||
// If we had any dynamic types in the input here then we can't predict
|
||||
// what path we'll take through here once these become known types, so
|
||||
// we'll conservatively produce DynamicVal for these.
|
||||
if hasDynamic {
|
||||
return unifyAllAsDynamic(types)
|
||||
}
|
||||
|
||||
// There are two different ways we can succeed here:
|
||||
// - If all of the given object types have the same set of attribute names
|
||||
// and the corresponding types are all unifyable, then we construct that
|
||||
// type.
|
||||
// - If the given object types have different attribute names or their
|
||||
// corresponding types are not unifyable, we'll instead try to unify
|
||||
// all of the attribute types together to produce a map type.
|
||||
//
|
||||
// Our unification behavior is intentionally stricter than our conversion
|
||||
// behavior for subset object types because user intent is different with
|
||||
// unification use-cases: it makes sense to allow {"foo":true} to convert
|
||||
// to emptyobjectval, but unifying an object with an attribute with the
|
||||
// empty object type should be an error because unifying to the empty
|
||||
// object type would be suprising and useless.
|
||||
|
||||
firstAttrs := types[0].AttributeTypes()
|
||||
for _, ty := range types[1:] {
|
||||
thisAttrs := ty.AttributeTypes()
|
||||
if len(thisAttrs) != len(firstAttrs) {
|
||||
// If number of attributes is different then there can be no
|
||||
// object type in common.
|
||||
return unifyObjectTypesToMap(types, unsafe)
|
||||
}
|
||||
for name := range thisAttrs {
|
||||
if _, ok := firstAttrs[name]; !ok {
|
||||
// If attribute names don't exactly match then there can be
|
||||
// no object type in common.
|
||||
return unifyObjectTypesToMap(types, unsafe)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here then we've proven that all of the given object types
|
||||
// have exactly the same set of attribute names, though the types may
|
||||
// differ.
|
||||
retAtys := make(map[string]cty.Type)
|
||||
atysAcross := make([]cty.Type, len(types))
|
||||
for name := range firstAttrs {
|
||||
for i, ty := range types {
|
||||
atysAcross[i] = ty.AttributeType(name)
|
||||
}
|
||||
retAtys[name], _ = unify(atysAcross, unsafe)
|
||||
if retAtys[name] == cty.NilType {
|
||||
// Cannot unify this attribute alone, which means that unification
|
||||
// of everything down to a map type can't be possible either.
|
||||
return cty.NilType, nil
|
||||
}
|
||||
}
|
||||
retTy := cty.Object(retAtys)
|
||||
|
||||
conversions := make([]Conversion, len(types))
|
||||
for i, ty := range types {
|
||||
if ty.Equals(retTy) {
|
||||
continue
|
||||
}
|
||||
if unsafe {
|
||||
conversions[i] = GetConversionUnsafe(ty, retTy)
|
||||
} else {
|
||||
conversions[i] = GetConversion(ty, retTy)
|
||||
}
|
||||
if conversions[i] == nil {
|
||||
// Shouldn't be reachable, since we were able to unify
|
||||
return unifyObjectTypesToMap(types, unsafe)
|
||||
}
|
||||
}
|
||||
|
||||
return retTy, conversions
|
||||
}
|
||||
|
||||
func unifyObjectTypesToMap(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
|
||||
// This is our fallback case for unifyObjectTypes, where we see if we can
|
||||
// construct a map type that can accept all of the attribute types.
|
||||
|
||||
var atys []cty.Type
|
||||
for _, ty := range types {
|
||||
for _, aty := range ty.AttributeTypes() {
|
||||
atys = append(atys, aty)
|
||||
}
|
||||
}
|
||||
|
||||
ety, _ := unify(atys, unsafe)
|
||||
if ety == cty.NilType {
|
||||
return cty.NilType, nil
|
||||
}
|
||||
|
||||
retTy := cty.Map(ety)
|
||||
conversions := make([]Conversion, len(types))
|
||||
for i, ty := range types {
|
||||
if ty.Equals(retTy) {
|
||||
continue
|
||||
}
|
||||
if unsafe {
|
||||
conversions[i] = GetConversionUnsafe(ty, retTy)
|
||||
} else {
|
||||
conversions[i] = GetConversion(ty, retTy)
|
||||
}
|
||||
if conversions[i] == nil {
|
||||
return cty.NilType, nil
|
||||
}
|
||||
}
|
||||
return retTy, conversions
|
||||
}
|
||||
|
||||
func unifyTupleTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) {
|
||||
// If we had any dynamic types in the input here then we can't predict
|
||||
// what path we'll take through here once these become known types, so
|
||||
// we'll conservatively produce DynamicVal for these.
|
||||
if hasDynamic {
|
||||
return unifyAllAsDynamic(types)
|
||||
}
|
||||
|
||||
// There are two different ways we can succeed here:
|
||||
// - If all of the given tuple types have the same sequence of element types
|
||||
// and the corresponding types are all unifyable, then we construct that
|
||||
// type.
|
||||
// - If the given tuple types have different element types or their
|
||||
// corresponding types are not unifyable, we'll instead try to unify
|
||||
// all of the elements types together to produce a list type.
|
||||
|
||||
firstEtys := types[0].TupleElementTypes()
|
||||
for _, ty := range types[1:] {
|
||||
thisEtys := ty.TupleElementTypes()
|
||||
if len(thisEtys) != len(firstEtys) {
|
||||
// If number of elements is different then there can be no
|
||||
// tuple type in common.
|
||||
return unifyTupleTypesToList(types, unsafe)
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here then we've proven that all of the given tuple types
|
||||
// have the same number of elements, though the types may differ.
|
||||
retEtys := make([]cty.Type, len(firstEtys))
|
||||
atysAcross := make([]cty.Type, len(types))
|
||||
for idx := range firstEtys {
|
||||
for tyI, ty := range types {
|
||||
atysAcross[tyI] = ty.TupleElementTypes()[idx]
|
||||
}
|
||||
retEtys[idx], _ = unify(atysAcross, unsafe)
|
||||
if retEtys[idx] == cty.NilType {
|
||||
// Cannot unify this element alone, which means that unification
|
||||
// of everything down to a map type can't be possible either.
|
||||
return cty.NilType, nil
|
||||
}
|
||||
}
|
||||
retTy := cty.Tuple(retEtys)
|
||||
|
||||
conversions := make([]Conversion, len(types))
|
||||
for i, ty := range types {
|
||||
if ty.Equals(retTy) {
|
||||
continue
|
||||
}
|
||||
if unsafe {
|
||||
conversions[i] = GetConversionUnsafe(ty, retTy)
|
||||
} else {
|
||||
conversions[i] = GetConversion(ty, retTy)
|
||||
}
|
||||
if conversions[i] == nil {
|
||||
// Shouldn't be reachable, since we were able to unify
|
||||
return unifyTupleTypesToList(types, unsafe)
|
||||
}
|
||||
}
|
||||
|
||||
return retTy, conversions
|
||||
}
|
||||
|
||||
func unifyTupleTypesToList(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
|
||||
// This is our fallback case for unifyTupleTypes, where we see if we can
|
||||
// construct a list type that can accept all of the element types.
|
||||
|
||||
var etys []cty.Type
|
||||
for _, ty := range types {
|
||||
for _, ety := range ty.TupleElementTypes() {
|
||||
etys = append(etys, ety)
|
||||
}
|
||||
}
|
||||
|
||||
ety, _ := unify(etys, unsafe)
|
||||
if ety == cty.NilType {
|
||||
return cty.NilType, nil
|
||||
}
|
||||
|
||||
retTy := cty.List(ety)
|
||||
conversions := make([]Conversion, len(types))
|
||||
for i, ty := range types {
|
||||
if ty.Equals(retTy) {
|
||||
continue
|
||||
}
|
||||
if unsafe {
|
||||
conversions[i] = GetConversionUnsafe(ty, retTy)
|
||||
} else {
|
||||
conversions[i] = GetConversion(ty, retTy)
|
||||
}
|
||||
if conversions[i] == nil {
|
||||
// Shouldn't be reachable, since we were able to unify
|
||||
return unifyObjectTypesToMap(types, unsafe)
|
||||
}
|
||||
}
|
||||
return retTy, conversions
|
||||
}
|
||||
|
||||
func unifyAllAsDynamic(types []cty.Type) (cty.Type, []Conversion) {
|
||||
conversions := make([]Conversion, len(types))
|
||||
for i := range conversions {
|
||||
conversions[i] = func(cty.Value) (cty.Value, error) {
|
||||
return cty.DynamicVal, nil
|
||||
}
|
||||
}
|
||||
return cty.DynamicPseudoType, conversions
|
||||
}
|
18
vendor/github.com/zclconf/go-cty/cty/doc.go
generated
vendored
Normal file
18
vendor/github.com/zclconf/go-cty/cty/doc.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Package cty (pronounced see-tie) provides some infrastructure for a type
|
||||
// system that might be useful for applications that need to represent
|
||||
// configuration values provided by the user whose types are not known
|
||||
// at compile time, particularly if the calling application also allows
|
||||
// such values to be used in expressions.
|
||||
//
|
||||
// The type system consists of primitive types Number, String and Bool, as
|
||||
// well as List and Map collection types and Object types that can have
|
||||
// arbitrarily-typed sets of attributes.
|
||||
//
|
||||
// A set of operations is defined on these types, which is accessible via
|
||||
// the wrapper struct Value, which annotates the raw, internal representation
|
||||
// of a value with its corresponding type.
|
||||
//
|
||||
// This package is oriented towards being a building block for configuration
|
||||
// languages used to bootstrap an application. It is not optimized for use
|
||||
// in tight loops where CPU time or memory pressure are a concern.
|
||||
package cty
|
194
vendor/github.com/zclconf/go-cty/cty/element_iterator.go
generated
vendored
Normal file
194
vendor/github.com/zclconf/go-cty/cty/element_iterator.go
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/zclconf/go-cty/cty/set"
|
||||
)
|
||||
|
||||
// ElementIterator is the interface type returned by Value.ElementIterator to
|
||||
// allow the caller to iterate over elements of a collection-typed value.
|
||||
//
|
||||
// Its usage pattern is as follows:
|
||||
//
|
||||
// it := val.ElementIterator()
|
||||
// for it.Next() {
|
||||
// key, val := it.Element()
|
||||
// // ...
|
||||
// }
|
||||
type ElementIterator interface {
|
||||
Next() bool
|
||||
Element() (key Value, value Value)
|
||||
}
|
||||
|
||||
func canElementIterator(val Value) bool {
|
||||
switch {
|
||||
case val.IsMarked():
|
||||
return false
|
||||
case val.ty.IsListType():
|
||||
return true
|
||||
case val.ty.IsMapType():
|
||||
return true
|
||||
case val.ty.IsSetType():
|
||||
return true
|
||||
case val.ty.IsTupleType():
|
||||
return true
|
||||
case val.ty.IsObjectType():
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func elementIterator(val Value) ElementIterator {
|
||||
val.assertUnmarked()
|
||||
switch {
|
||||
case val.ty.IsListType():
|
||||
return &listElementIterator{
|
||||
ety: val.ty.ElementType(),
|
||||
vals: val.v.([]interface{}),
|
||||
idx: -1,
|
||||
}
|
||||
case val.ty.IsMapType():
|
||||
// We iterate the keys in a predictable lexicographical order so
|
||||
// that results will always be stable given the same input map.
|
||||
rawMap := val.v.(map[string]interface{})
|
||||
keys := make([]string, 0, len(rawMap))
|
||||
for key := range rawMap {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
return &mapElementIterator{
|
||||
ety: val.ty.ElementType(),
|
||||
vals: rawMap,
|
||||
keys: keys,
|
||||
idx: -1,
|
||||
}
|
||||
case val.ty.IsSetType():
|
||||
rawSet := val.v.(set.Set)
|
||||
return &setElementIterator{
|
||||
ety: val.ty.ElementType(),
|
||||
setIt: rawSet.Iterator(),
|
||||
}
|
||||
case val.ty.IsTupleType():
|
||||
return &tupleElementIterator{
|
||||
etys: val.ty.TupleElementTypes(),
|
||||
vals: val.v.([]interface{}),
|
||||
idx: -1,
|
||||
}
|
||||
case val.ty.IsObjectType():
|
||||
// We iterate the keys in a predictable lexicographical order so
|
||||
// that results will always be stable given the same object type.
|
||||
atys := val.ty.AttributeTypes()
|
||||
keys := make([]string, 0, len(atys))
|
||||
for key := range atys {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
return &objectElementIterator{
|
||||
atys: atys,
|
||||
vals: val.v.(map[string]interface{}),
|
||||
attrNames: keys,
|
||||
idx: -1,
|
||||
}
|
||||
default:
|
||||
panic("attempt to iterate on non-collection, non-tuple type")
|
||||
}
|
||||
}
|
||||
|
||||
type listElementIterator struct {
|
||||
ety Type
|
||||
vals []interface{}
|
||||
idx int
|
||||
}
|
||||
|
||||
func (it *listElementIterator) Element() (Value, Value) {
|
||||
i := it.idx
|
||||
return NumberIntVal(int64(i)), Value{
|
||||
ty: it.ety,
|
||||
v: it.vals[i],
|
||||
}
|
||||
}
|
||||
|
||||
func (it *listElementIterator) Next() bool {
|
||||
it.idx++
|
||||
return it.idx < len(it.vals)
|
||||
}
|
||||
|
||||
type mapElementIterator struct {
|
||||
ety Type
|
||||
vals map[string]interface{}
|
||||
keys []string
|
||||
idx int
|
||||
}
|
||||
|
||||
func (it *mapElementIterator) Element() (Value, Value) {
|
||||
key := it.keys[it.idx]
|
||||
return StringVal(key), Value{
|
||||
ty: it.ety,
|
||||
v: it.vals[key],
|
||||
}
|
||||
}
|
||||
|
||||
func (it *mapElementIterator) Next() bool {
|
||||
it.idx++
|
||||
return it.idx < len(it.keys)
|
||||
}
|
||||
|
||||
type setElementIterator struct {
|
||||
ety Type
|
||||
setIt *set.Iterator
|
||||
}
|
||||
|
||||
func (it *setElementIterator) Element() (Value, Value) {
|
||||
val := Value{
|
||||
ty: it.ety,
|
||||
v: it.setIt.Value(),
|
||||
}
|
||||
return val, val
|
||||
}
|
||||
|
||||
func (it *setElementIterator) Next() bool {
|
||||
return it.setIt.Next()
|
||||
}
|
||||
|
||||
type tupleElementIterator struct {
|
||||
etys []Type
|
||||
vals []interface{}
|
||||
idx int
|
||||
}
|
||||
|
||||
func (it *tupleElementIterator) Element() (Value, Value) {
|
||||
i := it.idx
|
||||
return NumberIntVal(int64(i)), Value{
|
||||
ty: it.etys[i],
|
||||
v: it.vals[i],
|
||||
}
|
||||
}
|
||||
|
||||
func (it *tupleElementIterator) Next() bool {
|
||||
it.idx++
|
||||
return it.idx < len(it.vals)
|
||||
}
|
||||
|
||||
type objectElementIterator struct {
|
||||
atys map[string]Type
|
||||
vals map[string]interface{}
|
||||
attrNames []string
|
||||
idx int
|
||||
}
|
||||
|
||||
func (it *objectElementIterator) Element() (Value, Value) {
|
||||
key := it.attrNames[it.idx]
|
||||
return StringVal(key), Value{
|
||||
ty: it.atys[key],
|
||||
v: it.vals[key],
|
||||
}
|
||||
}
|
||||
|
||||
func (it *objectElementIterator) Next() bool {
|
||||
it.idx++
|
||||
return it.idx < len(it.attrNames)
|
||||
}
|
55
vendor/github.com/zclconf/go-cty/cty/error.go
generated
vendored
Normal file
55
vendor/github.com/zclconf/go-cty/cty/error.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// PathError is a specialization of error that represents where in a
|
||||
// potentially-deep data structure an error occured, using a Path.
|
||||
type PathError struct {
|
||||
error
|
||||
Path Path
|
||||
}
|
||||
|
||||
func errorf(path Path, f string, args ...interface{}) error {
|
||||
// We need to copy the Path because often our caller builds it by
|
||||
// continually mutating the same underlying buffer.
|
||||
sPath := make(Path, len(path))
|
||||
copy(sPath, path)
|
||||
return PathError{
|
||||
error: fmt.Errorf(f, args...),
|
||||
Path: sPath,
|
||||
}
|
||||
}
|
||||
|
||||
// NewErrorf creates a new PathError for the current path by passing the
|
||||
// given format and arguments to fmt.Errorf and then wrapping the result
|
||||
// similarly to NewError.
|
||||
func (p Path) NewErrorf(f string, args ...interface{}) error {
|
||||
return errorf(p, f, args...)
|
||||
}
|
||||
|
||||
// NewError creates a new PathError for the current path, wrapping the given
|
||||
// error.
|
||||
func (p Path) NewError(err error) error {
|
||||
// if we're being asked to wrap an existing PathError then our new
|
||||
// PathError will be the concatenation of the two paths, ensuring
|
||||
// that we still get a single flat PathError that's thus easier for
|
||||
// callers to deal with.
|
||||
perr, wrappingPath := err.(PathError)
|
||||
pathLen := len(p)
|
||||
if wrappingPath {
|
||||
pathLen = pathLen + len(perr.Path)
|
||||
}
|
||||
|
||||
sPath := make(Path, pathLen)
|
||||
copy(sPath, p)
|
||||
if wrappingPath {
|
||||
copy(sPath[len(p):], perr.Path)
|
||||
}
|
||||
|
||||
return PathError{
|
||||
error: err,
|
||||
Path: sPath,
|
||||
}
|
||||
}
|
70
vendor/github.com/zclconf/go-cty/cty/function/argument.go
generated
vendored
Normal file
70
vendor/github.com/zclconf/go-cty/cty/function/argument.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Parameter represents a parameter to a function.
|
||||
type Parameter struct {
|
||||
// Name is an optional name for the argument. This package ignores this
|
||||
// value, but callers may use it for documentation, etc.
|
||||
Name string
|
||||
|
||||
// A type that any argument for this parameter must conform to.
|
||||
// cty.DynamicPseudoType can be used, either at top-level or nested
|
||||
// in a parameterized type, to indicate that any type should be
|
||||
// permitted, to allow the definition of type-generic functions.
|
||||
Type cty.Type
|
||||
|
||||
// If AllowNull is set then null values may be passed into this
|
||||
// argument's slot in both the type-check function and the implementation
|
||||
// function. If not set, such values are rejected by the built-in
|
||||
// checking rules.
|
||||
AllowNull bool
|
||||
|
||||
// If AllowUnknown is set then unknown values may be passed into this
|
||||
// argument's slot in the implementation function. If not set, any
|
||||
// unknown values will cause the function to immediately return
|
||||
// an unkonwn value without calling the implementation function, thus
|
||||
// freeing the function implementer from dealing with this case.
|
||||
AllowUnknown bool
|
||||
|
||||
// If AllowDynamicType is set then DynamicVal may be passed into this
|
||||
// argument's slot in the implementation function. If not set, any
|
||||
// dynamic values will cause the function to immediately return
|
||||
// DynamicVal value without calling the implementation function, thus
|
||||
// freeing the function implementer from dealing with this case.
|
||||
//
|
||||
// Note that DynamicVal is also unknown, so in order to receive dynamic
|
||||
// *values* it is also necessary to set AllowUnknown.
|
||||
//
|
||||
// However, it is valid to set AllowDynamicType without AllowUnknown, in
|
||||
// which case a dynamic value may be passed to the type checking function
|
||||
// but will not make it to the *implementation* function. Instead, an
|
||||
// unknown value of the type returned by the type-check function will be
|
||||
// returned. This is suggested for functions that have a static return
|
||||
// type since it allows the return value to be typed even if the input
|
||||
// values are not, thus improving the type-check accuracy of derived
|
||||
// values.
|
||||
AllowDynamicType bool
|
||||
|
||||
// If AllowMarked is set then marked values may be passed into this
|
||||
// argument's slot in the implementation function. If not set, any
|
||||
// marked value will be unmarked before calling and then the markings
|
||||
// from that value will be applied automatically to the function result,
|
||||
// ensuring that the marks get propagated in a simplistic way even if
|
||||
// a function is unable to handle them.
|
||||
//
|
||||
// For any argument whose parameter has AllowMarked set, it's the
|
||||
// function implementation's responsibility to Unmark the given value
|
||||
// and propagate the marks appropriatedly to the result in order to
|
||||
// avoid losing the marks. Application-specific functions might use
|
||||
// special rules to selectively propagate particular marks.
|
||||
//
|
||||
// The automatic unmarking of values applies only to the main
|
||||
// implementation function. In an application that uses marked values,
|
||||
// the Type implementation for a function must always be prepared to accept
|
||||
// marked values, which is easy to achieve by consulting only the type
|
||||
// and ignoring the value itself.
|
||||
AllowMarked bool
|
||||
}
|
6
vendor/github.com/zclconf/go-cty/cty/function/doc.go
generated
vendored
Normal file
6
vendor/github.com/zclconf/go-cty/cty/function/doc.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
// Package function builds on the functionality of cty by modeling functions
|
||||
// that operate on cty Values.
|
||||
//
|
||||
// Functions are, at their core, Go anonymous functions. However, this package
|
||||
// wraps around them utility functions for parameter type checking, etc.
|
||||
package function
|
50
vendor/github.com/zclconf/go-cty/cty/function/error.go
generated
vendored
Normal file
50
vendor/github.com/zclconf/go-cty/cty/function/error.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
// ArgError represents an error with one of the arguments in a call. The
|
||||
// attribute Index represents the zero-based index of the argument in question.
|
||||
//
|
||||
// Its error *may* be a cty.PathError, in which case the error actually
|
||||
// pertains to a nested value within the data structure passed as the argument.
|
||||
type ArgError struct {
|
||||
error
|
||||
Index int
|
||||
}
|
||||
|
||||
func NewArgErrorf(i int, f string, args ...interface{}) error {
|
||||
return ArgError{
|
||||
error: fmt.Errorf(f, args...),
|
||||
Index: i,
|
||||
}
|
||||
}
|
||||
|
||||
func NewArgError(i int, err error) error {
|
||||
return ArgError{
|
||||
error: err,
|
||||
Index: i,
|
||||
}
|
||||
}
|
||||
|
||||
// PanicError indicates that a panic occurred while executing either a
|
||||
// function's type or implementation function. This is captured and wrapped
|
||||
// into a normal error so that callers (expected to be language runtimes)
|
||||
// are freed from having to deal with panics in buggy functions.
|
||||
type PanicError struct {
|
||||
Value interface{}
|
||||
Stack []byte
|
||||
}
|
||||
|
||||
func errorForPanic(val interface{}) error {
|
||||
return PanicError{
|
||||
Value: val,
|
||||
Stack: debug.Stack(),
|
||||
}
|
||||
}
|
||||
|
||||
func (e PanicError) Error() string {
|
||||
return fmt.Sprintf("panic in function implementation: %s\n%s", e.Value, e.Stack)
|
||||
}
|
342
vendor/github.com/zclconf/go-cty/cty/function/function.go
generated
vendored
Normal file
342
vendor/github.com/zclconf/go-cty/cty/function/function.go
generated
vendored
Normal file
@ -0,0 +1,342 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Function represents a function. This is the main type in this package.
|
||||
type Function struct {
|
||||
spec *Spec
|
||||
}
|
||||
|
||||
// Spec is the specification of a function, used to instantiate
|
||||
// a new Function.
|
||||
type Spec struct {
|
||||
// Params is a description of the positional parameters for the function.
|
||||
// The standard checking logic rejects any calls that do not provide
|
||||
// arguments conforming to this definition, freeing the function
|
||||
// implementer from dealing with such inconsistencies.
|
||||
Params []Parameter
|
||||
|
||||
// VarParam is an optional specification of additional "varargs" the
|
||||
// function accepts. If this is non-nil then callers may provide an
|
||||
// arbitrary number of additional arguments (after those matching with
|
||||
// the fixed parameters in Params) that conform to the given specification,
|
||||
// which will appear as additional values in the slices of values
|
||||
// provided to the type and implementation functions.
|
||||
VarParam *Parameter
|
||||
|
||||
// Type is the TypeFunc that decides the return type of the function
|
||||
// given its arguments, which may be Unknown. See the documentation
|
||||
// of TypeFunc for more information.
|
||||
//
|
||||
// Use StaticReturnType if the function's return type does not vary
|
||||
// depending on its arguments.
|
||||
Type TypeFunc
|
||||
|
||||
// Impl is the ImplFunc that implements the function's behavior.
|
||||
//
|
||||
// Functions are expected to behave as pure functions, and not create
|
||||
// any visible side-effects.
|
||||
//
|
||||
// If a TypeFunc is also provided, the value returned from Impl *must*
|
||||
// conform to the type it returns, or a call to the function will panic.
|
||||
Impl ImplFunc
|
||||
}
|
||||
|
||||
// New creates a new function with the given specification.
|
||||
//
|
||||
// After passing a Spec to this function, the caller must no longer read from
|
||||
// or mutate it.
|
||||
func New(spec *Spec) Function {
|
||||
f := Function{
|
||||
spec: spec,
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// TypeFunc is a callback type for determining the return type of a function
|
||||
// given its arguments.
|
||||
//
|
||||
// Any of the values passed to this function may be unknown, even if the
|
||||
// parameters are not configured to accept unknowns.
|
||||
//
|
||||
// If any of the given values are *not* unknown, the TypeFunc may use the
|
||||
// values for pre-validation and for choosing the return type. For example,
|
||||
// a hypothetical JSON-unmarshalling function could return
|
||||
// cty.DynamicPseudoType if the given JSON string is unknown, but return
|
||||
// a concrete type based on the JSON structure if the JSON string is already
|
||||
// known.
|
||||
type TypeFunc func(args []cty.Value) (cty.Type, error)
|
||||
|
||||
// ImplFunc is a callback type for the main implementation of a function.
|
||||
//
|
||||
// "args" are the values for the arguments, and this slice will always be at
|
||||
// least as long as the argument definition slice for the function.
|
||||
//
|
||||
// "retType" is the type returned from the Type callback, included as a
|
||||
// convenience to avoid the need to re-compute the return type for generic
|
||||
// functions whose return type is a function of the arguments.
|
||||
type ImplFunc func(args []cty.Value, retType cty.Type) (cty.Value, error)
|
||||
|
||||
// StaticReturnType returns a TypeFunc that always returns the given type.
|
||||
//
|
||||
// This is provided as a convenience for defining a function whose return
|
||||
// type does not depend on the argument types.
|
||||
func StaticReturnType(ty cty.Type) TypeFunc {
|
||||
return func([]cty.Value) (cty.Type, error) {
|
||||
return ty, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReturnType returns the return type of a function given a set of candidate
|
||||
// argument types, or returns an error if the given types are unacceptable.
|
||||
//
|
||||
// If the caller already knows values for at least some of the arguments
|
||||
// it can be better to call ReturnTypeForValues, since certain functions may
|
||||
// determine their return types from their values and return DynamicVal if
|
||||
// the values are unknown.
|
||||
func (f Function) ReturnType(argTypes []cty.Type) (cty.Type, error) {
|
||||
vals := make([]cty.Value, len(argTypes))
|
||||
for i, ty := range argTypes {
|
||||
vals[i] = cty.UnknownVal(ty)
|
||||
}
|
||||
return f.ReturnTypeForValues(vals)
|
||||
}
|
||||
|
||||
// ReturnTypeForValues is similar to ReturnType but can be used if the caller
|
||||
// already knows the values of some or all of the arguments, in which case
|
||||
// the function may be able to determine a more definite result if its
|
||||
// return type depends on the argument *values*.
|
||||
//
|
||||
// For any arguments whose values are not known, pass an Unknown value of
|
||||
// the appropriate type.
|
||||
func (f Function) ReturnTypeForValues(args []cty.Value) (ty cty.Type, err error) {
|
||||
var posArgs []cty.Value
|
||||
var varArgs []cty.Value
|
||||
|
||||
if f.spec.VarParam == nil {
|
||||
if len(args) != len(f.spec.Params) {
|
||||
return cty.Type{}, fmt.Errorf(
|
||||
"wrong number of arguments (%d required; %d given)",
|
||||
len(f.spec.Params), len(args),
|
||||
)
|
||||
}
|
||||
|
||||
posArgs = args
|
||||
varArgs = nil
|
||||
} else {
|
||||
if len(args) < len(f.spec.Params) {
|
||||
return cty.Type{}, fmt.Errorf(
|
||||
"wrong number of arguments (at least %d required; %d given)",
|
||||
len(f.spec.Params), len(args),
|
||||
)
|
||||
}
|
||||
|
||||
posArgs = args[0:len(f.spec.Params)]
|
||||
varArgs = args[len(f.spec.Params):]
|
||||
}
|
||||
|
||||
for i, spec := range f.spec.Params {
|
||||
val := posArgs[i]
|
||||
|
||||
if val.IsMarked() && !spec.AllowMarked {
|
||||
// During type checking we just unmark values and discard their
|
||||
// marks, under the assumption that during actual execution of
|
||||
// the function we'll do similarly and then re-apply the marks
|
||||
// afterwards. Note that this does mean that a function that
|
||||
// inspects values (rather than just types) in its Type
|
||||
// implementation can potentially fail to take into account marks,
|
||||
// unless it specifically opts in to seeing them.
|
||||
unmarked, _ := val.Unmark()
|
||||
newArgs := make([]cty.Value, len(args))
|
||||
copy(newArgs, args)
|
||||
newArgs[i] = unmarked
|
||||
args = newArgs
|
||||
}
|
||||
|
||||
if val.IsNull() && !spec.AllowNull {
|
||||
return cty.Type{}, NewArgErrorf(i, "argument must not be null")
|
||||
}
|
||||
|
||||
// AllowUnknown is ignored for type-checking, since we expect to be
|
||||
// able to type check with unknown values. We *do* still need to deal
|
||||
// with DynamicPseudoType here though, since the Type function might
|
||||
// not be ready to deal with that.
|
||||
|
||||
if val.Type() == cty.DynamicPseudoType {
|
||||
if !spec.AllowDynamicType {
|
||||
return cty.DynamicPseudoType, nil
|
||||
}
|
||||
} else if errs := val.Type().TestConformance(spec.Type); errs != nil {
|
||||
// For now we'll just return the first error in the set, since
|
||||
// we don't have a good way to return the whole list here.
|
||||
// Would be good to do something better at some point...
|
||||
return cty.Type{}, NewArgError(i, errs[0])
|
||||
}
|
||||
}
|
||||
|
||||
if varArgs != nil {
|
||||
spec := f.spec.VarParam
|
||||
for i, val := range varArgs {
|
||||
realI := i + len(posArgs)
|
||||
|
||||
if val.IsMarked() && !spec.AllowMarked {
|
||||
// See the similar block in the loop above for what's going on here.
|
||||
unmarked, _ := val.Unmark()
|
||||
newArgs := make([]cty.Value, len(args))
|
||||
copy(newArgs, args)
|
||||
newArgs[realI] = unmarked
|
||||
args = newArgs
|
||||
}
|
||||
|
||||
if val.IsNull() && !spec.AllowNull {
|
||||
return cty.Type{}, NewArgErrorf(realI, "argument must not be null")
|
||||
}
|
||||
|
||||
if val.Type() == cty.DynamicPseudoType {
|
||||
if !spec.AllowDynamicType {
|
||||
return cty.DynamicPseudoType, nil
|
||||
}
|
||||
} else if errs := val.Type().TestConformance(spec.Type); errs != nil {
|
||||
// For now we'll just return the first error in the set, since
|
||||
// we don't have a good way to return the whole list here.
|
||||
// Would be good to do something better at some point...
|
||||
return cty.Type{}, NewArgError(i, errs[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Intercept any panics from the function and return them as normal errors,
|
||||
// so a calling language runtime doesn't need to deal with panics.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ty = cty.NilType
|
||||
err = errorForPanic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
return f.spec.Type(args)
|
||||
}
|
||||
|
||||
// Call actually calls the function with the given arguments, which must
|
||||
// conform to the function's parameter specification or an error will be
|
||||
// returned.
|
||||
func (f Function) Call(args []cty.Value) (val cty.Value, err error) {
|
||||
expectedType, err := f.ReturnTypeForValues(args)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
||||
// Type checking already dealt with most situations relating to our
|
||||
// parameter specification, but we still need to deal with unknown
|
||||
// values and marked values.
|
||||
posArgs := args[:len(f.spec.Params)]
|
||||
varArgs := args[len(f.spec.Params):]
|
||||
var resultMarks []cty.ValueMarks
|
||||
|
||||
for i, spec := range f.spec.Params {
|
||||
val := posArgs[i]
|
||||
|
||||
if !val.IsKnown() && !spec.AllowUnknown {
|
||||
return cty.UnknownVal(expectedType), nil
|
||||
}
|
||||
|
||||
if val.IsMarked() && !spec.AllowMarked {
|
||||
unwrappedVal, marks := val.Unmark()
|
||||
// In order to avoid additional overhead on applications that
|
||||
// are not using marked values, we copy the given args only
|
||||
// if we encounter a marked value we need to unmark. However,
|
||||
// as a consequence we end up doing redundant copying if multiple
|
||||
// marked values need to be unwrapped. That seems okay because
|
||||
// argument lists are generally small.
|
||||
newArgs := make([]cty.Value, len(args))
|
||||
copy(newArgs, args)
|
||||
newArgs[i] = unwrappedVal
|
||||
resultMarks = append(resultMarks, marks)
|
||||
args = newArgs
|
||||
}
|
||||
}
|
||||
|
||||
if f.spec.VarParam != nil {
|
||||
spec := f.spec.VarParam
|
||||
for i, val := range varArgs {
|
||||
if !val.IsKnown() && !spec.AllowUnknown {
|
||||
return cty.UnknownVal(expectedType), nil
|
||||
}
|
||||
if val.IsMarked() && !spec.AllowMarked {
|
||||
unwrappedVal, marks := val.Unmark()
|
||||
newArgs := make([]cty.Value, len(args))
|
||||
copy(newArgs, args)
|
||||
newArgs[len(posArgs)+i] = unwrappedVal
|
||||
resultMarks = append(resultMarks, marks)
|
||||
args = newArgs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var retVal cty.Value
|
||||
{
|
||||
// Intercept any panics from the function and return them as normal errors,
|
||||
// so a calling language runtime doesn't need to deal with panics.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
val = cty.NilVal
|
||||
err = errorForPanic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
retVal, err = f.spec.Impl(args, expectedType)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
if len(resultMarks) > 0 {
|
||||
retVal = retVal.WithMarks(resultMarks...)
|
||||
}
|
||||
}
|
||||
|
||||
// Returned value must conform to what the Type function expected, to
|
||||
// protect callers from having to deal with inconsistencies.
|
||||
if errs := retVal.Type().TestConformance(expectedType); errs != nil {
|
||||
panic(fmt.Errorf(
|
||||
"returned value %#v does not conform to expected return type %#v: %s",
|
||||
retVal, expectedType, errs[0],
|
||||
))
|
||||
}
|
||||
|
||||
return retVal, nil
|
||||
}
|
||||
|
||||
// ProxyFunc the type returned by the method Function.Proxy.
|
||||
type ProxyFunc func(args ...cty.Value) (cty.Value, error)
|
||||
|
||||
// Proxy returns a function that can be called with cty.Value arguments
|
||||
// to run the function. This is provided as a convenience for when using
|
||||
// a function directly within Go code.
|
||||
func (f Function) Proxy() ProxyFunc {
|
||||
return func(args ...cty.Value) (cty.Value, error) {
|
||||
return f.Call(args)
|
||||
}
|
||||
}
|
||||
|
||||
// Params returns information about the function's fixed positional parameters.
|
||||
// This does not include information about any variadic arguments accepted;
|
||||
// for that, call VarParam.
|
||||
func (f Function) Params() []Parameter {
|
||||
new := make([]Parameter, len(f.spec.Params))
|
||||
copy(new, f.spec.Params)
|
||||
return new
|
||||
}
|
||||
|
||||
// VarParam returns information about the variadic arguments the function
|
||||
// expects, or nil if the function is not variadic.
|
||||
func (f Function) VarParam() *Parameter {
|
||||
if f.spec.VarParam == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := *f.spec.VarParam
|
||||
return &ret
|
||||
}
|
31
vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go
generated
vendored
Normal file
31
vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Unpredictable wraps a given function such that it retains the same arguments
|
||||
// and type checking behavior but will return an unknown value when called.
|
||||
//
|
||||
// It is recommended that most functions be "pure", which is to say that they
|
||||
// will always produce the same value given particular input. However,
|
||||
// sometimes it is necessary to offer functions whose behavior depends on
|
||||
// some external state, such as reading a file or determining the current time.
|
||||
// In such cases, an unpredictable wrapper might be used to stand in for
|
||||
// the function during some sort of prior "checking" phase in order to delay
|
||||
// the actual effect until later.
|
||||
//
|
||||
// While Unpredictable can support a function that isn't pure in its
|
||||
// implementation, it still expects a function to be pure in its type checking
|
||||
// behavior, except for the special case of returning cty.DynamicPseudoType
|
||||
// if it is not yet able to predict its return value based on current argument
|
||||
// information.
|
||||
func Unpredictable(f Function) Function {
|
||||
newSpec := *f.spec // shallow copy
|
||||
newSpec.Impl = unpredictableImpl
|
||||
return New(&newSpec)
|
||||
}
|
||||
|
||||
func unpredictableImpl(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
||||
return cty.UnknownVal(retType), nil
|
||||
}
|
204
vendor/github.com/zclconf/go-cty/cty/gob.go
generated
vendored
Normal file
204
vendor/github.com/zclconf/go-cty/cty/gob.go
generated
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/zclconf/go-cty/cty/set"
|
||||
)
|
||||
|
||||
// GobEncode is an implementation of the gob.GobEncoder interface, which
|
||||
// allows Values to be included in structures encoded with encoding/gob.
|
||||
//
|
||||
// Currently it is not possible to represent values of capsule types in gob,
|
||||
// because the types themselves cannot be represented.
|
||||
func (val Value) GobEncode() ([]byte, error) {
|
||||
if val.IsMarked() {
|
||||
return nil, errors.New("value is marked")
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
enc := gob.NewEncoder(buf)
|
||||
|
||||
gv := gobValue{
|
||||
Version: 0,
|
||||
Ty: val.ty,
|
||||
V: val.v,
|
||||
}
|
||||
|
||||
err := enc.Encode(gv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error encoding cty.Value: %s", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// GobDecode is an implementation of the gob.GobDecoder interface, which
|
||||
// inverts the operation performed by GobEncode. See the documentation of
|
||||
// GobEncode for considerations when using cty.Value instances with gob.
|
||||
func (val *Value) GobDecode(buf []byte) error {
|
||||
r := bytes.NewReader(buf)
|
||||
dec := gob.NewDecoder(r)
|
||||
|
||||
var gv gobValue
|
||||
err := dec.Decode(&gv)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error decoding cty.Value: %s", err)
|
||||
}
|
||||
if gv.Version != 0 {
|
||||
return fmt.Errorf("unsupported cty.Value encoding version %d; only 0 is supported", gv.Version)
|
||||
}
|
||||
|
||||
// Because big.Float.GobEncode is implemented with a pointer reciever,
|
||||
// gob encoding of an interface{} containing a *big.Float value does not
|
||||
// round-trip correctly, emerging instead as a non-pointer big.Float.
|
||||
// The rest of cty expects all number values to be represented by
|
||||
// *big.Float, so we'll fix that up here.
|
||||
gv.V = gobDecodeFixNumberPtr(gv.V, gv.Ty)
|
||||
|
||||
val.ty = gv.Ty
|
||||
val.v = gv.V
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GobEncode is an implementation of the gob.GobEncoder interface, which
|
||||
// allows Types to be included in structures encoded with encoding/gob.
|
||||
//
|
||||
// Currently it is not possible to represent capsule types in gob.
|
||||
func (t Type) GobEncode() ([]byte, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := gob.NewEncoder(buf)
|
||||
|
||||
gt := gobType{
|
||||
Version: 0,
|
||||
Impl: t.typeImpl,
|
||||
}
|
||||
|
||||
err := enc.Encode(gt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error encoding cty.Type: %s", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// GobDecode is an implementatino of the gob.GobDecoder interface, which
|
||||
// reverses the encoding performed by GobEncode to allow types to be recovered
|
||||
// from gob buffers.
|
||||
func (t *Type) GobDecode(buf []byte) error {
|
||||
r := bytes.NewReader(buf)
|
||||
dec := gob.NewDecoder(r)
|
||||
|
||||
var gt gobType
|
||||
err := dec.Decode(>)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error decoding cty.Type: %s", err)
|
||||
}
|
||||
if gt.Version != 0 {
|
||||
return fmt.Errorf("unsupported cty.Type encoding version %d; only 0 is supported", gt.Version)
|
||||
}
|
||||
|
||||
t.typeImpl = gt.Impl
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Capsule types cannot currently be gob-encoded, because they rely on pointer
|
||||
// equality and we have no way to recover the original pointer on decode.
|
||||
func (t *capsuleType) GobEncode() ([]byte, error) {
|
||||
return nil, fmt.Errorf("cannot gob-encode capsule type %q", t.FriendlyName(friendlyTypeName))
|
||||
}
|
||||
|
||||
func (t *capsuleType) GobDecode() ([]byte, error) {
|
||||
return nil, fmt.Errorf("cannot gob-decode capsule type %q", t.FriendlyName(friendlyTypeName))
|
||||
}
|
||||
|
||||
type gobValue struct {
|
||||
Version int
|
||||
Ty Type
|
||||
V interface{}
|
||||
}
|
||||
|
||||
type gobType struct {
|
||||
Version int
|
||||
Impl typeImpl
|
||||
}
|
||||
|
||||
type gobCapsuleTypeImpl struct {
|
||||
}
|
||||
|
||||
// goDecodeFixNumberPtr fixes an unfortunate quirk of round-tripping cty.Number
|
||||
// values through gob: the big.Float.GobEncode method is implemented on a
|
||||
// pointer receiver, and so it loses the "pointer-ness" of the value on
|
||||
// encode, causing the values to emerge the other end as big.Float rather than
|
||||
// *big.Float as we expect elsewhere in cty.
|
||||
//
|
||||
// The implementation of gobDecodeFixNumberPtr mutates the given raw value
|
||||
// during its work, and may either return the same value mutated or a new
|
||||
// value. Callers must no longer use whatever value they pass as "raw" after
|
||||
// this function is called.
|
||||
func gobDecodeFixNumberPtr(raw interface{}, ty Type) interface{} {
|
||||
// Unfortunately we need to work recursively here because number values
|
||||
// might be embedded in structural or collection type values.
|
||||
|
||||
switch {
|
||||
case ty.Equals(Number):
|
||||
if bf, ok := raw.(big.Float); ok {
|
||||
return &bf // wrap in pointer
|
||||
}
|
||||
case ty.IsMapType() && ty.ElementType().Equals(Number):
|
||||
if m, ok := raw.(map[string]interface{}); ok {
|
||||
for k, v := range m {
|
||||
m[k] = gobDecodeFixNumberPtr(v, ty.ElementType())
|
||||
}
|
||||
}
|
||||
case ty.IsListType() && ty.ElementType().Equals(Number):
|
||||
if s, ok := raw.([]interface{}); ok {
|
||||
for i, v := range s {
|
||||
s[i] = gobDecodeFixNumberPtr(v, ty.ElementType())
|
||||
}
|
||||
}
|
||||
case ty.IsSetType() && ty.ElementType().Equals(Number):
|
||||
if s, ok := raw.(set.Set); ok {
|
||||
newS := set.NewSet(s.Rules())
|
||||
for it := s.Iterator(); it.Next(); {
|
||||
newV := gobDecodeFixNumberPtr(it.Value(), ty.ElementType())
|
||||
newS.Add(newV)
|
||||
}
|
||||
return newS
|
||||
}
|
||||
case ty.IsObjectType():
|
||||
if m, ok := raw.(map[string]interface{}); ok {
|
||||
for k, v := range m {
|
||||
aty := ty.AttributeType(k)
|
||||
m[k] = gobDecodeFixNumberPtr(v, aty)
|
||||
}
|
||||
}
|
||||
case ty.IsTupleType():
|
||||
if s, ok := raw.([]interface{}); ok {
|
||||
for i, v := range s {
|
||||
ety := ty.TupleElementType(i)
|
||||
s[i] = gobDecodeFixNumberPtr(v, ety)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return raw
|
||||
}
|
||||
|
||||
// gobDecodeFixNumberPtrVal is a helper wrapper around gobDecodeFixNumberPtr
|
||||
// that works with already-constructed values. This is primarily for testing,
|
||||
// to fix up intentionally-invalid number values for the parts of the test
|
||||
// code that need them to be valid, such as calling GoString on them.
|
||||
func gobDecodeFixNumberPtrVal(v Value) Value {
|
||||
raw := gobDecodeFixNumberPtr(v.v, v.ty)
|
||||
return Value{
|
||||
v: raw,
|
||||
ty: v.ty,
|
||||
}
|
||||
}
|
99
vendor/github.com/zclconf/go-cty/cty/helper.go
generated
vendored
Normal file
99
vendor/github.com/zclconf/go-cty/cty/helper.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// anyUnknown is a helper to easily check if a set of values contains any
|
||||
// unknowns, for operations that short-circuit to return unknown in that case.
|
||||
func anyUnknown(values ...Value) bool {
|
||||
for _, val := range values {
|
||||
if val.v == unknown {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// typeCheck tests whether all of the given values belong to the given type.
|
||||
// If the given types are a mixture of the given type and the dynamic
|
||||
// pseudo-type then a short-circuit dynamic value is returned. If the given
|
||||
// values are all of the correct type but at least one is unknown then
|
||||
// a short-circuit unknown value is returned. If any other types appear then
|
||||
// an error is returned. Otherwise (finally!) the result is nil, nil.
|
||||
func typeCheck(required Type, ret Type, values ...Value) (shortCircuit *Value, err error) {
|
||||
hasDynamic := false
|
||||
hasUnknown := false
|
||||
|
||||
for i, val := range values {
|
||||
if val.ty == DynamicPseudoType {
|
||||
hasDynamic = true
|
||||
continue
|
||||
}
|
||||
|
||||
if !val.Type().Equals(required) {
|
||||
return nil, fmt.Errorf(
|
||||
"type mismatch: want %s but value %d is %s",
|
||||
required.FriendlyName(),
|
||||
i, val.ty.FriendlyName(),
|
||||
)
|
||||
}
|
||||
|
||||
if val.v == unknown {
|
||||
hasUnknown = true
|
||||
}
|
||||
}
|
||||
|
||||
if hasDynamic {
|
||||
return &DynamicVal, nil
|
||||
}
|
||||
|
||||
if hasUnknown {
|
||||
ret := UnknownVal(ret)
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// mustTypeCheck is a wrapper around typeCheck that immediately panics if
|
||||
// any error is returned.
|
||||
func mustTypeCheck(required Type, ret Type, values ...Value) *Value {
|
||||
shortCircuit, err := typeCheck(required, ret, values...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return shortCircuit
|
||||
}
|
||||
|
||||
// shortCircuitForceType takes the return value from mustTypeCheck and
|
||||
// replaces it with an unknown of the given type if the original value was
|
||||
// DynamicVal.
|
||||
//
|
||||
// This is useful for operations that are specified to always return a
|
||||
// particular type, since then a dynamic result can safely be "upgrade" to
|
||||
// a strongly-typed unknown, which then allows subsequent operations to
|
||||
// be actually type-checked.
|
||||
//
|
||||
// It is safe to use this only if the operation in question is defined as
|
||||
// returning either a value of the given type or panicking, since we know
|
||||
// then that subsequent operations won't run if the operation panics.
|
||||
//
|
||||
// If the given short-circuit value is *not* DynamicVal then it must be
|
||||
// of the given type, or this function will panic.
|
||||
func forceShortCircuitType(shortCircuit *Value, ty Type) *Value {
|
||||
if shortCircuit == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if shortCircuit.ty == DynamicPseudoType {
|
||||
ret := UnknownVal(ty)
|
||||
return &ret
|
||||
}
|
||||
|
||||
if !shortCircuit.ty.Equals(ty) {
|
||||
panic("forceShortCircuitType got value of wrong type")
|
||||
}
|
||||
|
||||
return shortCircuit
|
||||
}
|
176
vendor/github.com/zclconf/go-cty/cty/json.go
generated
vendored
Normal file
176
vendor/github.com/zclconf/go-cty/cty/json.go
generated
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// MarshalJSON is an implementation of json.Marshaler that allows Type
|
||||
// instances to be serialized as JSON.
|
||||
//
|
||||
// All standard types can be serialized, but capsule types cannot since there
|
||||
// is no way to automatically recover the original pointer and capsule types
|
||||
// compare by equality.
|
||||
func (t Type) MarshalJSON() ([]byte, error) {
|
||||
switch impl := t.typeImpl.(type) {
|
||||
case primitiveType:
|
||||
switch impl.Kind {
|
||||
case primitiveTypeBool:
|
||||
return []byte{'"', 'b', 'o', 'o', 'l', '"'}, nil
|
||||
case primitiveTypeNumber:
|
||||
return []byte{'"', 'n', 'u', 'm', 'b', 'e', 'r', '"'}, nil
|
||||
case primitiveTypeString:
|
||||
return []byte{'"', 's', 't', 'r', 'i', 'n', 'g', '"'}, nil
|
||||
default:
|
||||
panic("unknown primitive type kind")
|
||||
}
|
||||
case typeList, typeMap, typeSet:
|
||||
buf := &bytes.Buffer{}
|
||||
etyJSON, err := t.ElementType().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf.WriteRune('[')
|
||||
switch impl.(type) {
|
||||
case typeList:
|
||||
buf.WriteString(`"list"`)
|
||||
case typeMap:
|
||||
buf.WriteString(`"map"`)
|
||||
case typeSet:
|
||||
buf.WriteString(`"set"`)
|
||||
}
|
||||
buf.WriteRune(',')
|
||||
buf.Write(etyJSON)
|
||||
buf.WriteRune(']')
|
||||
return buf.Bytes(), nil
|
||||
case typeObject:
|
||||
buf := &bytes.Buffer{}
|
||||
atysJSON, err := json.Marshal(t.AttributeTypes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf.WriteString(`["object",`)
|
||||
buf.Write(atysJSON)
|
||||
buf.WriteRune(']')
|
||||
return buf.Bytes(), nil
|
||||
case typeTuple:
|
||||
buf := &bytes.Buffer{}
|
||||
etysJSON, err := json.Marshal(t.TupleElementTypes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf.WriteString(`["tuple",`)
|
||||
buf.Write(etysJSON)
|
||||
buf.WriteRune(']')
|
||||
return buf.Bytes(), nil
|
||||
case pseudoTypeDynamic:
|
||||
return []byte{'"', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '"'}, nil
|
||||
case *capsuleType:
|
||||
return nil, fmt.Errorf("type not allowed: %s", t.FriendlyName())
|
||||
default:
|
||||
// should never happen
|
||||
panic("unknown type implementation")
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalJSON is the opposite of MarshalJSON. See the documentation of
|
||||
// MarshalJSON for information on the limitations of JSON serialization of
|
||||
// types.
|
||||
func (t *Type) UnmarshalJSON(buf []byte) error {
|
||||
r := bytes.NewReader(buf)
|
||||
dec := json.NewDecoder(r)
|
||||
|
||||
tok, err := dec.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch v := tok.(type) {
|
||||
case string:
|
||||
switch v {
|
||||
case "bool":
|
||||
*t = Bool
|
||||
case "number":
|
||||
*t = Number
|
||||
case "string":
|
||||
*t = String
|
||||
case "dynamic":
|
||||
*t = DynamicPseudoType
|
||||
default:
|
||||
return fmt.Errorf("invalid primitive type name %q", v)
|
||||
}
|
||||
|
||||
if dec.More() {
|
||||
return fmt.Errorf("extraneous data after type description")
|
||||
}
|
||||
return nil
|
||||
case json.Delim:
|
||||
if rune(v) != '[' {
|
||||
return fmt.Errorf("invalid complex type description")
|
||||
}
|
||||
|
||||
tok, err = dec.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kind, ok := tok.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid complex type kind name")
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case "list":
|
||||
var ety Type
|
||||
err = dec.Decode(&ety)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = List(ety)
|
||||
case "map":
|
||||
var ety Type
|
||||
err = dec.Decode(&ety)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = Map(ety)
|
||||
case "set":
|
||||
var ety Type
|
||||
err = dec.Decode(&ety)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = Set(ety)
|
||||
case "object":
|
||||
var atys map[string]Type
|
||||
err = dec.Decode(&atys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = Object(atys)
|
||||
case "tuple":
|
||||
var etys []Type
|
||||
err = dec.Decode(&etys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = Tuple(etys)
|
||||
default:
|
||||
return fmt.Errorf("invalid complex type kind name")
|
||||
}
|
||||
|
||||
tok, err = dec.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if delim, ok := tok.(json.Delim); !ok || rune(delim) != ']' || dec.More() {
|
||||
return fmt.Errorf("unexpected extra data in type description")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
default:
|
||||
return fmt.Errorf("invalid type description")
|
||||
}
|
||||
}
|
74
vendor/github.com/zclconf/go-cty/cty/list_type.go
generated
vendored
Normal file
74
vendor/github.com/zclconf/go-cty/cty/list_type.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// TypeList instances represent specific list types. Each distinct ElementType
|
||||
// creates a distinct, non-equal list type.
|
||||
type typeList struct {
|
||||
typeImplSigil
|
||||
ElementTypeT Type
|
||||
}
|
||||
|
||||
// List creates a map type with the given element Type.
|
||||
//
|
||||
// List types are CollectionType implementations.
|
||||
func List(elem Type) Type {
|
||||
return Type{
|
||||
typeList{
|
||||
ElementTypeT: elem,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Equals returns true if the other Type is a list whose element type is
|
||||
// equal to that of the receiver.
|
||||
func (t typeList) Equals(other Type) bool {
|
||||
ot, isList := other.typeImpl.(typeList)
|
||||
if !isList {
|
||||
return false
|
||||
}
|
||||
|
||||
return t.ElementTypeT.Equals(ot.ElementTypeT)
|
||||
}
|
||||
|
||||
func (t typeList) FriendlyName(mode friendlyTypeNameMode) string {
|
||||
elemName := t.ElementTypeT.friendlyNameMode(mode)
|
||||
if mode == friendlyTypeConstraintName {
|
||||
if t.ElementTypeT == DynamicPseudoType {
|
||||
elemName = "any single type"
|
||||
}
|
||||
}
|
||||
return "list of " + elemName
|
||||
}
|
||||
|
||||
func (t typeList) ElementType() Type {
|
||||
return t.ElementTypeT
|
||||
}
|
||||
|
||||
func (t typeList) GoString() string {
|
||||
return fmt.Sprintf("cty.List(%#v)", t.ElementTypeT)
|
||||
}
|
||||
|
||||
// IsListType returns true if the given type is a list type, regardless of its
|
||||
// element type.
|
||||
func (t Type) IsListType() bool {
|
||||
_, ok := t.typeImpl.(typeList)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ListElementType is a convenience method that checks if the given type is
|
||||
// a list type, returning a pointer to its element type if so and nil
|
||||
// otherwise. This is intended to allow convenient conditional branches,
|
||||
// like so:
|
||||
//
|
||||
// if et := t.ListElementType(); et != nil {
|
||||
// // Do something with *et
|
||||
// }
|
||||
func (t Type) ListElementType() *Type {
|
||||
if lt, ok := t.typeImpl.(typeList); ok {
|
||||
return <.ElementTypeT
|
||||
}
|
||||
return nil
|
||||
}
|
74
vendor/github.com/zclconf/go-cty/cty/map_type.go
generated
vendored
Normal file
74
vendor/github.com/zclconf/go-cty/cty/map_type.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// TypeList instances represent specific list types. Each distinct ElementType
|
||||
// creates a distinct, non-equal list type.
|
||||
type typeMap struct {
|
||||
typeImplSigil
|
||||
ElementTypeT Type
|
||||
}
|
||||
|
||||
// Map creates a map type with the given element Type.
|
||||
//
|
||||
// Map types are CollectionType implementations.
|
||||
func Map(elem Type) Type {
|
||||
return Type{
|
||||
typeMap{
|
||||
ElementTypeT: elem,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Equals returns true if the other Type is a map whose element type is
|
||||
// equal to that of the receiver.
|
||||
func (t typeMap) Equals(other Type) bool {
|
||||
ot, isMap := other.typeImpl.(typeMap)
|
||||
if !isMap {
|
||||
return false
|
||||
}
|
||||
|
||||
return t.ElementTypeT.Equals(ot.ElementTypeT)
|
||||
}
|
||||
|
||||
func (t typeMap) FriendlyName(mode friendlyTypeNameMode) string {
|
||||
elemName := t.ElementTypeT.friendlyNameMode(mode)
|
||||
if mode == friendlyTypeConstraintName {
|
||||
if t.ElementTypeT == DynamicPseudoType {
|
||||
elemName = "any single type"
|
||||
}
|
||||
}
|
||||
return "map of " + elemName
|
||||
}
|
||||
|
||||
func (t typeMap) ElementType() Type {
|
||||
return t.ElementTypeT
|
||||
}
|
||||
|
||||
func (t typeMap) GoString() string {
|
||||
return fmt.Sprintf("cty.Map(%#v)", t.ElementTypeT)
|
||||
}
|
||||
|
||||
// IsMapType returns true if the given type is a list type, regardless of its
|
||||
// element type.
|
||||
func (t Type) IsMapType() bool {
|
||||
_, ok := t.typeImpl.(typeMap)
|
||||
return ok
|
||||
}
|
||||
|
||||
// MapElementType is a convenience method that checks if the given type is
|
||||
// a map type, returning a pointer to its element type if so and nil
|
||||
// otherwise. This is intended to allow convenient conditional branches,
|
||||
// like so:
|
||||
//
|
||||
// if et := t.MapElementType(); et != nil {
|
||||
// // Do something with *et
|
||||
// }
|
||||
func (t Type) MapElementType() *Type {
|
||||
if lt, ok := t.typeImpl.(typeMap); ok {
|
||||
return <.ElementTypeT
|
||||
}
|
||||
return nil
|
||||
}
|
296
vendor/github.com/zclconf/go-cty/cty/marks.go
generated
vendored
Normal file
296
vendor/github.com/zclconf/go-cty/cty/marks.go
generated
vendored
Normal file
@ -0,0 +1,296 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// marker is an internal wrapper type used to add special "marks" to values.
|
||||
//
|
||||
// A "mark" is an annotation that can be used to represent additional
|
||||
// characteristics of values that propagate through operation methods to
|
||||
// result values. However, a marked value cannot be used with integration
|
||||
// methods normally associated with its type, in order to ensure that
|
||||
// calling applications don't inadvertently drop marks as they round-trip
|
||||
// values out of cty and back in again.
|
||||
//
|
||||
// Marked values are created only explicitly by the calling application, so
|
||||
// an application that never marks a value does not need to worry about
|
||||
// encountering marked values.
|
||||
type marker struct {
|
||||
realV interface{}
|
||||
marks ValueMarks
|
||||
}
|
||||
|
||||
// ValueMarks is a map, representing a set, of "mark" values associated with
|
||||
// a Value. See Value.Mark for more information on the usage of mark values.
|
||||
type ValueMarks map[interface{}]struct{}
|
||||
|
||||
// NewValueMarks constructs a new ValueMarks set with the given mark values.
|
||||
func NewValueMarks(marks ...interface{}) ValueMarks {
|
||||
if len(marks) == 0 {
|
||||
return nil
|
||||
}
|
||||
ret := make(ValueMarks, len(marks))
|
||||
for _, v := range marks {
|
||||
ret[v] = struct{}{}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Equal returns true if the receiver and the given ValueMarks both contain
|
||||
// the same marks.
|
||||
func (m ValueMarks) Equal(o ValueMarks) bool {
|
||||
if len(m) != len(o) {
|
||||
return false
|
||||
}
|
||||
for v := range m {
|
||||
if _, ok := o[v]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (m ValueMarks) GoString() string {
|
||||
var s strings.Builder
|
||||
s.WriteString("cty.NewValueMarks(")
|
||||
i := 0
|
||||
for mv := range m {
|
||||
if i != 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
s.WriteString(fmt.Sprintf("%#v", mv))
|
||||
i++
|
||||
}
|
||||
s.WriteString(")")
|
||||
return s.String()
|
||||
}
|
||||
|
||||
// IsMarked returns true if and only if the receiving value carries at least
|
||||
// one mark. A marked value cannot be used directly with integration methods
|
||||
// without explicitly unmarking it (and retrieving the markings) first.
|
||||
func (val Value) IsMarked() bool {
|
||||
_, ok := val.v.(marker)
|
||||
return ok
|
||||
}
|
||||
|
||||
// HasMark returns true if and only if the receiving value has the given mark.
|
||||
func (val Value) HasMark(mark interface{}) bool {
|
||||
if mr, ok := val.v.(marker); ok {
|
||||
_, ok := mr.marks[mark]
|
||||
return ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ContainsMarked returns true if the receiving value or any value within it
|
||||
// is marked.
|
||||
//
|
||||
// This operation is relatively expensive. If you only need a shallow result,
|
||||
// use IsMarked instead.
|
||||
func (val Value) ContainsMarked() bool {
|
||||
ret := false
|
||||
Walk(val, func(_ Path, v Value) (bool, error) {
|
||||
if v.IsMarked() {
|
||||
ret = true
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
func (val Value) assertUnmarked() {
|
||||
if val.IsMarked() {
|
||||
panic("value is marked, so must be unmarked first")
|
||||
}
|
||||
}
|
||||
|
||||
// Marks returns a map (representing a set) of all of the mark values
|
||||
// associated with the receiving value, without changing the marks. Returns nil
|
||||
// if the value is not marked at all.
|
||||
func (val Value) Marks() ValueMarks {
|
||||
if mr, ok := val.v.(marker); ok {
|
||||
// copy so that the caller can't mutate our internals
|
||||
ret := make(ValueMarks, len(mr.marks))
|
||||
for k, v := range mr.marks {
|
||||
ret[k] = v
|
||||
}
|
||||
return ret
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasSameMarks returns true if an only if the receiver and the given other
|
||||
// value have identical marks.
|
||||
func (val Value) HasSameMarks(other Value) bool {
|
||||
vm, vmOK := val.v.(marker)
|
||||
om, omOK := other.v.(marker)
|
||||
if vmOK != omOK {
|
||||
return false
|
||||
}
|
||||
if vmOK {
|
||||
return vm.marks.Equal(om.marks)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Mark returns a new value that as the same type and underlying value as
|
||||
// the receiver but that also carries the given value as a "mark".
|
||||
//
|
||||
// Marks are used to carry additional application-specific characteristics
|
||||
// associated with values. A marked value can be used with operation methods,
|
||||
// in which case the marks are propagated to the operation results. A marked
|
||||
// value _cannot_ be used with integration methods, so callers of those
|
||||
// must derive an unmarked value using Unmark (and thus explicitly handle
|
||||
// the markings) before calling the integration methods.
|
||||
//
|
||||
// The mark value can be any value that would be valid to use as a map key.
|
||||
// The mark value should be of a named type in order to use the type itself
|
||||
// as a namespace for markings. That type can be unexported if desired, in
|
||||
// order to ensure that the mark can only be handled through the defining
|
||||
// package's own functions.
|
||||
//
|
||||
// An application that never calls this method does not need to worry about
|
||||
// handling marked values.
|
||||
func (val Value) Mark(mark interface{}) Value {
|
||||
var newMarker marker
|
||||
newMarker.realV = val.v
|
||||
if mr, ok := val.v.(marker); ok {
|
||||
// It's already a marker, so we'll retain existing marks.
|
||||
newMarker.marks = make(ValueMarks, len(mr.marks)+1)
|
||||
for k, v := range mr.marks {
|
||||
newMarker.marks[k] = v
|
||||
}
|
||||
} else {
|
||||
// It's not a marker yet, so we're creating the first mark.
|
||||
newMarker.marks = make(ValueMarks, 1)
|
||||
}
|
||||
newMarker.marks[mark] = struct{}{}
|
||||
return Value{
|
||||
ty: val.ty,
|
||||
v: newMarker,
|
||||
}
|
||||
}
|
||||
|
||||
// Unmark separates the marks of the receiving value from the value itself,
|
||||
// removing a new unmarked value and a map (representing a set) of the marks.
|
||||
//
|
||||
// If the receiver isn't marked, Unmark returns it verbatim along with a nil
|
||||
// map of marks.
|
||||
func (val Value) Unmark() (Value, ValueMarks) {
|
||||
if !val.IsMarked() {
|
||||
return val, nil
|
||||
}
|
||||
mr := val.v.(marker)
|
||||
marks := val.Marks() // copy so that the caller can't mutate our internals
|
||||
return Value{
|
||||
ty: val.ty,
|
||||
v: mr.realV,
|
||||
}, marks
|
||||
}
|
||||
|
||||
// UnmarkDeep is similar to Unmark, but it works with an entire nested structure
|
||||
// rather than just the given value directly.
|
||||
//
|
||||
// The result is guaranteed to contain no nested values that are marked, and
|
||||
// the returned marks set includes the superset of all of the marks encountered
|
||||
// during the operation.
|
||||
func (val Value) UnmarkDeep() (Value, ValueMarks) {
|
||||
marks := make(ValueMarks)
|
||||
ret, _ := Transform(val, func(_ Path, v Value) (Value, error) {
|
||||
unmarkedV, valueMarks := val.Unmark()
|
||||
for m, s := range valueMarks {
|
||||
marks[m] = s
|
||||
}
|
||||
return unmarkedV, nil
|
||||
})
|
||||
return ret, marks
|
||||
}
|
||||
|
||||
func (val Value) unmarkForce() Value {
|
||||
unw, _ := val.Unmark()
|
||||
return unw
|
||||
}
|
||||
|
||||
// WithMarks returns a new value that has the same type and underlying value
|
||||
// as the receiver and also has the marks from the given maps (representing
|
||||
// sets).
|
||||
func (val Value) WithMarks(marks ...ValueMarks) Value {
|
||||
if len(marks) == 0 {
|
||||
return val
|
||||
}
|
||||
ownMarks := val.Marks()
|
||||
markCount := len(ownMarks)
|
||||
for _, s := range marks {
|
||||
markCount += len(s)
|
||||
}
|
||||
if markCount == 0 {
|
||||
return val
|
||||
}
|
||||
newMarks := make(ValueMarks, markCount)
|
||||
for m := range ownMarks {
|
||||
newMarks[m] = struct{}{}
|
||||
}
|
||||
for _, s := range marks {
|
||||
for m := range s {
|
||||
newMarks[m] = struct{}{}
|
||||
}
|
||||
}
|
||||
v := val.v
|
||||
if mr, ok := v.(marker); ok {
|
||||
v = mr.realV
|
||||
}
|
||||
return Value{
|
||||
ty: val.ty,
|
||||
v: marker{
|
||||
realV: v,
|
||||
marks: newMarks,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// WithSameMarks returns a new value that has the same type and underlying
|
||||
// value as the receiver and also has the marks from the given source values.
|
||||
//
|
||||
// Use this if you are implementing your own higher-level operations against
|
||||
// cty using the integration methods, to re-introduce the marks from the
|
||||
// source values of the operation.
|
||||
func (val Value) WithSameMarks(srcs ...Value) Value {
|
||||
if len(srcs) == 0 {
|
||||
return val
|
||||
}
|
||||
ownMarks := val.Marks()
|
||||
markCount := len(ownMarks)
|
||||
for _, sv := range srcs {
|
||||
if mr, ok := sv.v.(marker); ok {
|
||||
markCount += len(mr.marks)
|
||||
}
|
||||
}
|
||||
if markCount == 0 {
|
||||
return val
|
||||
}
|
||||
newMarks := make(ValueMarks, markCount)
|
||||
for m := range ownMarks {
|
||||
newMarks[m] = struct{}{}
|
||||
}
|
||||
for _, sv := range srcs {
|
||||
if mr, ok := sv.v.(marker); ok {
|
||||
for m := range mr.marks {
|
||||
newMarks[m] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
v := val.v
|
||||
if mr, ok := v.(marker); ok {
|
||||
v = mr.realV
|
||||
}
|
||||
return Value{
|
||||
ty: val.ty,
|
||||
v: marker{
|
||||
realV: v,
|
||||
marks: newMarks,
|
||||
},
|
||||
}
|
||||
}
|
14
vendor/github.com/zclconf/go-cty/cty/null.go
generated
vendored
Normal file
14
vendor/github.com/zclconf/go-cty/cty/null.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
package cty
|
||||
|
||||
// NullVal returns a null value of the given type. A null can be created of any
|
||||
// type, but operations on such values will always panic. Calling applications
|
||||
// are encouraged to use nulls only sparingly, particularly when user-provided
|
||||
// expressions are to be evaluated, since the precence of nulls creates a
|
||||
// much higher chance of evaluation errors that can't be caught by a type
|
||||
// checker.
|
||||
func NullVal(t Type) Value {
|
||||
return Value{
|
||||
ty: t,
|
||||
v: nil,
|
||||
}
|
||||
}
|
135
vendor/github.com/zclconf/go-cty/cty/object_type.go
generated
vendored
Normal file
135
vendor/github.com/zclconf/go-cty/cty/object_type.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type typeObject struct {
|
||||
typeImplSigil
|
||||
AttrTypes map[string]Type
|
||||
}
|
||||
|
||||
// Object creates an object type with the given attribute types.
|
||||
//
|
||||
// After a map is passed to this function the caller must no longer access it,
|
||||
// since ownership is transferred to this library.
|
||||
func Object(attrTypes map[string]Type) Type {
|
||||
attrTypesNorm := make(map[string]Type, len(attrTypes))
|
||||
for k, v := range attrTypes {
|
||||
attrTypesNorm[NormalizeString(k)] = v
|
||||
}
|
||||
|
||||
return Type{
|
||||
typeObject{
|
||||
AttrTypes: attrTypesNorm,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t typeObject) Equals(other Type) bool {
|
||||
if ot, ok := other.typeImpl.(typeObject); ok {
|
||||
if len(t.AttrTypes) != len(ot.AttrTypes) {
|
||||
// Fast path: if we don't have the same number of attributes
|
||||
// then we can't possibly be equal. This also avoids the need
|
||||
// to test attributes in both directions below, since we know
|
||||
// there can't be extras in "other".
|
||||
return false
|
||||
}
|
||||
|
||||
for attr, ty := range t.AttrTypes {
|
||||
oty, ok := ot.AttrTypes[attr]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if !oty.Equals(ty) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t typeObject) FriendlyName(mode friendlyTypeNameMode) string {
|
||||
// There isn't really a friendly way to write an object type due to its
|
||||
// complexity, so we'll just do something English-ish. Callers will
|
||||
// probably want to make some extra effort to avoid ever printing out
|
||||
// an object type FriendlyName in its entirety. For example, could
|
||||
// produce an error message by diffing two object types and saying
|
||||
// something like "Expected attribute foo to be string, but got number".
|
||||
// TODO: Finish this
|
||||
return "object"
|
||||
}
|
||||
|
||||
func (t typeObject) GoString() string {
|
||||
if len(t.AttrTypes) == 0 {
|
||||
return "cty.EmptyObject"
|
||||
}
|
||||
return fmt.Sprintf("cty.Object(%#v)", t.AttrTypes)
|
||||
}
|
||||
|
||||
// EmptyObject is a shorthand for Object(map[string]Type{}), to more
|
||||
// easily talk about the empty object type.
|
||||
var EmptyObject Type
|
||||
|
||||
// EmptyObjectVal is the only possible non-null, non-unknown value of type
|
||||
// EmptyObject.
|
||||
var EmptyObjectVal Value
|
||||
|
||||
func init() {
|
||||
EmptyObject = Object(map[string]Type{})
|
||||
EmptyObjectVal = Value{
|
||||
ty: EmptyObject,
|
||||
v: map[string]interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
// IsObjectType returns true if the given type is an object type, regardless
|
||||
// of its element type.
|
||||
func (t Type) IsObjectType() bool {
|
||||
_, ok := t.typeImpl.(typeObject)
|
||||
return ok
|
||||
}
|
||||
|
||||
// HasAttribute returns true if the receiver has an attribute with the given
|
||||
// name, regardless of its type. Will panic if the reciever isn't an object
|
||||
// type; use IsObjectType to determine whether this operation will succeed.
|
||||
func (t Type) HasAttribute(name string) bool {
|
||||
name = NormalizeString(name)
|
||||
if ot, ok := t.typeImpl.(typeObject); ok {
|
||||
_, hasAttr := ot.AttrTypes[name]
|
||||
return hasAttr
|
||||
}
|
||||
panic("HasAttribute on non-object Type")
|
||||
}
|
||||
|
||||
// AttributeType returns the type of the attribute with the given name. Will
|
||||
// panic if the receiver is not an object type (use IsObjectType to confirm)
|
||||
// or if the object type has no such attribute (use HasAttribute to confirm).
|
||||
func (t Type) AttributeType(name string) Type {
|
||||
name = NormalizeString(name)
|
||||
if ot, ok := t.typeImpl.(typeObject); ok {
|
||||
aty, hasAttr := ot.AttrTypes[name]
|
||||
if !hasAttr {
|
||||
panic("no such attribute")
|
||||
}
|
||||
return aty
|
||||
}
|
||||
panic("AttributeType on non-object Type")
|
||||
}
|
||||
|
||||
// AttributeTypes returns a map from attribute names to their associated
|
||||
// types. Will panic if the receiver is not an object type (use IsObjectType
|
||||
// to confirm).
|
||||
//
|
||||
// The returned map is part of the internal state of the type, and is provided
|
||||
// for read access only. It is forbidden for any caller to modify the returned
|
||||
// map. For many purposes the attribute-related methods of Value are more
|
||||
// appropriate and more convenient to use.
|
||||
func (t Type) AttributeTypes() map[string]Type {
|
||||
if ot, ok := t.typeImpl.(typeObject); ok {
|
||||
return ot.AttrTypes
|
||||
}
|
||||
panic("AttributeTypes on non-object Type")
|
||||
}
|
250
vendor/github.com/zclconf/go-cty/cty/path.go
generated
vendored
Normal file
250
vendor/github.com/zclconf/go-cty/cty/path.go
generated
vendored
Normal file
@ -0,0 +1,250 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A Path is a sequence of operations to locate a nested value within a
|
||||
// data structure.
|
||||
//
|
||||
// The empty Path represents the given item. Any PathSteps within represent
|
||||
// taking a single step down into a data structure.
|
||||
//
|
||||
// Path has some convenience methods for gradually constructing a path,
|
||||
// but callers can also feel free to just produce a slice of PathStep manually
|
||||
// and convert to this type, which may be more appropriate in environments
|
||||
// where memory pressure is a concern.
|
||||
//
|
||||
// Although a Path is technically mutable, by convention callers should not
|
||||
// mutate a path once it has been built and passed to some other subsystem.
|
||||
// Instead, use Copy and then mutate the copy before using it.
|
||||
type Path []PathStep
|
||||
|
||||
// PathStep represents a single step down into a data structure, as part
|
||||
// of a Path. PathStep is a closed interface, meaning that the only
|
||||
// permitted implementations are those within this package.
|
||||
type PathStep interface {
|
||||
pathStepSigil() pathStepImpl
|
||||
Apply(Value) (Value, error)
|
||||
}
|
||||
|
||||
// embed pathImpl into a struct to declare it a PathStep implementation
|
||||
type pathStepImpl struct{}
|
||||
|
||||
func (p pathStepImpl) pathStepSigil() pathStepImpl {
|
||||
return p
|
||||
}
|
||||
|
||||
// Index returns a new Path that is the reciever with an IndexStep appended
|
||||
// to the end.
|
||||
//
|
||||
// This is provided as a convenient way to construct paths, but each call
|
||||
// will create garbage so it should not be used where memory pressure is a
|
||||
// concern.
|
||||
func (p Path) Index(v Value) Path {
|
||||
ret := make(Path, len(p)+1)
|
||||
copy(ret, p)
|
||||
ret[len(p)] = IndexStep{
|
||||
Key: v,
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// IndexPath is a convenience method to start a new Path with an IndexStep.
|
||||
func IndexPath(v Value) Path {
|
||||
return Path{}.Index(v)
|
||||
}
|
||||
|
||||
// GetAttr returns a new Path that is the reciever with a GetAttrStep appended
|
||||
// to the end.
|
||||
//
|
||||
// This is provided as a convenient way to construct paths, but each call
|
||||
// will create garbage so it should not be used where memory pressure is a
|
||||
// concern.
|
||||
func (p Path) GetAttr(name string) Path {
|
||||
ret := make(Path, len(p)+1)
|
||||
copy(ret, p)
|
||||
ret[len(p)] = GetAttrStep{
|
||||
Name: name,
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Equals compares 2 Paths for exact equality.
|
||||
func (p Path) Equals(other Path) bool {
|
||||
if len(p) != len(other) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range p {
|
||||
pv := p[i]
|
||||
switch pv := pv.(type) {
|
||||
case GetAttrStep:
|
||||
ov, ok := other[i].(GetAttrStep)
|
||||
if !ok || pv != ov {
|
||||
return false
|
||||
}
|
||||
case IndexStep:
|
||||
ov, ok := other[i].(IndexStep)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if !pv.Key.RawEquals(ov.Key) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
// Any invalid steps default to evaluating false.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
// HasPrefix determines if the path p contains the provided prefix.
|
||||
func (p Path) HasPrefix(prefix Path) bool {
|
||||
if len(prefix) > len(p) {
|
||||
return false
|
||||
}
|
||||
|
||||
return p[:len(prefix)].Equals(prefix)
|
||||
}
|
||||
|
||||
// GetAttrPath is a convenience method to start a new Path with a GetAttrStep.
|
||||
func GetAttrPath(name string) Path {
|
||||
return Path{}.GetAttr(name)
|
||||
}
|
||||
|
||||
// Apply applies each of the steps in turn to successive values starting with
|
||||
// the given value, and returns the result. If any step returns an error,
|
||||
// the whole operation returns an error.
|
||||
func (p Path) Apply(val Value) (Value, error) {
|
||||
var err error
|
||||
for i, step := range p {
|
||||
val, err = step.Apply(val)
|
||||
if err != nil {
|
||||
return NilVal, fmt.Errorf("at step %d: %s", i, err)
|
||||
}
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// LastStep applies the given path up to the last step and then returns
|
||||
// the resulting value and the final step.
|
||||
//
|
||||
// This is useful when dealing with assignment operations, since in that
|
||||
// case the *value* of the last step is not important (and may not, in fact,
|
||||
// present at all) and we care only about its location.
|
||||
//
|
||||
// Since LastStep applies all steps except the last, it will return errors
|
||||
// for those steps in the same way as Apply does.
|
||||
//
|
||||
// If the path has *no* steps then the returned PathStep will be nil,
|
||||
// representing that any operation should be applied directly to the
|
||||
// given value.
|
||||
func (p Path) LastStep(val Value) (Value, PathStep, error) {
|
||||
var err error
|
||||
|
||||
if len(p) == 0 {
|
||||
return val, nil, nil
|
||||
}
|
||||
|
||||
journey := p[:len(p)-1]
|
||||
val, err = journey.Apply(val)
|
||||
if err != nil {
|
||||
return NilVal, nil, err
|
||||
}
|
||||
return val, p[len(p)-1], nil
|
||||
}
|
||||
|
||||
// Copy makes a shallow copy of the receiver. Often when paths are passed to
|
||||
// caller code they come with the constraint that they are valid only until
|
||||
// the caller returns, due to how they are constructed internally. Callers
|
||||
// can use Copy to conveniently produce a copy of the value that _they_ control
|
||||
// the validity of.
|
||||
func (p Path) Copy() Path {
|
||||
ret := make(Path, len(p))
|
||||
copy(ret, p)
|
||||
return ret
|
||||
}
|
||||
|
||||
// IndexStep is a Step implementation representing applying the index operation
|
||||
// to a value, which must be of either a list, map, or set type.
|
||||
//
|
||||
// When describing a path through a *type* rather than a concrete value,
|
||||
// the Key may be an unknown value, indicating that the step applies to
|
||||
// *any* key of the given type.
|
||||
//
|
||||
// When indexing into a set, the Key is actually the element being accessed
|
||||
// itself, since in sets elements are their own identity.
|
||||
type IndexStep struct {
|
||||
pathStepImpl
|
||||
Key Value
|
||||
}
|
||||
|
||||
// Apply returns the value resulting from indexing the given value with
|
||||
// our key value.
|
||||
func (s IndexStep) Apply(val Value) (Value, error) {
|
||||
if val == NilVal || val.IsNull() {
|
||||
return NilVal, errors.New("cannot index a null value")
|
||||
}
|
||||
|
||||
switch s.Key.Type() {
|
||||
case Number:
|
||||
if !(val.Type().IsListType() || val.Type().IsTupleType()) {
|
||||
return NilVal, errors.New("not a list type")
|
||||
}
|
||||
case String:
|
||||
if !val.Type().IsMapType() {
|
||||
return NilVal, errors.New("not a map type")
|
||||
}
|
||||
default:
|
||||
return NilVal, errors.New("key value not number or string")
|
||||
}
|
||||
|
||||
has := val.HasIndex(s.Key)
|
||||
if !has.IsKnown() {
|
||||
return UnknownVal(val.Type().ElementType()), nil
|
||||
}
|
||||
if !has.True() {
|
||||
return NilVal, errors.New("value does not have given index key")
|
||||
}
|
||||
|
||||
return val.Index(s.Key), nil
|
||||
}
|
||||
|
||||
func (s IndexStep) GoString() string {
|
||||
return fmt.Sprintf("cty.IndexStep{Key:%#v}", s.Key)
|
||||
}
|
||||
|
||||
// GetAttrStep is a Step implementation representing retrieving an attribute
|
||||
// from a value, which must be of an object type.
|
||||
type GetAttrStep struct {
|
||||
pathStepImpl
|
||||
Name string
|
||||
}
|
||||
|
||||
// Apply returns the value of our named attribute from the given value, which
|
||||
// must be of an object type that has a value of that name.
|
||||
func (s GetAttrStep) Apply(val Value) (Value, error) {
|
||||
if val == NilVal || val.IsNull() {
|
||||
return NilVal, errors.New("cannot access attributes on a null value")
|
||||
}
|
||||
|
||||
if !val.Type().IsObjectType() {
|
||||
return NilVal, errors.New("not an object type")
|
||||
}
|
||||
|
||||
if !val.Type().HasAttribute(s.Name) {
|
||||
return NilVal, fmt.Errorf("object has no attribute %q", s.Name)
|
||||
}
|
||||
|
||||
return val.GetAttr(s.Name), nil
|
||||
}
|
||||
|
||||
func (s GetAttrStep) GoString() string {
|
||||
return fmt.Sprintf("cty.GetAttrStep{Name:%q}", s.Name)
|
||||
}
|
198
vendor/github.com/zclconf/go-cty/cty/path_set.go
generated
vendored
Normal file
198
vendor/github.com/zclconf/go-cty/cty/path_set.go
generated
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc64"
|
||||
|
||||
"github.com/zclconf/go-cty/cty/set"
|
||||
)
|
||||
|
||||
// PathSet represents a set of Path objects. This can be used, for example,
|
||||
// to talk about a subset of paths within a value that meet some criteria,
|
||||
// without directly modifying the values at those paths.
|
||||
type PathSet struct {
|
||||
set set.Set
|
||||
}
|
||||
|
||||
// NewPathSet creates and returns a PathSet, with initial contents optionally
|
||||
// set by the given arguments.
|
||||
func NewPathSet(paths ...Path) PathSet {
|
||||
ret := PathSet{
|
||||
set: set.NewSet(pathSetRules{}),
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
ret.Add(path)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Add inserts a single given path into the set.
|
||||
//
|
||||
// Paths are immutable after construction by convention. It is particularly
|
||||
// important not to mutate a path after it has been placed into a PathSet.
|
||||
// If a Path is mutated while in a set, behavior is undefined.
|
||||
func (s PathSet) Add(path Path) {
|
||||
s.set.Add(path)
|
||||
}
|
||||
|
||||
// AddAllSteps is like Add but it also adds all of the steps leading to
|
||||
// the given path.
|
||||
//
|
||||
// For example, if given a path representing "foo.bar", it will add both
|
||||
// "foo" and "bar".
|
||||
func (s PathSet) AddAllSteps(path Path) {
|
||||
for i := 1; i <= len(path); i++ {
|
||||
s.Add(path[:i])
|
||||
}
|
||||
}
|
||||
|
||||
// Has returns true if the given path is in the receiving set.
|
||||
func (s PathSet) Has(path Path) bool {
|
||||
return s.set.Has(path)
|
||||
}
|
||||
|
||||
// List makes and returns a slice of all of the paths in the receiving set,
|
||||
// in an undefined but consistent order.
|
||||
func (s PathSet) List() []Path {
|
||||
if s.Empty() {
|
||||
return nil
|
||||
}
|
||||
ret := make([]Path, 0, s.set.Length())
|
||||
for it := s.set.Iterator(); it.Next(); {
|
||||
ret = append(ret, it.Value().(Path))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Remove modifies the receving set to no longer include the given path.
|
||||
// If the given path was already absent, this is a no-op.
|
||||
func (s PathSet) Remove(path Path) {
|
||||
s.set.Remove(path)
|
||||
}
|
||||
|
||||
// Empty returns true if the length of the receiving set is zero.
|
||||
func (s PathSet) Empty() bool {
|
||||
return s.set.Length() == 0
|
||||
}
|
||||
|
||||
// Union returns a new set whose contents are the union of the receiver and
|
||||
// the given other set.
|
||||
func (s PathSet) Union(other PathSet) PathSet {
|
||||
return PathSet{
|
||||
set: s.set.Union(other.set),
|
||||
}
|
||||
}
|
||||
|
||||
// Intersection returns a new set whose contents are the intersection of the
|
||||
// receiver and the given other set.
|
||||
func (s PathSet) Intersection(other PathSet) PathSet {
|
||||
return PathSet{
|
||||
set: s.set.Intersection(other.set),
|
||||
}
|
||||
}
|
||||
|
||||
// Subtract returns a new set whose contents are those from the receiver with
|
||||
// any elements of the other given set subtracted.
|
||||
func (s PathSet) Subtract(other PathSet) PathSet {
|
||||
return PathSet{
|
||||
set: s.set.Subtract(other.set),
|
||||
}
|
||||
}
|
||||
|
||||
// SymmetricDifference returns a new set whose contents are the symmetric
|
||||
// difference of the receiver and the given other set.
|
||||
func (s PathSet) SymmetricDifference(other PathSet) PathSet {
|
||||
return PathSet{
|
||||
set: s.set.SymmetricDifference(other.set),
|
||||
}
|
||||
}
|
||||
|
||||
// Equal returns true if and only if both the receiver and the given other
|
||||
// set contain exactly the same paths.
|
||||
func (s PathSet) Equal(other PathSet) bool {
|
||||
if s.set.Length() != other.set.Length() {
|
||||
return false
|
||||
}
|
||||
// Now we know the lengths are the same we only need to test in one
|
||||
// direction whether everything in one is in the other.
|
||||
for it := s.set.Iterator(); it.Next(); {
|
||||
if !other.set.Has(it.Value()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var crc64Table = crc64.MakeTable(crc64.ISO)
|
||||
|
||||
var indexStepPlaceholder = []byte("#")
|
||||
|
||||
// pathSetRules is an implementation of set.Rules from the set package,
|
||||
// used internally within PathSet.
|
||||
type pathSetRules struct {
|
||||
}
|
||||
|
||||
func (r pathSetRules) Hash(v interface{}) int {
|
||||
path := v.(Path)
|
||||
hash := crc64.New(crc64Table)
|
||||
|
||||
for _, rawStep := range path {
|
||||
switch step := rawStep.(type) {
|
||||
case GetAttrStep:
|
||||
// (this creates some garbage converting the string name to a
|
||||
// []byte, but that's okay since cty is not designed to be
|
||||
// used in tight loops under memory pressure.)
|
||||
hash.Write([]byte(step.Name))
|
||||
default:
|
||||
// For any other step type we just append a predefined value,
|
||||
// which means that e.g. all indexes into a given collection will
|
||||
// hash to the same value but we assume that collections are
|
||||
// small and thus this won't hurt too much.
|
||||
hash.Write(indexStepPlaceholder)
|
||||
}
|
||||
}
|
||||
|
||||
// We discard half of the hash on 32-bit platforms; collisions just make
|
||||
// our lookups take marginally longer, so not a big deal.
|
||||
return int(hash.Sum64())
|
||||
}
|
||||
|
||||
func (r pathSetRules) Equivalent(a, b interface{}) bool {
|
||||
aPath := a.(Path)
|
||||
bPath := b.(Path)
|
||||
|
||||
if len(aPath) != len(bPath) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range aPath {
|
||||
switch aStep := aPath[i].(type) {
|
||||
case GetAttrStep:
|
||||
bStep, ok := bPath[i].(GetAttrStep)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if aStep.Name != bStep.Name {
|
||||
return false
|
||||
}
|
||||
case IndexStep:
|
||||
bStep, ok := bPath[i].(IndexStep)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
eq := aStep.Key.Equals(bStep.Key)
|
||||
if !eq.IsKnown() || eq.False() {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
// Should never happen, since we document PathStep as a closed type.
|
||||
panic(fmt.Errorf("unsupported step type %T", aStep))
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
122
vendor/github.com/zclconf/go-cty/cty/primitive_type.go
generated
vendored
Normal file
122
vendor/github.com/zclconf/go-cty/cty/primitive_type.go
generated
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
package cty
|
||||
|
||||
import "math/big"
|
||||
|
||||
// primitiveType is the hidden implementation of the various primitive types
|
||||
// that are exposed as variables in this package.
|
||||
type primitiveType struct {
|
||||
typeImplSigil
|
||||
Kind primitiveTypeKind
|
||||
}
|
||||
|
||||
type primitiveTypeKind byte
|
||||
|
||||
const (
|
||||
primitiveTypeBool primitiveTypeKind = 'B'
|
||||
primitiveTypeNumber primitiveTypeKind = 'N'
|
||||
primitiveTypeString primitiveTypeKind = 'S'
|
||||
)
|
||||
|
||||
func (t primitiveType) Equals(other Type) bool {
|
||||
if otherP, ok := other.typeImpl.(primitiveType); ok {
|
||||
return otherP.Kind == t.Kind
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t primitiveType) FriendlyName(mode friendlyTypeNameMode) string {
|
||||
switch t.Kind {
|
||||
case primitiveTypeBool:
|
||||
return "bool"
|
||||
case primitiveTypeNumber:
|
||||
return "number"
|
||||
case primitiveTypeString:
|
||||
return "string"
|
||||
default:
|
||||
// should never happen
|
||||
panic("invalid primitive type")
|
||||
}
|
||||
}
|
||||
|
||||
func (t primitiveType) GoString() string {
|
||||
switch t.Kind {
|
||||
case primitiveTypeBool:
|
||||
return "cty.Bool"
|
||||
case primitiveTypeNumber:
|
||||
return "cty.Number"
|
||||
case primitiveTypeString:
|
||||
return "cty.String"
|
||||
default:
|
||||
// should never happen
|
||||
panic("invalid primitive type")
|
||||
}
|
||||
}
|
||||
|
||||
// Number is the numeric type. Number values are arbitrary-precision
|
||||
// decimal numbers, which can then be converted into Go's various numeric
|
||||
// types only if they are in the appropriate range.
|
||||
var Number Type
|
||||
|
||||
// String is the string type. String values are sequences of unicode codepoints
|
||||
// encoded internally as UTF-8.
|
||||
var String Type
|
||||
|
||||
// Bool is the boolean type. The two values of this type are True and False.
|
||||
var Bool Type
|
||||
|
||||
// True is the truthy value of type Bool
|
||||
var True Value
|
||||
|
||||
// False is the falsey value of type Bool
|
||||
var False Value
|
||||
|
||||
// Zero is a number value representing exactly zero.
|
||||
var Zero Value
|
||||
|
||||
// PositiveInfinity is a Number value representing positive infinity
|
||||
var PositiveInfinity Value
|
||||
|
||||
// NegativeInfinity is a Number value representing negative infinity
|
||||
var NegativeInfinity Value
|
||||
|
||||
func init() {
|
||||
Number = Type{
|
||||
primitiveType{Kind: primitiveTypeNumber},
|
||||
}
|
||||
String = Type{
|
||||
primitiveType{Kind: primitiveTypeString},
|
||||
}
|
||||
Bool = Type{
|
||||
primitiveType{Kind: primitiveTypeBool},
|
||||
}
|
||||
True = Value{
|
||||
ty: Bool,
|
||||
v: true,
|
||||
}
|
||||
False = Value{
|
||||
ty: Bool,
|
||||
v: false,
|
||||
}
|
||||
Zero = Value{
|
||||
ty: Number,
|
||||
v: big.NewFloat(0),
|
||||
}
|
||||
PositiveInfinity = Value{
|
||||
ty: Number,
|
||||
v: (&big.Float{}).SetInf(false),
|
||||
}
|
||||
NegativeInfinity = Value{
|
||||
ty: Number,
|
||||
v: (&big.Float{}).SetInf(true),
|
||||
}
|
||||
}
|
||||
|
||||
// IsPrimitiveType returns true if and only if the reciever is a primitive
|
||||
// type, which means it's either number, string, or bool. Any two primitive
|
||||
// types can be safely compared for equality using the standard == operator
|
||||
// without panic, which is not a guarantee that holds for all types. Primitive
|
||||
// types can therefore also be used in switch statements.
|
||||
func (t Type) IsPrimitiveType() bool {
|
||||
_, ok := t.typeImpl.(primitiveType)
|
||||
return ok
|
||||
}
|
76
vendor/github.com/zclconf/go-cty/cty/set/gob.go
generated
vendored
Normal file
76
vendor/github.com/zclconf/go-cty/cty/set/gob.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
package set
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// GobEncode is an implementation of the interface gob.GobEncoder, allowing
|
||||
// sets to be included in structures encoded via gob.
|
||||
//
|
||||
// The set rules are included in the serialized value, so the caller must
|
||||
// register its concrete rules type with gob.Register before using a
|
||||
// set in a gob, and possibly also implement GobEncode/GobDecode to customize
|
||||
// how any parameters are persisted.
|
||||
//
|
||||
// The set elements are also included, so if they are of non-primitive types
|
||||
// they too must be registered with gob.
|
||||
//
|
||||
// If the produced gob values will persist for a long time, the caller must
|
||||
// ensure compatibility of the rules implementation. In particular, if the
|
||||
// definition of element equivalence changes between encoding and decoding
|
||||
// then two distinct stored elements may be considered equivalent on decoding,
|
||||
// causing the recovered set to have fewer elements than when it was stored.
|
||||
func (s Set) GobEncode() ([]byte, error) {
|
||||
gs := gobSet{
|
||||
Version: 0,
|
||||
Rules: s.rules,
|
||||
Values: s.Values(),
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
enc := gob.NewEncoder(buf)
|
||||
err := enc.Encode(gs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error encoding set.Set: %s", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// GobDecode is the opposite of GobEncode. See GobEncode for information
|
||||
// on the requirements for and caveats of including set values in gobs.
|
||||
func (s *Set) GobDecode(buf []byte) error {
|
||||
r := bytes.NewReader(buf)
|
||||
dec := gob.NewDecoder(r)
|
||||
|
||||
var gs gobSet
|
||||
err := dec.Decode(&gs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error decoding set.Set: %s", err)
|
||||
}
|
||||
if gs.Version != 0 {
|
||||
return fmt.Errorf("unsupported set.Set encoding version %d; need 0", gs.Version)
|
||||
}
|
||||
|
||||
victim := NewSetFromSlice(gs.Rules, gs.Values)
|
||||
s.vals = victim.vals
|
||||
s.rules = victim.rules
|
||||
return nil
|
||||
}
|
||||
|
||||
type gobSet struct {
|
||||
Version int
|
||||
Rules Rules
|
||||
|
||||
// The bucket-based representation is for efficient in-memory access, but
|
||||
// for serialization it's enough to just retain the values themselves,
|
||||
// which we can re-bucket using the rules (which may have changed!) when
|
||||
// we re-inflate.
|
||||
Values []interface{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
gob.Register([]interface{}(nil))
|
||||
}
|
15
vendor/github.com/zclconf/go-cty/cty/set/iterator.go
generated
vendored
Normal file
15
vendor/github.com/zclconf/go-cty/cty/set/iterator.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
package set
|
||||
|
||||
type Iterator struct {
|
||||
vals []interface{}
|
||||
idx int
|
||||
}
|
||||
|
||||
func (it *Iterator) Value() interface{} {
|
||||
return it.vals[it.idx]
|
||||
}
|
||||
|
||||
func (it *Iterator) Next() bool {
|
||||
it.idx++
|
||||
return it.idx < len(it.vals)
|
||||
}
|
210
vendor/github.com/zclconf/go-cty/cty/set/ops.go
generated
vendored
Normal file
210
vendor/github.com/zclconf/go-cty/cty/set/ops.go
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
package set
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Add inserts the given value into the receiving Set.
|
||||
//
|
||||
// This mutates the set in-place. This operation is not thread-safe.
|
||||
func (s Set) Add(val interface{}) {
|
||||
hv := s.rules.Hash(val)
|
||||
if _, ok := s.vals[hv]; !ok {
|
||||
s.vals[hv] = make([]interface{}, 0, 1)
|
||||
}
|
||||
bucket := s.vals[hv]
|
||||
|
||||
// See if an equivalent value is already present
|
||||
for _, ev := range bucket {
|
||||
if s.rules.Equivalent(val, ev) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s.vals[hv] = append(bucket, val)
|
||||
}
|
||||
|
||||
// Remove deletes the given value from the receiving set, if indeed it was
|
||||
// there in the first place. If the value is not present, this is a no-op.
|
||||
func (s Set) Remove(val interface{}) {
|
||||
hv := s.rules.Hash(val)
|
||||
bucket, ok := s.vals[hv]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for i, ev := range bucket {
|
||||
if s.rules.Equivalent(val, ev) {
|
||||
newBucket := make([]interface{}, 0, len(bucket)-1)
|
||||
newBucket = append(newBucket, bucket[:i]...)
|
||||
newBucket = append(newBucket, bucket[i+1:]...)
|
||||
if len(newBucket) > 0 {
|
||||
s.vals[hv] = newBucket
|
||||
} else {
|
||||
delete(s.vals, hv)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Has returns true if the given value is in the receiving set, or false if
|
||||
// it is not.
|
||||
func (s Set) Has(val interface{}) bool {
|
||||
hv := s.rules.Hash(val)
|
||||
bucket, ok := s.vals[hv]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, ev := range bucket {
|
||||
if s.rules.Equivalent(val, ev) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Copy performs a shallow copy of the receiving set, returning a new set
|
||||
// with the same rules and elements.
|
||||
func (s Set) Copy() Set {
|
||||
ret := NewSet(s.rules)
|
||||
for k, v := range s.vals {
|
||||
ret.vals[k] = v
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Iterator returns an iterator over values in the set. If the set's rules
|
||||
// implement OrderedRules then the result is ordered per those rules. If
|
||||
// no order is provided, or if it is not a total order, then the iteration
|
||||
// order is undefined but consistent for a particular version of cty. Do not
|
||||
// rely on specific ordering between cty releases unless the rules order is a
|
||||
// total order.
|
||||
//
|
||||
// The pattern for using the returned iterator is:
|
||||
//
|
||||
// it := set.Iterator()
|
||||
// for it.Next() {
|
||||
// val := it.Value()
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// Once an iterator has been created for a set, the set *must not* be mutated
|
||||
// until the iterator is no longer in use.
|
||||
func (s Set) Iterator() *Iterator {
|
||||
vals := s.Values()
|
||||
|
||||
return &Iterator{
|
||||
vals: vals,
|
||||
idx: -1,
|
||||
}
|
||||
}
|
||||
|
||||
// EachValue calls the given callback once for each value in the set, in an
|
||||
// undefined order that callers should not depend on.
|
||||
func (s Set) EachValue(cb func(interface{})) {
|
||||
it := s.Iterator()
|
||||
for it.Next() {
|
||||
cb(it.Value())
|
||||
}
|
||||
}
|
||||
|
||||
// Values returns a slice of all the values in the set. If the set rules have
|
||||
// an order then the result is in that order. If no order is provided or if
|
||||
// it is not a total order then the result order is undefined, but consistent
|
||||
// for a particular set value within a specific release of cty.
|
||||
func (s Set) Values() []interface{} {
|
||||
var ret []interface{}
|
||||
// Sort the bucketIds to ensure that we always traverse in a
|
||||
// consistent order.
|
||||
bucketIDs := make([]int, 0, len(s.vals))
|
||||
for id := range s.vals {
|
||||
bucketIDs = append(bucketIDs, id)
|
||||
}
|
||||
sort.Ints(bucketIDs)
|
||||
|
||||
for _, bucketID := range bucketIDs {
|
||||
ret = append(ret, s.vals[bucketID]...)
|
||||
}
|
||||
|
||||
if orderRules, ok := s.rules.(OrderedRules); ok {
|
||||
sort.SliceStable(ret, func(i, j int) bool {
|
||||
return orderRules.Less(ret[i], ret[j])
|
||||
})
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Length returns the number of values in the set.
|
||||
func (s Set) Length() int {
|
||||
var count int
|
||||
for _, bucket := range s.vals {
|
||||
count = count + len(bucket)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// Union returns a new set that contains all of the members of both the
|
||||
// receiving set and the given set. Both sets must have the same rules, or
|
||||
// else this function will panic.
|
||||
func (s1 Set) Union(s2 Set) Set {
|
||||
mustHaveSameRules(s1, s2)
|
||||
rs := NewSet(s1.rules)
|
||||
s1.EachValue(func(v interface{}) {
|
||||
rs.Add(v)
|
||||
})
|
||||
s2.EachValue(func(v interface{}) {
|
||||
rs.Add(v)
|
||||
})
|
||||
return rs
|
||||
}
|
||||
|
||||
// Intersection returns a new set that contains the values that both the
|
||||
// receiver and given sets have in common. Both sets must have the same rules,
|
||||
// or else this function will panic.
|
||||
func (s1 Set) Intersection(s2 Set) Set {
|
||||
mustHaveSameRules(s1, s2)
|
||||
rs := NewSet(s1.rules)
|
||||
s1.EachValue(func(v interface{}) {
|
||||
if s2.Has(v) {
|
||||
rs.Add(v)
|
||||
}
|
||||
})
|
||||
return rs
|
||||
}
|
||||
|
||||
// Subtract returns a new set that contains all of the values from the receiver
|
||||
// that are not also in the given set. Both sets must have the same rules,
|
||||
// or else this function will panic.
|
||||
func (s1 Set) Subtract(s2 Set) Set {
|
||||
mustHaveSameRules(s1, s2)
|
||||
rs := NewSet(s1.rules)
|
||||
s1.EachValue(func(v interface{}) {
|
||||
if !s2.Has(v) {
|
||||
rs.Add(v)
|
||||
}
|
||||
})
|
||||
return rs
|
||||
}
|
||||
|
||||
// SymmetricDifference returns a new set that contains all of the values from
|
||||
// both the receiver and given sets, except those that both sets have in
|
||||
// common. Both sets must have the same rules, or else this function will
|
||||
// panic.
|
||||
func (s1 Set) SymmetricDifference(s2 Set) Set {
|
||||
mustHaveSameRules(s1, s2)
|
||||
rs := NewSet(s1.rules)
|
||||
s1.EachValue(func(v interface{}) {
|
||||
if !s2.Has(v) {
|
||||
rs.Add(v)
|
||||
}
|
||||
})
|
||||
s2.EachValue(func(v interface{}) {
|
||||
if !s1.Has(v) {
|
||||
rs.Add(v)
|
||||
}
|
||||
})
|
||||
return rs
|
||||
}
|
43
vendor/github.com/zclconf/go-cty/cty/set/rules.go
generated
vendored
Normal file
43
vendor/github.com/zclconf/go-cty/cty/set/rules.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
package set
|
||||
|
||||
// Rules represents the operations that define membership for a Set.
|
||||
//
|
||||
// Each Set has a Rules instance, whose methods must satisfy the interface
|
||||
// contracts given below for any value that will be added to the set.
|
||||
type Rules interface {
|
||||
// Hash returns an int that somewhat-uniquely identifies the given value.
|
||||
//
|
||||
// A good hash function will minimize collisions for values that will be
|
||||
// added to the set, though collisions *are* permitted. Collisions will
|
||||
// simply reduce the efficiency of operations on the set.
|
||||
Hash(interface{}) int
|
||||
|
||||
// Equivalent returns true if and only if the two values are considered
|
||||
// equivalent for the sake of set membership. Two values that are
|
||||
// equivalent cannot exist in the set at the same time, and if two
|
||||
// equivalent values are added it is undefined which one will be
|
||||
// returned when enumerating all of the set members.
|
||||
//
|
||||
// Two values that are equivalent *must* result in the same hash value,
|
||||
// though it is *not* required that two values with the same hash value
|
||||
// be equivalent.
|
||||
Equivalent(interface{}, interface{}) bool
|
||||
}
|
||||
|
||||
// OrderedRules is an extension of Rules that can apply a partial order to
|
||||
// element values. When a set's Rules implements OrderedRules an iterator
|
||||
// over the set will return items in the order described by the rules.
|
||||
//
|
||||
// If the given order is not a total order (that is, some pairs of non-equivalent
|
||||
// elements do not have a defined order) then the resulting iteration order
|
||||
// is undefined but consistent for a particular version of cty. The exact
|
||||
// order in that case is not part of the contract and is subject to change
|
||||
// between versions.
|
||||
type OrderedRules interface {
|
||||
Rules
|
||||
|
||||
// Less returns true if and only if the first argument should sort before
|
||||
// the second argument. If the second argument should sort before the first
|
||||
// or if there is no defined order for the values, return false.
|
||||
Less(interface{}, interface{}) bool
|
||||
}
|
62
vendor/github.com/zclconf/go-cty/cty/set/set.go
generated
vendored
Normal file
62
vendor/github.com/zclconf/go-cty/cty/set/set.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
package set
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Set is an implementation of the concept of a set: a collection where all
|
||||
// values are conceptually either in or out of the set, but the members are
|
||||
// not ordered.
|
||||
//
|
||||
// This type primarily exists to be the internal type of sets in cty, but
|
||||
// it is considered to be at the same level of abstraction as Go's built in
|
||||
// slice and map collection types, and so should make no cty-specific
|
||||
// assumptions.
|
||||
//
|
||||
// Set operations are not thread safe. It is the caller's responsibility to
|
||||
// provide mutex guarantees where necessary.
|
||||
//
|
||||
// Set operations are not optimized to minimize memory pressure. Mutating
|
||||
// a set will generally create garbage and so should perhaps be avoided in
|
||||
// tight loops where memory pressure is a concern.
|
||||
type Set struct {
|
||||
vals map[int][]interface{}
|
||||
rules Rules
|
||||
}
|
||||
|
||||
// NewSet returns an empty set with the membership rules given.
|
||||
func NewSet(rules Rules) Set {
|
||||
return Set{
|
||||
vals: map[int][]interface{}{},
|
||||
rules: rules,
|
||||
}
|
||||
}
|
||||
|
||||
func NewSetFromSlice(rules Rules, vals []interface{}) Set {
|
||||
s := NewSet(rules)
|
||||
for _, v := range vals {
|
||||
s.Add(v)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func sameRules(s1 Set, s2 Set) bool {
|
||||
return s1.rules == s2.rules
|
||||
}
|
||||
|
||||
func mustHaveSameRules(s1 Set, s2 Set) {
|
||||
if !sameRules(s1, s2) {
|
||||
panic(fmt.Errorf("incompatible set rules: %#v, %#v", s1.rules, s2.rules))
|
||||
}
|
||||
}
|
||||
|
||||
// HasRules returns true if and only if the receiving set has the given rules
|
||||
// instance as its rules.
|
||||
func (s Set) HasRules(rules Rules) bool {
|
||||
return s.rules == rules
|
||||
}
|
||||
|
||||
// Rules returns the receiving set's rules instance.
|
||||
func (s Set) Rules() Rules {
|
||||
return s.rules
|
||||
}
|
132
vendor/github.com/zclconf/go-cty/cty/set_helper.go
generated
vendored
Normal file
132
vendor/github.com/zclconf/go-cty/cty/set_helper.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zclconf/go-cty/cty/set"
|
||||
)
|
||||
|
||||
// ValueSet is to cty.Set what []cty.Value is to cty.List and
|
||||
// map[string]cty.Value is to cty.Map. It's provided to allow callers a
|
||||
// convenient interface for manipulating sets before wrapping them in cty.Set
|
||||
// values using cty.SetValFromValueSet.
|
||||
//
|
||||
// Unlike value slices and value maps, ValueSet instances have a single
|
||||
// homogenous element type because that is a requirement of the underlying
|
||||
// set implementation, which uses the element type to select a suitable
|
||||
// hashing function.
|
||||
//
|
||||
// Set mutations are not concurrency-safe.
|
||||
type ValueSet struct {
|
||||
// ValueSet is just a thin wrapper around a set.Set with our value-oriented
|
||||
// "rules" applied. We do this so that the caller can work in terms of
|
||||
// cty.Value objects even though the set internals use the raw values.
|
||||
s set.Set
|
||||
}
|
||||
|
||||
// NewValueSet creates and returns a new ValueSet with the given element type.
|
||||
func NewValueSet(ety Type) ValueSet {
|
||||
return newValueSet(set.NewSet(setRules{Type: ety}))
|
||||
}
|
||||
|
||||
func newValueSet(s set.Set) ValueSet {
|
||||
return ValueSet{
|
||||
s: s,
|
||||
}
|
||||
}
|
||||
|
||||
// ElementType returns the element type for the receiving ValueSet.
|
||||
func (s ValueSet) ElementType() Type {
|
||||
return s.s.Rules().(setRules).Type
|
||||
}
|
||||
|
||||
// Add inserts the given value into the receiving set.
|
||||
func (s ValueSet) Add(v Value) {
|
||||
s.requireElementType(v)
|
||||
s.s.Add(v.v)
|
||||
}
|
||||
|
||||
// Remove deletes the given value from the receiving set, if indeed it was
|
||||
// there in the first place. If the value is not present, this is a no-op.
|
||||
func (s ValueSet) Remove(v Value) {
|
||||
s.requireElementType(v)
|
||||
s.s.Remove(v.v)
|
||||
}
|
||||
|
||||
// Has returns true if the given value is in the receiving set, or false if
|
||||
// it is not.
|
||||
func (s ValueSet) Has(v Value) bool {
|
||||
s.requireElementType(v)
|
||||
return s.s.Has(v.v)
|
||||
}
|
||||
|
||||
// Copy performs a shallow copy of the receiving set, returning a new set
|
||||
// with the same rules and elements.
|
||||
func (s ValueSet) Copy() ValueSet {
|
||||
return newValueSet(s.s.Copy())
|
||||
}
|
||||
|
||||
// Length returns the number of values in the set.
|
||||
func (s ValueSet) Length() int {
|
||||
return s.s.Length()
|
||||
}
|
||||
|
||||
// Values returns a slice of all of the values in the set in no particular
|
||||
// order.
|
||||
func (s ValueSet) Values() []Value {
|
||||
l := s.s.Length()
|
||||
if l == 0 {
|
||||
return nil
|
||||
}
|
||||
ret := make([]Value, 0, l)
|
||||
ety := s.ElementType()
|
||||
for it := s.s.Iterator(); it.Next(); {
|
||||
ret = append(ret, Value{
|
||||
ty: ety,
|
||||
v: it.Value(),
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Union returns a new set that contains all of the members of both the
|
||||
// receiving set and the given set. Both sets must have the same element type,
|
||||
// or else this function will panic.
|
||||
func (s ValueSet) Union(other ValueSet) ValueSet {
|
||||
return newValueSet(s.s.Union(other.s))
|
||||
}
|
||||
|
||||
// Intersection returns a new set that contains the values that both the
|
||||
// receiver and given sets have in common. Both sets must have the same element
|
||||
// type, or else this function will panic.
|
||||
func (s ValueSet) Intersection(other ValueSet) ValueSet {
|
||||
return newValueSet(s.s.Intersection(other.s))
|
||||
}
|
||||
|
||||
// Subtract returns a new set that contains all of the values from the receiver
|
||||
// that are not also in the given set. Both sets must have the same element
|
||||
// type, or else this function will panic.
|
||||
func (s ValueSet) Subtract(other ValueSet) ValueSet {
|
||||
return newValueSet(s.s.Subtract(other.s))
|
||||
}
|
||||
|
||||
// SymmetricDifference returns a new set that contains all of the values from
|
||||
// both the receiver and given sets, except those that both sets have in
|
||||
// common. Both sets must have the same element type, or else this function
|
||||
// will panic.
|
||||
func (s ValueSet) SymmetricDifference(other ValueSet) ValueSet {
|
||||
return newValueSet(s.s.SymmetricDifference(other.s))
|
||||
}
|
||||
|
||||
// requireElementType panics if the given value is not of the set's element type.
|
||||
//
|
||||
// It also panics if the given value is marked, because marked values cannot
|
||||
// be stored in sets.
|
||||
func (s ValueSet) requireElementType(v Value) {
|
||||
if v.IsMarked() {
|
||||
panic("cannot store marked value directly in a set (make the set itself unknown instead)")
|
||||
}
|
||||
if !v.Type().Equals(s.ElementType()) {
|
||||
panic(fmt.Errorf("attempt to use %#v value with set of %#v", v.Type(), s.ElementType()))
|
||||
}
|
||||
}
|
244
vendor/github.com/zclconf/go-cty/cty/set_internals.go
generated
vendored
Normal file
244
vendor/github.com/zclconf/go-cty/cty/set_internals.go
generated
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"math/big"
|
||||
"sort"
|
||||
|
||||
"github.com/zclconf/go-cty/cty/set"
|
||||
)
|
||||
|
||||
// setRules provides a Rules implementation for the ./set package that
|
||||
// respects the equality rules for cty values of the given type.
|
||||
//
|
||||
// This implementation expects that values added to the set will be
|
||||
// valid internal values for the given Type, which is to say that wrapping
|
||||
// the given value in a Value struct along with the ruleset's type should
|
||||
// produce a valid, working Value.
|
||||
type setRules struct {
|
||||
Type Type
|
||||
}
|
||||
|
||||
var _ set.OrderedRules = setRules{}
|
||||
|
||||
// Hash returns a hash value for the receiver that can be used for equality
|
||||
// checks where some inaccuracy is tolerable.
|
||||
//
|
||||
// The hash function is value-type-specific, so it is not meaningful to compare
|
||||
// hash results for values of different types.
|
||||
//
|
||||
// This function is not safe to use for security-related applications, since
|
||||
// the hash used is not strong enough.
|
||||
func (val Value) Hash() int {
|
||||
hashBytes, marks := makeSetHashBytes(val)
|
||||
if len(marks) > 0 {
|
||||
panic("can't take hash of value that has marks or has embedded values that have marks")
|
||||
}
|
||||
return int(crc32.ChecksumIEEE(hashBytes))
|
||||
}
|
||||
|
||||
func (r setRules) Hash(v interface{}) int {
|
||||
return Value{
|
||||
ty: r.Type,
|
||||
v: v,
|
||||
}.Hash()
|
||||
}
|
||||
|
||||
func (r setRules) Equivalent(v1 interface{}, v2 interface{}) bool {
|
||||
v1v := Value{
|
||||
ty: r.Type,
|
||||
v: v1,
|
||||
}
|
||||
v2v := Value{
|
||||
ty: r.Type,
|
||||
v: v2,
|
||||
}
|
||||
|
||||
eqv := v1v.Equals(v2v)
|
||||
|
||||
// By comparing the result to true we ensure that an Unknown result,
|
||||
// which will result if either value is unknown, will be considered
|
||||
// as non-equivalent. Two unknown values are not equivalent for the
|
||||
// sake of set membership.
|
||||
return eqv.v == true
|
||||
}
|
||||
|
||||
// Less is an implementation of set.OrderedRules so that we can iterate over
|
||||
// set elements in a consistent order, where such an order is possible.
|
||||
func (r setRules) Less(v1, v2 interface{}) bool {
|
||||
v1v := Value{
|
||||
ty: r.Type,
|
||||
v: v1,
|
||||
}
|
||||
v2v := Value{
|
||||
ty: r.Type,
|
||||
v: v2,
|
||||
}
|
||||
|
||||
if v1v.RawEquals(v2v) { // Easy case: if they are equal then v1 can't be less
|
||||
return false
|
||||
}
|
||||
|
||||
// Null values always sort after non-null values
|
||||
if v2v.IsNull() && !v1v.IsNull() {
|
||||
return true
|
||||
} else if v1v.IsNull() {
|
||||
return false
|
||||
}
|
||||
// Unknown values always sort after known values
|
||||
if v1v.IsKnown() && !v2v.IsKnown() {
|
||||
return true
|
||||
} else if !v1v.IsKnown() {
|
||||
return false
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case String:
|
||||
// String values sort lexicographically
|
||||
return v1v.AsString() < v2v.AsString()
|
||||
case Bool:
|
||||
// Weird to have a set of bools, but if we do then false sorts before true.
|
||||
if v2v.True() || !v1v.True() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
case Number:
|
||||
v1f := v1v.AsBigFloat()
|
||||
v2f := v2v.AsBigFloat()
|
||||
return v1f.Cmp(v2f) < 0
|
||||
default:
|
||||
// No other types have a well-defined ordering, so we just produce a
|
||||
// default consistent-but-undefined ordering then. This situation is
|
||||
// not considered a compatibility constraint; callers should rely only
|
||||
// on the ordering rules for primitive values.
|
||||
v1h, _ := makeSetHashBytes(v1v)
|
||||
v2h, _ := makeSetHashBytes(v2v)
|
||||
return bytes.Compare(v1h, v2h) < 0
|
||||
}
|
||||
}
|
||||
|
||||
func makeSetHashBytes(val Value) ([]byte, ValueMarks) {
|
||||
var buf bytes.Buffer
|
||||
marks := make(ValueMarks)
|
||||
appendSetHashBytes(val, &buf, marks)
|
||||
return buf.Bytes(), marks
|
||||
}
|
||||
|
||||
func appendSetHashBytes(val Value, buf *bytes.Buffer, marks ValueMarks) {
|
||||
// Exactly what bytes we generate here don't matter as long as the following
|
||||
// constraints hold:
|
||||
// - Unknown and null values all generate distinct strings from
|
||||
// each other and from any normal value of the given type.
|
||||
// - The delimiter used to separate items in a compound structure can
|
||||
// never appear literally in any of its elements.
|
||||
// Since we don't support hetrogenous lists we don't need to worry about
|
||||
// collisions between values of different types, apart from
|
||||
// PseudoTypeDynamic.
|
||||
// If in practice we *do* get a collision then it's not a big deal because
|
||||
// the Equivalent function will still distinguish values, but set
|
||||
// performance will be best if we are able to produce a distinct string
|
||||
// for each distinct value, unknown values notwithstanding.
|
||||
|
||||
// Marks aren't considered part of a value for equality-testing purposes,
|
||||
// so we'll unmark our value before we work with it but we'll remember
|
||||
// the marks in case the caller needs to re-apply them to a derived
|
||||
// value.
|
||||
if val.IsMarked() {
|
||||
unmarkedVal, valMarks := val.Unmark()
|
||||
for m := range valMarks {
|
||||
marks[m] = struct{}{}
|
||||
}
|
||||
val = unmarkedVal
|
||||
}
|
||||
|
||||
if !val.IsKnown() {
|
||||
buf.WriteRune('?')
|
||||
return
|
||||
}
|
||||
if val.IsNull() {
|
||||
buf.WriteRune('~')
|
||||
return
|
||||
}
|
||||
|
||||
switch val.ty {
|
||||
case Number:
|
||||
// Due to an unfortunate quirk of gob encoding for big.Float, we end up
|
||||
// with non-pointer values immediately after a gob round-trip, and
|
||||
// we end up in here before we've had a chance to run
|
||||
// gobDecodeFixNumberPtr on the inner values of a gob-encoded set,
|
||||
// and so sadly we must make a special effort to handle that situation
|
||||
// here just so that we can get far enough along to fix it up for
|
||||
// everything else in this package.
|
||||
if bf, ok := val.v.(big.Float); ok {
|
||||
buf.WriteString(bf.String())
|
||||
return
|
||||
}
|
||||
buf.WriteString(val.v.(*big.Float).String())
|
||||
return
|
||||
case Bool:
|
||||
if val.v.(bool) {
|
||||
buf.WriteRune('T')
|
||||
} else {
|
||||
buf.WriteRune('F')
|
||||
}
|
||||
return
|
||||
case String:
|
||||
buf.WriteString(fmt.Sprintf("%q", val.v.(string)))
|
||||
return
|
||||
}
|
||||
|
||||
if val.ty.IsMapType() {
|
||||
buf.WriteRune('{')
|
||||
val.ForEachElement(func(keyVal, elementVal Value) bool {
|
||||
appendSetHashBytes(keyVal, buf, marks)
|
||||
buf.WriteRune(':')
|
||||
appendSetHashBytes(elementVal, buf, marks)
|
||||
buf.WriteRune(';')
|
||||
return false
|
||||
})
|
||||
buf.WriteRune('}')
|
||||
return
|
||||
}
|
||||
|
||||
if val.ty.IsListType() || val.ty.IsSetType() {
|
||||
buf.WriteRune('[')
|
||||
val.ForEachElement(func(keyVal, elementVal Value) bool {
|
||||
appendSetHashBytes(elementVal, buf, marks)
|
||||
buf.WriteRune(';')
|
||||
return false
|
||||
})
|
||||
buf.WriteRune(']')
|
||||
return
|
||||
}
|
||||
|
||||
if val.ty.IsObjectType() {
|
||||
buf.WriteRune('<')
|
||||
attrNames := make([]string, 0, len(val.ty.AttributeTypes()))
|
||||
for attrName := range val.ty.AttributeTypes() {
|
||||
attrNames = append(attrNames, attrName)
|
||||
}
|
||||
sort.Strings(attrNames)
|
||||
for _, attrName := range attrNames {
|
||||
appendSetHashBytes(val.GetAttr(attrName), buf, marks)
|
||||
buf.WriteRune(';')
|
||||
}
|
||||
buf.WriteRune('>')
|
||||
return
|
||||
}
|
||||
|
||||
if val.ty.IsTupleType() {
|
||||
buf.WriteRune('<')
|
||||
val.ForEachElement(func(keyVal, elementVal Value) bool {
|
||||
appendSetHashBytes(elementVal, buf, marks)
|
||||
buf.WriteRune(';')
|
||||
return false
|
||||
})
|
||||
buf.WriteRune('>')
|
||||
return
|
||||
}
|
||||
|
||||
// should never get down here
|
||||
panic("unsupported type in set hash")
|
||||
}
|
72
vendor/github.com/zclconf/go-cty/cty/set_type.go
generated
vendored
Normal file
72
vendor/github.com/zclconf/go-cty/cty/set_type.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type typeSet struct {
|
||||
typeImplSigil
|
||||
ElementTypeT Type
|
||||
}
|
||||
|
||||
// Set creates a set type with the given element Type.
|
||||
//
|
||||
// Set types are CollectionType implementations.
|
||||
func Set(elem Type) Type {
|
||||
return Type{
|
||||
typeSet{
|
||||
ElementTypeT: elem,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Equals returns true if the other Type is a set whose element type is
|
||||
// equal to that of the receiver.
|
||||
func (t typeSet) Equals(other Type) bool {
|
||||
ot, isSet := other.typeImpl.(typeSet)
|
||||
if !isSet {
|
||||
return false
|
||||
}
|
||||
|
||||
return t.ElementTypeT.Equals(ot.ElementTypeT)
|
||||
}
|
||||
|
||||
func (t typeSet) FriendlyName(mode friendlyTypeNameMode) string {
|
||||
elemName := t.ElementTypeT.friendlyNameMode(mode)
|
||||
if mode == friendlyTypeConstraintName {
|
||||
if t.ElementTypeT == DynamicPseudoType {
|
||||
elemName = "any single type"
|
||||
}
|
||||
}
|
||||
return "set of " + elemName
|
||||
}
|
||||
|
||||
func (t typeSet) ElementType() Type {
|
||||
return t.ElementTypeT
|
||||
}
|
||||
|
||||
func (t typeSet) GoString() string {
|
||||
return fmt.Sprintf("cty.Set(%#v)", t.ElementTypeT)
|
||||
}
|
||||
|
||||
// IsSetType returns true if the given type is a list type, regardless of its
|
||||
// element type.
|
||||
func (t Type) IsSetType() bool {
|
||||
_, ok := t.typeImpl.(typeSet)
|
||||
return ok
|
||||
}
|
||||
|
||||
// SetElementType is a convenience method that checks if the given type is
|
||||
// a set type, returning a pointer to its element type if so and nil
|
||||
// otherwise. This is intended to allow convenient conditional branches,
|
||||
// like so:
|
||||
//
|
||||
// if et := t.SetElementType(); et != nil {
|
||||
// // Do something with *et
|
||||
// }
|
||||
func (t Type) SetElementType() *Type {
|
||||
if lt, ok := t.typeImpl.(typeSet); ok {
|
||||
return <.ElementTypeT
|
||||
}
|
||||
return nil
|
||||
}
|
121
vendor/github.com/zclconf/go-cty/cty/tuple_type.go
generated
vendored
Normal file
121
vendor/github.com/zclconf/go-cty/cty/tuple_type.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type typeTuple struct {
|
||||
typeImplSigil
|
||||
ElemTypes []Type
|
||||
}
|
||||
|
||||
// Tuple creates a tuple type with the given element types.
|
||||
//
|
||||
// After a slice is passed to this function the caller must no longer access
|
||||
// the underlying array, since ownership is transferred to this library.
|
||||
func Tuple(elemTypes []Type) Type {
|
||||
return Type{
|
||||
typeTuple{
|
||||
ElemTypes: elemTypes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t typeTuple) Equals(other Type) bool {
|
||||
if ot, ok := other.typeImpl.(typeTuple); ok {
|
||||
if len(t.ElemTypes) != len(ot.ElemTypes) {
|
||||
// Fast path: if we don't have the same number of elements
|
||||
// then we can't possibly be equal.
|
||||
return false
|
||||
}
|
||||
|
||||
for i, ty := range t.ElemTypes {
|
||||
oty := ot.ElemTypes[i]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if !oty.Equals(ty) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t typeTuple) FriendlyName(mode friendlyTypeNameMode) string {
|
||||
// There isn't really a friendly way to write a tuple type due to its
|
||||
// complexity, so we'll just do something English-ish. Callers will
|
||||
// probably want to make some extra effort to avoid ever printing out
|
||||
// a tuple type FriendlyName in its entirety. For example, could
|
||||
// produce an error message by diffing two object types and saying
|
||||
// something like "Expected attribute foo to be string, but got number".
|
||||
// TODO: Finish this
|
||||
return "tuple"
|
||||
}
|
||||
|
||||
func (t typeTuple) GoString() string {
|
||||
if len(t.ElemTypes) == 0 {
|
||||
return "cty.EmptyTuple"
|
||||
}
|
||||
return fmt.Sprintf("cty.Tuple(%#v)", t.ElemTypes)
|
||||
}
|
||||
|
||||
// EmptyTuple is a shorthand for Tuple([]Type{}), to more easily talk about
|
||||
// the empty tuple type.
|
||||
var EmptyTuple Type
|
||||
|
||||
// EmptyTupleVal is the only possible non-null, non-unknown value of type
|
||||
// EmptyTuple.
|
||||
var EmptyTupleVal Value
|
||||
|
||||
func init() {
|
||||
EmptyTuple = Tuple([]Type{})
|
||||
EmptyTupleVal = Value{
|
||||
ty: EmptyTuple,
|
||||
v: []interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
// IsTupleType returns true if the given type is an object type, regardless
|
||||
// of its element type.
|
||||
func (t Type) IsTupleType() bool {
|
||||
_, ok := t.typeImpl.(typeTuple)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Length returns the number of elements of the receiving tuple type.
|
||||
// Will panic if the reciever isn't a tuple type; use IsTupleType to determine
|
||||
// whether this operation will succeed.
|
||||
func (t Type) Length() int {
|
||||
if ot, ok := t.typeImpl.(typeTuple); ok {
|
||||
return len(ot.ElemTypes)
|
||||
}
|
||||
panic("Length on non-tuple Type")
|
||||
}
|
||||
|
||||
// TupleElementType returns the type of the element with the given index. Will
|
||||
// panic if the receiver is not a tuple type (use IsTupleType to confirm)
|
||||
// or if the index is out of range (use Length to confirm).
|
||||
func (t Type) TupleElementType(idx int) Type {
|
||||
if ot, ok := t.typeImpl.(typeTuple); ok {
|
||||
return ot.ElemTypes[idx]
|
||||
}
|
||||
panic("TupleElementType on non-tuple Type")
|
||||
}
|
||||
|
||||
// TupleElementTypes returns a slice of the recieving tuple type's element
|
||||
// types. Will panic if the receiver is not a tuple type (use IsTupleType
|
||||
// to confirm).
|
||||
//
|
||||
// The returned slice is part of the internal state of the type, and is provided
|
||||
// for read access only. It is forbidden for any caller to modify the
|
||||
// underlying array. For many purposes the element-related methods of Value
|
||||
// are more appropriate and more convenient to use.
|
||||
func (t Type) TupleElementTypes() []Type {
|
||||
if ot, ok := t.typeImpl.(typeTuple); ok {
|
||||
return ot.ElemTypes
|
||||
}
|
||||
panic("TupleElementTypes on non-tuple Type")
|
||||
}
|
120
vendor/github.com/zclconf/go-cty/cty/type.go
generated
vendored
Normal file
120
vendor/github.com/zclconf/go-cty/cty/type.go
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
package cty
|
||||
|
||||
// Type represents value types within the type system.
|
||||
//
|
||||
// This is a closed interface type, meaning that only the concrete
|
||||
// implementations provided within this package are considered valid.
|
||||
type Type struct {
|
||||
typeImpl
|
||||
}
|
||||
|
||||
type typeImpl interface {
|
||||
// isTypeImpl is a do-nothing method that exists only to express
|
||||
// that a type is an implementation of typeImpl.
|
||||
isTypeImpl() typeImplSigil
|
||||
|
||||
// Equals returns true if the other given Type exactly equals the
|
||||
// receiver Type.
|
||||
Equals(other Type) bool
|
||||
|
||||
// FriendlyName returns a human-friendly *English* name for the given
|
||||
// type.
|
||||
FriendlyName(mode friendlyTypeNameMode) string
|
||||
|
||||
// GoString implements the GoStringer interface from package fmt.
|
||||
GoString() string
|
||||
}
|
||||
|
||||
// Base implementation of Type to embed into concrete implementations
|
||||
// to signal that they are implementations of Type.
|
||||
type typeImplSigil struct{}
|
||||
|
||||
func (t typeImplSigil) isTypeImpl() typeImplSigil {
|
||||
return typeImplSigil{}
|
||||
}
|
||||
|
||||
// Equals returns true if the other given Type exactly equals the receiver
|
||||
// type.
|
||||
func (t Type) Equals(other Type) bool {
|
||||
return t.typeImpl.Equals(other)
|
||||
}
|
||||
|
||||
// FriendlyName returns a human-friendly *English* name for the given type.
|
||||
func (t Type) FriendlyName() string {
|
||||
return t.typeImpl.FriendlyName(friendlyTypeName)
|
||||
}
|
||||
|
||||
// FriendlyNameForConstraint is similar to FriendlyName except that the
|
||||
// result is specialized for describing type _constraints_ rather than types
|
||||
// themselves. This is more appropriate when reporting that a particular value
|
||||
// does not conform to an expected type constraint.
|
||||
//
|
||||
// In particular, this function uses the term "any type" to refer to
|
||||
// cty.DynamicPseudoType, rather than "dynamic" as returned by FriendlyName.
|
||||
func (t Type) FriendlyNameForConstraint() string {
|
||||
return t.typeImpl.FriendlyName(friendlyTypeConstraintName)
|
||||
}
|
||||
|
||||
// friendlyNameMode is an internal combination of the various FriendlyName*
|
||||
// variants that just directly takes a mode, for easy passthrough for
|
||||
// recursive name construction.
|
||||
func (t Type) friendlyNameMode(mode friendlyTypeNameMode) string {
|
||||
return t.typeImpl.FriendlyName(mode)
|
||||
}
|
||||
|
||||
// GoString returns a string approximating how the receiver type would be
|
||||
// expressed in Go source code.
|
||||
func (t Type) GoString() string {
|
||||
if t.typeImpl == nil {
|
||||
return "cty.NilType"
|
||||
}
|
||||
|
||||
return t.typeImpl.GoString()
|
||||
}
|
||||
|
||||
// NilType is an invalid type used when a function is returning an error
|
||||
// and has no useful type to return. It should not be used and any methods
|
||||
// called on it will panic.
|
||||
var NilType = Type{}
|
||||
|
||||
// HasDynamicTypes returns true either if the receiver is itself
|
||||
// DynamicPseudoType or if it is a compound type whose descendent elements
|
||||
// are DynamicPseudoType.
|
||||
func (t Type) HasDynamicTypes() bool {
|
||||
switch {
|
||||
case t == DynamicPseudoType:
|
||||
return true
|
||||
case t.IsPrimitiveType():
|
||||
return false
|
||||
case t.IsCollectionType():
|
||||
return false
|
||||
case t.IsObjectType():
|
||||
attrTypes := t.AttributeTypes()
|
||||
for _, at := range attrTypes {
|
||||
if at.HasDynamicTypes() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case t.IsTupleType():
|
||||
elemTypes := t.TupleElementTypes()
|
||||
for _, et := range elemTypes {
|
||||
if et.HasDynamicTypes() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case t.IsCapsuleType():
|
||||
return false
|
||||
default:
|
||||
// Should never happen, since above should be exhaustive
|
||||
panic("HasDynamicTypes does not support the given type")
|
||||
}
|
||||
}
|
||||
|
||||
type friendlyTypeNameMode rune
|
||||
|
||||
const (
|
||||
friendlyTypeName friendlyTypeNameMode = 'N'
|
||||
friendlyTypeConstraintName friendlyTypeNameMode = 'C'
|
||||
)
|
139
vendor/github.com/zclconf/go-cty/cty/type_conform.go
generated
vendored
Normal file
139
vendor/github.com/zclconf/go-cty/cty/type_conform.go
generated
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
package cty
|
||||
|
||||
// TestConformance recursively walks the receiver and the given other type and
|
||||
// returns nil if the receiver *conforms* to the given type.
|
||||
//
|
||||
// Type conformance is similar to type equality but has one crucial difference:
|
||||
// PseudoTypeDynamic can be used within the given type to represent that
|
||||
// *any* type is allowed.
|
||||
//
|
||||
// If any non-conformities are found, the returned slice will be non-nil and
|
||||
// contain at least one error value. It will be nil if the type is entirely
|
||||
// conformant.
|
||||
//
|
||||
// Note that the special behavior of PseudoTypeDynamic is the *only* exception
|
||||
// to normal type equality. Calling applications may wish to apply their own
|
||||
// automatic conversion logic to the given data structure to create a more
|
||||
// liberal notion of conformance to a type.
|
||||
//
|
||||
// Returned errors are usually (but not always) PathError instances that
|
||||
// indicate where in the structure the error was found. If a returned error
|
||||
// is of that type then the error message is written for (English-speaking)
|
||||
// end-users working within the cty type system, not mentioning any Go-oriented
|
||||
// implementation details.
|
||||
func (t Type) TestConformance(other Type) []error {
|
||||
path := make(Path, 0)
|
||||
var errs []error
|
||||
testConformance(t, other, path, &errs)
|
||||
return errs
|
||||
}
|
||||
|
||||
func testConformance(given Type, want Type, path Path, errs *[]error) {
|
||||
if want.Equals(DynamicPseudoType) {
|
||||
// anything goes!
|
||||
return
|
||||
}
|
||||
|
||||
if given.Equals(want) {
|
||||
// Any equal types are always conformant
|
||||
return
|
||||
}
|
||||
|
||||
// The remainder of this function is concerned with detecting
|
||||
// and reporting the specific non-conformance, since we wouldn't
|
||||
// have got here if the types were not divergent.
|
||||
// We treat compound structures as special so that we can report
|
||||
// specifically what is non-conforming, rather than simply returning
|
||||
// the entire type names and letting the user puzzle it out.
|
||||
|
||||
if given.IsObjectType() && want.IsObjectType() {
|
||||
givenAttrs := given.AttributeTypes()
|
||||
wantAttrs := want.AttributeTypes()
|
||||
|
||||
for k := range givenAttrs {
|
||||
if _, exists := wantAttrs[k]; !exists {
|
||||
*errs = append(
|
||||
*errs,
|
||||
errorf(path, "unsupported attribute %q", k),
|
||||
)
|
||||
}
|
||||
}
|
||||
for k := range wantAttrs {
|
||||
if _, exists := givenAttrs[k]; !exists {
|
||||
*errs = append(
|
||||
*errs,
|
||||
errorf(path, "missing required attribute %q", k),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
path = append(path, nil)
|
||||
pathIdx := len(path) - 1
|
||||
|
||||
for k, wantAttrType := range wantAttrs {
|
||||
if givenAttrType, exists := givenAttrs[k]; exists {
|
||||
path[pathIdx] = GetAttrStep{Name: k}
|
||||
testConformance(givenAttrType, wantAttrType, path, errs)
|
||||
}
|
||||
}
|
||||
|
||||
path = path[0:pathIdx]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if given.IsTupleType() && want.IsTupleType() {
|
||||
givenElems := given.TupleElementTypes()
|
||||
wantElems := want.TupleElementTypes()
|
||||
|
||||
if len(givenElems) != len(wantElems) {
|
||||
*errs = append(
|
||||
*errs,
|
||||
errorf(path, "%d elements are required, but got %d", len(wantElems), len(givenElems)),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
path = append(path, nil)
|
||||
pathIdx := len(path) - 1
|
||||
|
||||
for i, wantElemType := range wantElems {
|
||||
givenElemType := givenElems[i]
|
||||
path[pathIdx] = IndexStep{Key: NumberIntVal(int64(i))}
|
||||
testConformance(givenElemType, wantElemType, path, errs)
|
||||
}
|
||||
|
||||
path = path[0:pathIdx]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if given.IsListType() && want.IsListType() {
|
||||
path = append(path, IndexStep{Key: UnknownVal(Number)})
|
||||
pathIdx := len(path) - 1
|
||||
testConformance(given.ElementType(), want.ElementType(), path, errs)
|
||||
path = path[0:pathIdx]
|
||||
return
|
||||
}
|
||||
|
||||
if given.IsMapType() && want.IsMapType() {
|
||||
path = append(path, IndexStep{Key: UnknownVal(String)})
|
||||
pathIdx := len(path) - 1
|
||||
testConformance(given.ElementType(), want.ElementType(), path, errs)
|
||||
path = path[0:pathIdx]
|
||||
return
|
||||
}
|
||||
|
||||
if given.IsSetType() && want.IsSetType() {
|
||||
path = append(path, IndexStep{Key: UnknownVal(given.ElementType())})
|
||||
pathIdx := len(path) - 1
|
||||
testConformance(given.ElementType(), want.ElementType(), path, errs)
|
||||
path = path[0:pathIdx]
|
||||
return
|
||||
}
|
||||
|
||||
*errs = append(
|
||||
*errs,
|
||||
errorf(path, "%s required, but received %s", want.FriendlyName(), given.FriendlyName()),
|
||||
)
|
||||
}
|
57
vendor/github.com/zclconf/go-cty/cty/types_to_register.go
generated
vendored
Normal file
57
vendor/github.com/zclconf/go-cty/cty/types_to_register.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/zclconf/go-cty/cty/set"
|
||||
)
|
||||
|
||||
// InternalTypesToRegister is a slice of values that covers all of the
|
||||
// internal types used in the representation of cty.Type and cty.Value
|
||||
// across all cty Types.
|
||||
//
|
||||
// This is intended to be used to register these types with encoding
|
||||
// packages that require registration of types used in interfaces, such as
|
||||
// encoding/gob, thus allowing cty types and values to be included in streams
|
||||
// created from those packages. However, registering with gob is not necessary
|
||||
// since that is done automatically as a side-effect of importing this package.
|
||||
//
|
||||
// Callers should not do anything with the values here except pass them on
|
||||
// verbatim to a registration function.
|
||||
//
|
||||
// If the calling application uses Capsule types that wrap local structs either
|
||||
// directly or indirectly, these structs may also need to be registered in
|
||||
// order to support encoding and decoding of values of these types. That is the
|
||||
// responsibility of the calling application.
|
||||
var InternalTypesToRegister []interface{}
|
||||
|
||||
func init() {
|
||||
InternalTypesToRegister = []interface{}{
|
||||
primitiveType{},
|
||||
typeList{},
|
||||
typeMap{},
|
||||
typeObject{},
|
||||
typeSet{},
|
||||
setRules{},
|
||||
set.Set{},
|
||||
typeTuple{},
|
||||
big.Float{},
|
||||
capsuleType{},
|
||||
[]interface{}(nil),
|
||||
map[string]interface{}(nil),
|
||||
}
|
||||
|
||||
// Register these with gob here, rather than in gob.go, to ensure
|
||||
// that this will always happen after we build the above.
|
||||
for _, tv := range InternalTypesToRegister {
|
||||
typeName := fmt.Sprintf("%T", tv)
|
||||
if strings.HasPrefix(typeName, "cty.") {
|
||||
gob.RegisterName(fmt.Sprintf("github.com/zclconf/go-cty/%s", typeName), tv)
|
||||
} else {
|
||||
gob.Register(tv)
|
||||
}
|
||||
}
|
||||
}
|
84
vendor/github.com/zclconf/go-cty/cty/unknown.go
generated
vendored
Normal file
84
vendor/github.com/zclconf/go-cty/cty/unknown.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
package cty
|
||||
|
||||
// unknownType is the placeholder type used for the sigil value representing
|
||||
// "Unknown", to make it unambigiously distinct from any other possible value.
|
||||
type unknownType struct {
|
||||
}
|
||||
|
||||
// Unknown is a special value that can be
|
||||
var unknown interface{} = &unknownType{}
|
||||
|
||||
// UnknownVal returns an Value that represents an unknown value of the given
|
||||
// type. Unknown values can be used to represent a value that is
|
||||
// not yet known. Its meaning is undefined in cty, but it could be used by
|
||||
// an calling application to allow partial evaluation.
|
||||
//
|
||||
// Unknown values of any type can be created of any type. All operations on
|
||||
// Unknown values themselves return Unknown.
|
||||
func UnknownVal(t Type) Value {
|
||||
return Value{
|
||||
ty: t,
|
||||
v: unknown,
|
||||
}
|
||||
}
|
||||
|
||||
func (t unknownType) GoString() string {
|
||||
// This is the stringification of our internal unknown marker. The
|
||||
// stringification of the public representation of unknowns is in
|
||||
// Value.GoString.
|
||||
return "cty.unknown"
|
||||
}
|
||||
|
||||
type pseudoTypeDynamic struct {
|
||||
typeImplSigil
|
||||
}
|
||||
|
||||
// DynamicPseudoType represents the dynamic pseudo-type.
|
||||
//
|
||||
// This type can represent situations where a type is not yet known. Its
|
||||
// meaning is undefined in cty, but it could be used by a calling
|
||||
// application to allow expression type checking with some types not yet known.
|
||||
// For example, the application might optimistically permit any operation on
|
||||
// values of this type in type checking, allowing a partial type-check result,
|
||||
// and then repeat the check when more information is known to get the
|
||||
// final, concrete type.
|
||||
//
|
||||
// It is a pseudo-type because it is used only as a sigil to the calling
|
||||
// application. "Unknown" is the only valid value of this pseudo-type, so
|
||||
// operations on values of this type will always short-circuit as per
|
||||
// the rules for that special value.
|
||||
var DynamicPseudoType Type
|
||||
|
||||
func (t pseudoTypeDynamic) Equals(other Type) bool {
|
||||
_, ok := other.typeImpl.(pseudoTypeDynamic)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (t pseudoTypeDynamic) FriendlyName(mode friendlyTypeNameMode) string {
|
||||
switch mode {
|
||||
case friendlyTypeConstraintName:
|
||||
return "any type"
|
||||
default:
|
||||
return "dynamic"
|
||||
}
|
||||
}
|
||||
|
||||
func (t pseudoTypeDynamic) GoString() string {
|
||||
return "cty.DynamicPseudoType"
|
||||
}
|
||||
|
||||
// DynamicVal is the only valid value of the pseudo-type dynamic.
|
||||
// This value can be used as a placeholder where a value or expression's
|
||||
// type and value are both unknown, thus allowing partial evaluation. See
|
||||
// the docs for DynamicPseudoType for more information.
|
||||
var DynamicVal Value
|
||||
|
||||
func init() {
|
||||
DynamicPseudoType = Type{
|
||||
pseudoTypeDynamic{},
|
||||
}
|
||||
DynamicVal = Value{
|
||||
ty: DynamicPseudoType,
|
||||
v: unknown,
|
||||
}
|
||||
}
|
64
vendor/github.com/zclconf/go-cty/cty/unknown_as_null.go
generated
vendored
Normal file
64
vendor/github.com/zclconf/go-cty/cty/unknown_as_null.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
package cty
|
||||
|
||||
// UnknownAsNull returns a value of the same type as the given value but
|
||||
// with any unknown values (including nested values) replaced with null
|
||||
// values of the same type.
|
||||
//
|
||||
// This can be useful if a result is to be serialized in a format that can't
|
||||
// represent unknowns, such as JSON, as long as the caller does not need to
|
||||
// retain the unknown value information.
|
||||
func UnknownAsNull(val Value) Value {
|
||||
ty := val.Type()
|
||||
switch {
|
||||
case val.IsNull():
|
||||
return val
|
||||
case !val.IsKnown():
|
||||
return NullVal(ty)
|
||||
case ty.IsListType() || ty.IsTupleType() || ty.IsSetType():
|
||||
length := val.LengthInt()
|
||||
if length == 0 {
|
||||
// If there are no elements then we can't have unknowns
|
||||
return val
|
||||
}
|
||||
vals := make([]Value, 0, length)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, v := it.Element()
|
||||
vals = append(vals, UnknownAsNull(v))
|
||||
}
|
||||
switch {
|
||||
case ty.IsListType():
|
||||
return ListVal(vals)
|
||||
case ty.IsTupleType():
|
||||
return TupleVal(vals)
|
||||
default:
|
||||
return SetVal(vals)
|
||||
}
|
||||
case ty.IsMapType() || ty.IsObjectType():
|
||||
var length int
|
||||
switch {
|
||||
case ty.IsMapType():
|
||||
length = val.LengthInt()
|
||||
default:
|
||||
length = len(val.Type().AttributeTypes())
|
||||
}
|
||||
if length == 0 {
|
||||
// If there are no elements then we can't have unknowns
|
||||
return val
|
||||
}
|
||||
vals := make(map[string]Value, length)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
k, v := it.Element()
|
||||
vals[k.AsString()] = UnknownAsNull(v)
|
||||
}
|
||||
switch {
|
||||
case ty.IsMapType():
|
||||
return MapVal(vals)
|
||||
default:
|
||||
return ObjectVal(vals)
|
||||
}
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
108
vendor/github.com/zclconf/go-cty/cty/value.go
generated
vendored
Normal file
108
vendor/github.com/zclconf/go-cty/cty/value.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
package cty
|
||||
|
||||
// Value represents a value of a particular type, and is the interface by
|
||||
// which operations are executed on typed values.
|
||||
//
|
||||
// Value has two different classes of method. Operation methods stay entirely
|
||||
// within the type system (methods accept and return Value instances) and
|
||||
// are intended for use in implementing a language in terms of cty, while
|
||||
// integration methods either enter or leave the type system, working with
|
||||
// native Go values. Operation methods are guaranteed to support all of the
|
||||
// expected short-circuit behavior for unknown and dynamic values, while
|
||||
// integration methods may not.
|
||||
//
|
||||
// The philosophy for the operations API is that it's the caller's
|
||||
// responsibility to ensure that the given types and values satisfy the
|
||||
// specified invariants during a separate type check, so that the caller is
|
||||
// able to return errors to its user from the application's own perspective.
|
||||
//
|
||||
// Consequently the design of these methods assumes such checks have already
|
||||
// been done and panics if any invariants turn out not to be satisfied. These
|
||||
// panic errors are not intended to be handled, but rather indicate a bug in
|
||||
// the calling application that should be fixed with more checks prior to
|
||||
// executing operations.
|
||||
//
|
||||
// A related consequence of this philosophy is that no automatic type
|
||||
// conversions are done. If a method specifies that its argument must be
|
||||
// number then it's the caller's responsibility to do that conversion before
|
||||
// the call, thus allowing the application to have more constrained conversion
|
||||
// rules than are offered by the built-in converter where necessary.
|
||||
type Value struct {
|
||||
ty Type
|
||||
v interface{}
|
||||
}
|
||||
|
||||
// Type returns the type of the value.
|
||||
func (val Value) Type() Type {
|
||||
return val.ty
|
||||
}
|
||||
|
||||
// IsKnown returns true if the value is known. That is, if it is not
|
||||
// the result of the unknown value constructor Unknown(...), and is not
|
||||
// the result of an operation on another unknown value.
|
||||
//
|
||||
// Unknown values are only produced either directly or as a result of
|
||||
// operating on other unknown values, and so an application that never
|
||||
// introduces Unknown values can be guaranteed to never receive any either.
|
||||
func (val Value) IsKnown() bool {
|
||||
if val.IsMarked() {
|
||||
return val.unmarkForce().IsKnown()
|
||||
}
|
||||
return val.v != unknown
|
||||
}
|
||||
|
||||
// IsNull returns true if the value is null. Values of any type can be
|
||||
// null, but any operations on a null value will panic. No operation ever
|
||||
// produces null, so an application that never introduces Null values can
|
||||
// be guaranteed to never receive any either.
|
||||
func (val Value) IsNull() bool {
|
||||
if val.IsMarked() {
|
||||
return val.unmarkForce().IsNull()
|
||||
}
|
||||
return val.v == nil
|
||||
}
|
||||
|
||||
// NilVal is an invalid Value that can be used as a placeholder when returning
|
||||
// with an error from a function that returns (Value, error).
|
||||
//
|
||||
// NilVal is *not* a valid error and so no operations may be performed on it.
|
||||
// Any attempt to use it will result in a panic.
|
||||
//
|
||||
// This should not be confused with the idea of a Null value, as returned by
|
||||
// NullVal. NilVal is a nil within the *Go* type system, and is invalid in
|
||||
// the cty type system. Null values *do* exist in the cty type system.
|
||||
var NilVal = Value{
|
||||
ty: Type{typeImpl: nil},
|
||||
v: nil,
|
||||
}
|
||||
|
||||
// IsWhollyKnown is an extension of IsKnown that also recursively checks
|
||||
// inside collections and structures to see if there are any nested unknown
|
||||
// values.
|
||||
func (val Value) IsWhollyKnown() bool {
|
||||
if val.IsMarked() {
|
||||
return val.unmarkForce().IsWhollyKnown()
|
||||
}
|
||||
|
||||
if !val.IsKnown() {
|
||||
return false
|
||||
}
|
||||
|
||||
if val.IsNull() {
|
||||
// Can't recurse into a null, so we're done
|
||||
return true
|
||||
}
|
||||
|
||||
switch {
|
||||
case val.CanIterateElements():
|
||||
for it := val.ElementIterator(); it.Next(); {
|
||||
_, ev := it.Element()
|
||||
if !ev.IsWhollyKnown() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
324
vendor/github.com/zclconf/go-cty/cty/value_init.go
generated
vendored
Normal file
324
vendor/github.com/zclconf/go-cty/cty/value_init.go
generated
vendored
Normal file
@ -0,0 +1,324 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
|
||||
"golang.org/x/text/unicode/norm"
|
||||
|
||||
"github.com/zclconf/go-cty/cty/set"
|
||||
)
|
||||
|
||||
// BoolVal returns a Value of type Number whose internal value is the given
|
||||
// bool.
|
||||
func BoolVal(v bool) Value {
|
||||
return Value{
|
||||
ty: Bool,
|
||||
v: v,
|
||||
}
|
||||
}
|
||||
|
||||
// NumberVal returns a Value of type Number whose internal value is the given
|
||||
// big.Float. The returned value becomes the owner of the big.Float object,
|
||||
// and so it's forbidden for the caller to mutate the object after it's
|
||||
// wrapped in this way.
|
||||
func NumberVal(v *big.Float) Value {
|
||||
return Value{
|
||||
ty: Number,
|
||||
v: v,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseNumberVal returns a Value of type number produced by parsing the given
|
||||
// string as a decimal real number. To ensure that two identical strings will
|
||||
// always produce an equal number, always use this function to derive a number
|
||||
// from a string; it will ensure that the precision and rounding mode for the
|
||||
// internal big decimal is configured in a consistent way.
|
||||
//
|
||||
// If the given string cannot be parsed as a number, the returned error has
|
||||
// the message "a number is required", making it suitable to return to an
|
||||
// end-user to signal a type conversion error.
|
||||
//
|
||||
// If the given string contains a number that becomes a recurring fraction
|
||||
// when expressed in binary then it will be truncated to have a 512-bit
|
||||
// mantissa. Note that this is a higher precision than that of a float64,
|
||||
// so coverting the same decimal number first to float64 and then calling
|
||||
// NumberFloatVal will not produce an equal result; the conversion first
|
||||
// to float64 will round the mantissa to fewer than 512 bits.
|
||||
func ParseNumberVal(s string) (Value, error) {
|
||||
// Base 10, precision 512, and rounding to nearest even is the standard
|
||||
// way to handle numbers arriving as strings.
|
||||
f, _, err := big.ParseFloat(s, 10, 512, big.ToNearestEven)
|
||||
if err != nil {
|
||||
return NilVal, fmt.Errorf("a number is required")
|
||||
}
|
||||
return NumberVal(f), nil
|
||||
}
|
||||
|
||||
// MustParseNumberVal is like ParseNumberVal but it will panic in case of any
|
||||
// error. It can be used during initialization or any other situation where
|
||||
// the given string is a constant or otherwise known to be correct by the
|
||||
// caller.
|
||||
func MustParseNumberVal(s string) Value {
|
||||
ret, err := ParseNumberVal(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// NumberIntVal returns a Value of type Number whose internal value is equal
|
||||
// to the given integer.
|
||||
func NumberIntVal(v int64) Value {
|
||||
return NumberVal(new(big.Float).SetInt64(v))
|
||||
}
|
||||
|
||||
// NumberUIntVal returns a Value of type Number whose internal value is equal
|
||||
// to the given unsigned integer.
|
||||
func NumberUIntVal(v uint64) Value {
|
||||
return NumberVal(new(big.Float).SetUint64(v))
|
||||
}
|
||||
|
||||
// NumberFloatVal returns a Value of type Number whose internal value is
|
||||
// equal to the given float.
|
||||
func NumberFloatVal(v float64) Value {
|
||||
return NumberVal(new(big.Float).SetFloat64(v))
|
||||
}
|
||||
|
||||
// StringVal returns a Value of type String whose internal value is the
|
||||
// given string.
|
||||
//
|
||||
// Strings must be UTF-8 encoded sequences of valid unicode codepoints, and
|
||||
// they are NFC-normalized on entry into the world of cty values.
|
||||
//
|
||||
// If the given string is not valid UTF-8 then behavior of string operations
|
||||
// is undefined.
|
||||
func StringVal(v string) Value {
|
||||
return Value{
|
||||
ty: String,
|
||||
v: NormalizeString(v),
|
||||
}
|
||||
}
|
||||
|
||||
// NormalizeString applies the same normalization that cty applies when
|
||||
// constructing string values.
|
||||
//
|
||||
// A return value from this function can be meaningfully compared byte-for-byte
|
||||
// with a Value.AsString result.
|
||||
func NormalizeString(s string) string {
|
||||
return norm.NFC.String(s)
|
||||
}
|
||||
|
||||
// ObjectVal returns a Value of an object type whose structure is defined
|
||||
// by the key names and value types in the given map.
|
||||
func ObjectVal(attrs map[string]Value) Value {
|
||||
attrTypes := make(map[string]Type, len(attrs))
|
||||
attrVals := make(map[string]interface{}, len(attrs))
|
||||
|
||||
for attr, val := range attrs {
|
||||
attr = NormalizeString(attr)
|
||||
attrTypes[attr] = val.ty
|
||||
attrVals[attr] = val.v
|
||||
}
|
||||
|
||||
return Value{
|
||||
ty: Object(attrTypes),
|
||||
v: attrVals,
|
||||
}
|
||||
}
|
||||
|
||||
// TupleVal returns a Value of a tuple type whose element types are
|
||||
// defined by the value types in the given slice.
|
||||
func TupleVal(elems []Value) Value {
|
||||
elemTypes := make([]Type, len(elems))
|
||||
elemVals := make([]interface{}, len(elems))
|
||||
|
||||
for i, val := range elems {
|
||||
elemTypes[i] = val.ty
|
||||
elemVals[i] = val.v
|
||||
}
|
||||
|
||||
return Value{
|
||||
ty: Tuple(elemTypes),
|
||||
v: elemVals,
|
||||
}
|
||||
}
|
||||
|
||||
// ListVal returns a Value of list type whose element type is defined by
|
||||
// the types of the given values, which must be homogenous.
|
||||
//
|
||||
// If the types are not all consistent (aside from elements that are of the
|
||||
// dynamic pseudo-type) then this function will panic. It will panic also
|
||||
// if the given list is empty, since then the element type cannot be inferred.
|
||||
// (See also ListValEmpty.)
|
||||
func ListVal(vals []Value) Value {
|
||||
if len(vals) == 0 {
|
||||
panic("must not call ListVal with empty slice")
|
||||
}
|
||||
elementType := DynamicPseudoType
|
||||
rawList := make([]interface{}, len(vals))
|
||||
|
||||
for i, val := range vals {
|
||||
if elementType == DynamicPseudoType {
|
||||
elementType = val.ty
|
||||
} else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) {
|
||||
panic(fmt.Errorf(
|
||||
"inconsistent list element types (%#v then %#v)",
|
||||
elementType, val.ty,
|
||||
))
|
||||
}
|
||||
|
||||
rawList[i] = val.v
|
||||
}
|
||||
|
||||
return Value{
|
||||
ty: List(elementType),
|
||||
v: rawList,
|
||||
}
|
||||
}
|
||||
|
||||
// ListValEmpty returns an empty list of the given element type.
|
||||
func ListValEmpty(element Type) Value {
|
||||
return Value{
|
||||
ty: List(element),
|
||||
v: []interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
// MapVal returns a Value of a map type whose element type is defined by
|
||||
// the types of the given values, which must be homogenous.
|
||||
//
|
||||
// If the types are not all consistent (aside from elements that are of the
|
||||
// dynamic pseudo-type) then this function will panic. It will panic also
|
||||
// if the given map is empty, since then the element type cannot be inferred.
|
||||
// (See also MapValEmpty.)
|
||||
func MapVal(vals map[string]Value) Value {
|
||||
if len(vals) == 0 {
|
||||
panic("must not call MapVal with empty map")
|
||||
}
|
||||
elementType := DynamicPseudoType
|
||||
rawMap := make(map[string]interface{}, len(vals))
|
||||
|
||||
for key, val := range vals {
|
||||
if elementType == DynamicPseudoType {
|
||||
elementType = val.ty
|
||||
} else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) {
|
||||
panic(fmt.Errorf(
|
||||
"inconsistent map element types (%#v then %#v)",
|
||||
elementType, val.ty,
|
||||
))
|
||||
}
|
||||
|
||||
rawMap[NormalizeString(key)] = val.v
|
||||
}
|
||||
|
||||
return Value{
|
||||
ty: Map(elementType),
|
||||
v: rawMap,
|
||||
}
|
||||
}
|
||||
|
||||
// MapValEmpty returns an empty map of the given element type.
|
||||
func MapValEmpty(element Type) Value {
|
||||
return Value{
|
||||
ty: Map(element),
|
||||
v: map[string]interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
// SetVal returns a Value of set type whose element type is defined by
|
||||
// the types of the given values, which must be homogenous.
|
||||
//
|
||||
// If the types are not all consistent (aside from elements that are of the
|
||||
// dynamic pseudo-type) then this function will panic. It will panic also
|
||||
// if the given list is empty, since then the element type cannot be inferred.
|
||||
// (See also SetValEmpty.)
|
||||
func SetVal(vals []Value) Value {
|
||||
if len(vals) == 0 {
|
||||
panic("must not call SetVal with empty slice")
|
||||
}
|
||||
elementType := DynamicPseudoType
|
||||
rawList := make([]interface{}, len(vals))
|
||||
var markSets []ValueMarks
|
||||
|
||||
for i, val := range vals {
|
||||
if unmarkedVal, marks := val.UnmarkDeep(); len(marks) > 0 {
|
||||
val = unmarkedVal
|
||||
markSets = append(markSets, marks)
|
||||
}
|
||||
if val.ContainsMarked() {
|
||||
// FIXME: Allow this, but unmark the values and apply the
|
||||
// marking to the set itself instead.
|
||||
panic("set cannot contain marked values")
|
||||
}
|
||||
if elementType == DynamicPseudoType {
|
||||
elementType = val.ty
|
||||
} else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) {
|
||||
panic(fmt.Errorf(
|
||||
"inconsistent set element types (%#v then %#v)",
|
||||
elementType, val.ty,
|
||||
))
|
||||
}
|
||||
|
||||
rawList[i] = val.v
|
||||
}
|
||||
|
||||
rawVal := set.NewSetFromSlice(setRules{elementType}, rawList)
|
||||
|
||||
return Value{
|
||||
ty: Set(elementType),
|
||||
v: rawVal,
|
||||
}.WithMarks(markSets...)
|
||||
}
|
||||
|
||||
// SetValFromValueSet returns a Value of set type based on an already-constructed
|
||||
// ValueSet.
|
||||
//
|
||||
// The element type of the returned value is the element type of the given
|
||||
// set.
|
||||
func SetValFromValueSet(s ValueSet) Value {
|
||||
ety := s.ElementType()
|
||||
rawVal := s.s.Copy() // copy so caller can't mutate what we wrap
|
||||
|
||||
return Value{
|
||||
ty: Set(ety),
|
||||
v: rawVal,
|
||||
}
|
||||
}
|
||||
|
||||
// SetValEmpty returns an empty set of the given element type.
|
||||
func SetValEmpty(element Type) Value {
|
||||
return Value{
|
||||
ty: Set(element),
|
||||
v: set.NewSet(setRules{element}),
|
||||
}
|
||||
}
|
||||
|
||||
// CapsuleVal creates a value of the given capsule type using the given
|
||||
// wrapVal, which must be a pointer to a value of the capsule type's native
|
||||
// type.
|
||||
//
|
||||
// This function will panic if the given type is not a capsule type, if
|
||||
// the given wrapVal is not compatible with the given capsule type, or if
|
||||
// wrapVal is not a pointer.
|
||||
func CapsuleVal(ty Type, wrapVal interface{}) Value {
|
||||
if !ty.IsCapsuleType() {
|
||||
panic("not a capsule type")
|
||||
}
|
||||
|
||||
wv := reflect.ValueOf(wrapVal)
|
||||
if wv.Kind() != reflect.Ptr {
|
||||
panic("wrapVal is not a pointer")
|
||||
}
|
||||
|
||||
it := ty.typeImpl.(*capsuleType).GoType
|
||||
if !wv.Type().Elem().AssignableTo(it) {
|
||||
panic("wrapVal target is not compatible with the given capsule type")
|
||||
}
|
||||
|
||||
return Value{
|
||||
ty: ty,
|
||||
v: wrapVal,
|
||||
}
|
||||
}
|
1290
vendor/github.com/zclconf/go-cty/cty/value_ops.go
generated
vendored
Normal file
1290
vendor/github.com/zclconf/go-cty/cty/value_ops.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
182
vendor/github.com/zclconf/go-cty/cty/walk.go
generated
vendored
Normal file
182
vendor/github.com/zclconf/go-cty/cty/walk.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
package cty
|
||||
|
||||
// Walk visits all of the values in a possibly-complex structure, calling
|
||||
// a given function for each value.
|
||||
//
|
||||
// For example, given a list of strings the callback would first be called
|
||||
// with the whole list and then called once for each element of the list.
|
||||
//
|
||||
// The callback function may prevent recursive visits to child values by
|
||||
// returning false. The callback function my halt the walk altogether by
|
||||
// returning a non-nil error. If the returned error is about the element
|
||||
// currently being visited, it is recommended to use the provided path
|
||||
// value to produce a PathError describing that context.
|
||||
//
|
||||
// The path passed to the given function may not be used after that function
|
||||
// returns, since its backing array is re-used for other calls.
|
||||
func Walk(val Value, cb func(Path, Value) (bool, error)) error {
|
||||
var path Path
|
||||
return walk(path, val, cb)
|
||||
}
|
||||
|
||||
func walk(path Path, val Value, cb func(Path, Value) (bool, error)) error {
|
||||
deeper, err := cb(path, val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !deeper {
|
||||
return nil
|
||||
}
|
||||
|
||||
if val.IsNull() || !val.IsKnown() {
|
||||
// Can't recurse into null or unknown values, regardless of type
|
||||
return nil
|
||||
}
|
||||
|
||||
ty := val.Type()
|
||||
switch {
|
||||
case ty.IsObjectType():
|
||||
for it := val.ElementIterator(); it.Next(); {
|
||||
nameVal, av := it.Element()
|
||||
path := append(path, GetAttrStep{
|
||||
Name: nameVal.AsString(),
|
||||
})
|
||||
err := walk(path, av, cb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case val.CanIterateElements():
|
||||
for it := val.ElementIterator(); it.Next(); {
|
||||
kv, ev := it.Element()
|
||||
path := append(path, IndexStep{
|
||||
Key: kv,
|
||||
})
|
||||
err := walk(path, ev, cb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Transform visits all of the values in a possibly-complex structure,
|
||||
// calling a given function for each value which has an opportunity to
|
||||
// replace that value.
|
||||
//
|
||||
// Unlike Walk, Transform visits child nodes first, so for a list of strings
|
||||
// it would first visit the strings and then the _new_ list constructed
|
||||
// from the transformed values of the list items.
|
||||
//
|
||||
// This is useful for creating the effect of being able to make deep mutations
|
||||
// to a value even though values are immutable. However, it's the responsibility
|
||||
// of the given function to preserve expected invariants, such as homogenity of
|
||||
// element types in collections; this function can panic if such invariants
|
||||
// are violated, just as if new values were constructed directly using the
|
||||
// value constructor functions. An easy way to preserve invariants is to
|
||||
// ensure that the transform function never changes the value type.
|
||||
//
|
||||
// The callback function my halt the walk altogether by
|
||||
// returning a non-nil error. If the returned error is about the element
|
||||
// currently being visited, it is recommended to use the provided path
|
||||
// value to produce a PathError describing that context.
|
||||
//
|
||||
// The path passed to the given function may not be used after that function
|
||||
// returns, since its backing array is re-used for other calls.
|
||||
func Transform(val Value, cb func(Path, Value) (Value, error)) (Value, error) {
|
||||
var path Path
|
||||
return transform(path, val, cb)
|
||||
}
|
||||
|
||||
func transform(path Path, val Value, cb func(Path, Value) (Value, error)) (Value, error) {
|
||||
ty := val.Type()
|
||||
var newVal Value
|
||||
|
||||
switch {
|
||||
|
||||
case val.IsNull() || !val.IsKnown():
|
||||
// Can't recurse into null or unknown values, regardless of type
|
||||
newVal = val
|
||||
|
||||
case ty.IsListType() || ty.IsSetType() || ty.IsTupleType():
|
||||
l := val.LengthInt()
|
||||
switch l {
|
||||
case 0:
|
||||
// No deep transform for an empty sequence
|
||||
newVal = val
|
||||
default:
|
||||
elems := make([]Value, 0, l)
|
||||
for it := val.ElementIterator(); it.Next(); {
|
||||
kv, ev := it.Element()
|
||||
path := append(path, IndexStep{
|
||||
Key: kv,
|
||||
})
|
||||
newEv, err := transform(path, ev, cb)
|
||||
if err != nil {
|
||||
return DynamicVal, err
|
||||
}
|
||||
elems = append(elems, newEv)
|
||||
}
|
||||
switch {
|
||||
case ty.IsListType():
|
||||
newVal = ListVal(elems)
|
||||
case ty.IsSetType():
|
||||
newVal = SetVal(elems)
|
||||
case ty.IsTupleType():
|
||||
newVal = TupleVal(elems)
|
||||
default:
|
||||
panic("unknown sequence type") // should never happen because of the case we are in
|
||||
}
|
||||
}
|
||||
|
||||
case ty.IsMapType():
|
||||
l := val.LengthInt()
|
||||
switch l {
|
||||
case 0:
|
||||
// No deep transform for an empty map
|
||||
newVal = val
|
||||
default:
|
||||
elems := make(map[string]Value)
|
||||
for it := val.ElementIterator(); it.Next(); {
|
||||
kv, ev := it.Element()
|
||||
path := append(path, IndexStep{
|
||||
Key: kv,
|
||||
})
|
||||
newEv, err := transform(path, ev, cb)
|
||||
if err != nil {
|
||||
return DynamicVal, err
|
||||
}
|
||||
elems[kv.AsString()] = newEv
|
||||
}
|
||||
newVal = MapVal(elems)
|
||||
}
|
||||
|
||||
case ty.IsObjectType():
|
||||
switch {
|
||||
case ty.Equals(EmptyObject):
|
||||
// No deep transform for an empty object
|
||||
newVal = val
|
||||
default:
|
||||
atys := ty.AttributeTypes()
|
||||
newAVs := make(map[string]Value)
|
||||
for name := range atys {
|
||||
av := val.GetAttr(name)
|
||||
path := append(path, GetAttrStep{
|
||||
Name: name,
|
||||
})
|
||||
newAV, err := transform(path, av, cb)
|
||||
if err != nil {
|
||||
return DynamicVal, err
|
||||
}
|
||||
newAVs[name] = newAV
|
||||
}
|
||||
newVal = ObjectVal(newAVs)
|
||||
}
|
||||
|
||||
default:
|
||||
newVal = val
|
||||
}
|
||||
|
||||
return cb(path, newVal)
|
||||
}
|
Reference in New Issue
Block a user