mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			549 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			549 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package gocty
 | 
						|
 | 
						|
import (
 | 
						|
	"math/big"
 | 
						|
	"reflect"
 | 
						|
 | 
						|
	"github.com/zclconf/go-cty/cty"
 | 
						|
	"github.com/zclconf/go-cty/cty/convert"
 | 
						|
	"github.com/zclconf/go-cty/cty/set"
 | 
						|
)
 | 
						|
 | 
						|
// ToCtyValue produces a cty.Value from a Go value. The result will conform
 | 
						|
// to the given type, or an error will be returned if this is not possible.
 | 
						|
//
 | 
						|
// The target type serves as a hint to resolve ambiguities in the mapping.
 | 
						|
// For example, the Go type set.Set tells us that the value is a set but
 | 
						|
// does not describe the set's element type. This also allows for convenient
 | 
						|
// conversions, such as populating a set from a slice rather than having to
 | 
						|
// first explicitly instantiate a set.Set.
 | 
						|
//
 | 
						|
// The audience of this function is assumed to be the developers of Go code
 | 
						|
// that is integrating with cty, and thus the error messages it returns are
 | 
						|
// presented from Go's perspective. These messages are thus not appropriate
 | 
						|
// for display to end-users. An error returned from ToCtyValue represents a
 | 
						|
// bug in the calling program, not user error.
 | 
						|
func ToCtyValue(val interface{}, ty cty.Type) (cty.Value, error) {
 | 
						|
	// 'path' starts off as empty but will grow for each level of recursive
 | 
						|
	// call we make, so by the time toCtyValue returns it is likely to have
 | 
						|
	// unused capacity on the end of it, depending on how deeply-recursive
 | 
						|
	// the given Type is.
 | 
						|
	path := make(cty.Path, 0)
 | 
						|
	return toCtyValue(reflect.ValueOf(val), ty, path)
 | 
						|
}
 | 
						|
 | 
						|
func toCtyValue(val reflect.Value, ty cty.Type, path cty.Path) (cty.Value, error) {
 | 
						|
	if val != (reflect.Value{}) && val.Type().AssignableTo(valueType) {
 | 
						|
		// If the source value is a cty.Value then we'll try to just pass
 | 
						|
		// through to the target type directly.
 | 
						|
		return toCtyPassthrough(val, ty, path)
 | 
						|
	}
 | 
						|
 | 
						|
	switch ty {
 | 
						|
	case cty.Bool:
 | 
						|
		return toCtyBool(val, path)
 | 
						|
	case cty.Number:
 | 
						|
		return toCtyNumber(val, path)
 | 
						|
	case cty.String:
 | 
						|
		return toCtyString(val, path)
 | 
						|
	case cty.DynamicPseudoType:
 | 
						|
		return toCtyDynamic(val, path)
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case ty.IsListType():
 | 
						|
		return toCtyList(val, ty.ElementType(), path)
 | 
						|
	case ty.IsMapType():
 | 
						|
		return toCtyMap(val, ty.ElementType(), path)
 | 
						|
	case ty.IsSetType():
 | 
						|
		return toCtySet(val, ty.ElementType(), path)
 | 
						|
	case ty.IsObjectType():
 | 
						|
		return toCtyObject(val, ty.AttributeTypes(), path)
 | 
						|
	case ty.IsTupleType():
 | 
						|
		return toCtyTuple(val, ty.TupleElementTypes(), path)
 | 
						|
	case ty.IsCapsuleType():
 | 
						|
		return toCtyCapsule(val, ty, path)
 | 
						|
	}
 | 
						|
 | 
						|
	// We should never fall out here
 | 
						|
	return cty.NilVal, path.NewErrorf("unsupported target type %#v", ty)
 | 
						|
}
 | 
						|
 | 
						|
func toCtyBool(val reflect.Value, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(cty.Bool), nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch val.Kind() {
 | 
						|
 | 
						|
	case reflect.Bool:
 | 
						|
		return cty.BoolVal(val.Bool()), nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return cty.NilVal, path.NewErrorf("can't convert Go %s to bool", val.Kind())
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
func toCtyNumber(val reflect.Value, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(cty.Number), nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch val.Kind() {
 | 
						|
 | 
						|
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						|
		return cty.NumberIntVal(val.Int()), nil
 | 
						|
 | 
						|
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
						|
		return cty.NumberUIntVal(val.Uint()), nil
 | 
						|
 | 
						|
	case reflect.Float32, reflect.Float64:
 | 
						|
		return cty.NumberFloatVal(val.Float()), nil
 | 
						|
 | 
						|
	case reflect.Struct:
 | 
						|
		if val.Type().AssignableTo(bigIntType) {
 | 
						|
			bigInt := val.Interface().(big.Int)
 | 
						|
			bigFloat := (&big.Float{}).SetInt(&bigInt)
 | 
						|
			val = reflect.ValueOf(*bigFloat)
 | 
						|
		}
 | 
						|
 | 
						|
		if val.Type().AssignableTo(bigFloatType) {
 | 
						|
			bigFloat := val.Interface().(big.Float)
 | 
						|
			return cty.NumberVal(&bigFloat), nil
 | 
						|
		}
 | 
						|
 | 
						|
		fallthrough
 | 
						|
	default:
 | 
						|
		return cty.NilVal, path.NewErrorf("can't convert Go %s to number", val.Kind())
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
func toCtyString(val reflect.Value, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(cty.String), nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch val.Kind() {
 | 
						|
 | 
						|
	case reflect.String:
 | 
						|
		return cty.StringVal(val.String()), nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return cty.NilVal, path.NewErrorf("can't convert Go %s to string", val.Kind())
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
func toCtyList(val reflect.Value, ety cty.Type, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(cty.List(ety)), nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch val.Kind() {
 | 
						|
 | 
						|
	case reflect.Slice:
 | 
						|
		if val.IsNil() {
 | 
						|
			return cty.NullVal(cty.List(ety)), nil
 | 
						|
		}
 | 
						|
		fallthrough
 | 
						|
	case reflect.Array:
 | 
						|
		if val.Len() == 0 {
 | 
						|
			return cty.ListValEmpty(ety), nil
 | 
						|
		}
 | 
						|
 | 
						|
		// While we work on our elements we'll temporarily grow
 | 
						|
		// path to give us a place to put our index step.
 | 
						|
		path = append(path, cty.PathStep(nil))
 | 
						|
 | 
						|
		vals := make([]cty.Value, val.Len())
 | 
						|
		for i := range vals {
 | 
						|
			var err error
 | 
						|
			path[len(path)-1] = cty.IndexStep{
 | 
						|
				Key: cty.NumberIntVal(int64(i)),
 | 
						|
			}
 | 
						|
			vals[i], err = toCtyValue(val.Index(i), ety, path)
 | 
						|
			if err != nil {
 | 
						|
				return cty.NilVal, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Discard our extra path segment, retaining it as extra capacity
 | 
						|
		// for future appending to the path.
 | 
						|
		path = path[:len(path)-1]
 | 
						|
 | 
						|
		return cty.ListVal(vals), nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.List(ety))
 | 
						|
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func toCtyMap(val reflect.Value, ety cty.Type, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(cty.Map(ety)), nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch val.Kind() {
 | 
						|
 | 
						|
	case reflect.Map:
 | 
						|
		if val.IsNil() {
 | 
						|
			return cty.NullVal(cty.Map(ety)), nil
 | 
						|
		}
 | 
						|
 | 
						|
		if val.Len() == 0 {
 | 
						|
			return cty.MapValEmpty(ety), nil
 | 
						|
		}
 | 
						|
 | 
						|
		keyType := val.Type().Key()
 | 
						|
		if keyType.Kind() != reflect.String {
 | 
						|
			return cty.NilVal, path.NewErrorf("can't convert Go map with key type %s; key type must be string", keyType)
 | 
						|
		}
 | 
						|
 | 
						|
		// While we work on our elements we'll temporarily grow
 | 
						|
		// path to give us a place to put our index step.
 | 
						|
		path = append(path, cty.PathStep(nil))
 | 
						|
 | 
						|
		vals := make(map[string]cty.Value, val.Len())
 | 
						|
		for _, kv := range val.MapKeys() {
 | 
						|
			k := kv.String()
 | 
						|
			var err error
 | 
						|
			path[len(path)-1] = cty.IndexStep{
 | 
						|
				Key: cty.StringVal(k),
 | 
						|
			}
 | 
						|
			vals[k], err = toCtyValue(val.MapIndex(reflect.ValueOf(k)), ety, path)
 | 
						|
			if err != nil {
 | 
						|
				return cty.NilVal, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Discard our extra path segment, retaining it as extra capacity
 | 
						|
		// for future appending to the path.
 | 
						|
		path = path[:len(path)-1]
 | 
						|
 | 
						|
		return cty.MapVal(vals), nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Map(ety))
 | 
						|
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func toCtySet(val reflect.Value, ety cty.Type, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(cty.Set(ety)), nil
 | 
						|
	}
 | 
						|
 | 
						|
	var vals []cty.Value
 | 
						|
 | 
						|
	switch val.Kind() {
 | 
						|
 | 
						|
	case reflect.Slice:
 | 
						|
		if val.IsNil() {
 | 
						|
			return cty.NullVal(cty.Set(ety)), nil
 | 
						|
		}
 | 
						|
		fallthrough
 | 
						|
	case reflect.Array:
 | 
						|
		if val.Len() == 0 {
 | 
						|
			return cty.SetValEmpty(ety), nil
 | 
						|
		}
 | 
						|
 | 
						|
		vals = make([]cty.Value, val.Len())
 | 
						|
		for i := range vals {
 | 
						|
			var err error
 | 
						|
			vals[i], err = toCtyValue(val.Index(i), ety, path)
 | 
						|
			if err != nil {
 | 
						|
				return cty.NilVal, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
	case reflect.Struct:
 | 
						|
 | 
						|
		if !val.Type().AssignableTo(setType) {
 | 
						|
			return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Type(), cty.Set(ety))
 | 
						|
		}
 | 
						|
 | 
						|
		rawSet := val.Interface().(set.Set)
 | 
						|
		inVals := rawSet.Values()
 | 
						|
 | 
						|
		if len(inVals) == 0 {
 | 
						|
			return cty.SetValEmpty(ety), nil
 | 
						|
		}
 | 
						|
 | 
						|
		vals = make([]cty.Value, len(inVals))
 | 
						|
		for i := range inVals {
 | 
						|
			var err error
 | 
						|
			vals[i], err = toCtyValue(reflect.ValueOf(inVals[i]), ety, path)
 | 
						|
			if err != nil {
 | 
						|
				return cty.NilVal, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
	default:
 | 
						|
		return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Set(ety))
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	return cty.SetVal(vals), nil
 | 
						|
}
 | 
						|
 | 
						|
func toCtyObject(val reflect.Value, attrTypes map[string]cty.Type, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(cty.Object(attrTypes)), nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch val.Kind() {
 | 
						|
 | 
						|
	case reflect.Map:
 | 
						|
		if val.IsNil() {
 | 
						|
			return cty.NullVal(cty.Object(attrTypes)), nil
 | 
						|
		}
 | 
						|
 | 
						|
		keyType := val.Type().Key()
 | 
						|
		if keyType.Kind() != reflect.String {
 | 
						|
			return cty.NilVal, path.NewErrorf("can't convert Go map with key type %s; key type must be string", keyType)
 | 
						|
		}
 | 
						|
 | 
						|
		if len(attrTypes) == 0 {
 | 
						|
			return cty.EmptyObjectVal, nil
 | 
						|
		}
 | 
						|
 | 
						|
		// While we work on our elements we'll temporarily grow
 | 
						|
		// path to give us a place to put our GetAttr step.
 | 
						|
		path = append(path, cty.PathStep(nil))
 | 
						|
 | 
						|
		haveKeys := make(map[string]struct{}, val.Len())
 | 
						|
		for _, kv := range val.MapKeys() {
 | 
						|
			haveKeys[kv.String()] = struct{}{}
 | 
						|
		}
 | 
						|
 | 
						|
		vals := make(map[string]cty.Value, len(attrTypes))
 | 
						|
		for k, at := range attrTypes {
 | 
						|
			var err error
 | 
						|
			path[len(path)-1] = cty.GetAttrStep{
 | 
						|
				Name: k,
 | 
						|
			}
 | 
						|
 | 
						|
			if _, have := haveKeys[k]; !have {
 | 
						|
				vals[k] = cty.NullVal(at)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			vals[k], err = toCtyValue(val.MapIndex(reflect.ValueOf(k)), at, path)
 | 
						|
			if err != nil {
 | 
						|
				return cty.NilVal, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Discard our extra path segment, retaining it as extra capacity
 | 
						|
		// for future appending to the path.
 | 
						|
		path = path[:len(path)-1]
 | 
						|
 | 
						|
		return cty.ObjectVal(vals), nil
 | 
						|
 | 
						|
	case reflect.Struct:
 | 
						|
		if len(attrTypes) == 0 {
 | 
						|
			return cty.EmptyObjectVal, nil
 | 
						|
		}
 | 
						|
 | 
						|
		// While we work on our elements we'll temporarily grow
 | 
						|
		// path to give us a place to put our GetAttr step.
 | 
						|
		path = append(path, cty.PathStep(nil))
 | 
						|
 | 
						|
		attrFields := structTagIndices(val.Type())
 | 
						|
 | 
						|
		vals := make(map[string]cty.Value, len(attrTypes))
 | 
						|
		for k, at := range attrTypes {
 | 
						|
			path[len(path)-1] = cty.GetAttrStep{
 | 
						|
				Name: k,
 | 
						|
			}
 | 
						|
 | 
						|
			if fieldIdx, have := attrFields[k]; have {
 | 
						|
				var err error
 | 
						|
				vals[k], err = toCtyValue(val.Field(fieldIdx), at, path)
 | 
						|
				if err != nil {
 | 
						|
					return cty.NilVal, err
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				vals[k] = cty.NullVal(at)
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Discard our extra path segment, retaining it as extra capacity
 | 
						|
		// for future appending to the path.
 | 
						|
		path = path[:len(path)-1]
 | 
						|
 | 
						|
		return cty.ObjectVal(vals), nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Object(attrTypes))
 | 
						|
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func toCtyTuple(val reflect.Value, elemTypes []cty.Type, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(cty.Tuple(elemTypes)), nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch val.Kind() {
 | 
						|
 | 
						|
	case reflect.Slice:
 | 
						|
		if val.IsNil() {
 | 
						|
			return cty.NullVal(cty.Tuple(elemTypes)), nil
 | 
						|
		}
 | 
						|
 | 
						|
		if val.Len() != len(elemTypes) {
 | 
						|
			return cty.NilVal, path.NewErrorf("wrong number of elements %d; need %d", val.Len(), len(elemTypes))
 | 
						|
		}
 | 
						|
 | 
						|
		if len(elemTypes) == 0 {
 | 
						|
			return cty.EmptyTupleVal, nil
 | 
						|
		}
 | 
						|
 | 
						|
		// While we work on our elements we'll temporarily grow
 | 
						|
		// path to give us a place to put our Index step.
 | 
						|
		path = append(path, cty.PathStep(nil))
 | 
						|
 | 
						|
		vals := make([]cty.Value, len(elemTypes))
 | 
						|
		for i, ety := range elemTypes {
 | 
						|
			var err error
 | 
						|
 | 
						|
			path[len(path)-1] = cty.IndexStep{
 | 
						|
				Key: cty.NumberIntVal(int64(i)),
 | 
						|
			}
 | 
						|
 | 
						|
			vals[i], err = toCtyValue(val.Index(i), ety, path)
 | 
						|
			if err != nil {
 | 
						|
				return cty.NilVal, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Discard our extra path segment, retaining it as extra capacity
 | 
						|
		// for future appending to the path.
 | 
						|
		path = path[:len(path)-1]
 | 
						|
 | 
						|
		return cty.TupleVal(vals), nil
 | 
						|
 | 
						|
	case reflect.Struct:
 | 
						|
		fieldCount := val.Type().NumField()
 | 
						|
		if fieldCount != len(elemTypes) {
 | 
						|
			return cty.NilVal, path.NewErrorf("wrong number of struct fields %d; need %d", fieldCount, len(elemTypes))
 | 
						|
		}
 | 
						|
 | 
						|
		if len(elemTypes) == 0 {
 | 
						|
			return cty.EmptyTupleVal, nil
 | 
						|
		}
 | 
						|
 | 
						|
		// While we work on our elements we'll temporarily grow
 | 
						|
		// path to give us a place to put our Index step.
 | 
						|
		path = append(path, cty.PathStep(nil))
 | 
						|
 | 
						|
		vals := make([]cty.Value, len(elemTypes))
 | 
						|
		for i, ety := range elemTypes {
 | 
						|
			var err error
 | 
						|
 | 
						|
			path[len(path)-1] = cty.IndexStep{
 | 
						|
				Key: cty.NumberIntVal(int64(i)),
 | 
						|
			}
 | 
						|
 | 
						|
			vals[i], err = toCtyValue(val.Field(i), ety, path)
 | 
						|
			if err != nil {
 | 
						|
				return cty.NilVal, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Discard our extra path segment, retaining it as extra capacity
 | 
						|
		// for future appending to the path.
 | 
						|
		path = path[:len(path)-1]
 | 
						|
 | 
						|
		return cty.TupleVal(vals), nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Tuple(elemTypes))
 | 
						|
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func toCtyCapsule(val reflect.Value, capsuleType cty.Type, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(capsuleType), nil
 | 
						|
	}
 | 
						|
 | 
						|
	if val.Kind() != reflect.Ptr {
 | 
						|
		if !val.CanAddr() {
 | 
						|
			return cty.NilVal, path.NewErrorf("source value for capsule %#v must be addressable", capsuleType)
 | 
						|
		}
 | 
						|
 | 
						|
		val = val.Addr()
 | 
						|
	}
 | 
						|
 | 
						|
	if !val.Type().Elem().AssignableTo(capsuleType.EncapsulatedType()) {
 | 
						|
		return cty.NilVal, path.NewErrorf("value of type %T not compatible with capsule %#v", val.Interface(), capsuleType)
 | 
						|
	}
 | 
						|
 | 
						|
	return cty.CapsuleVal(capsuleType, val.Interface()), nil
 | 
						|
}
 | 
						|
 | 
						|
func toCtyDynamic(val reflect.Value, path cty.Path) (cty.Value, error) {
 | 
						|
	if val = toCtyUnwrapPointer(val); !val.IsValid() {
 | 
						|
		return cty.NullVal(cty.DynamicPseudoType), nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch val.Kind() {
 | 
						|
 | 
						|
	case reflect.Struct:
 | 
						|
		if !val.Type().AssignableTo(valueType) {
 | 
						|
			return cty.NilVal, path.NewErrorf("can't convert Go %s dynamically; only cty.Value allowed", val.Type())
 | 
						|
		}
 | 
						|
 | 
						|
		return val.Interface().(cty.Value), nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return cty.NilVal, path.NewErrorf("can't convert Go %s dynamically; only cty.Value allowed", val.Kind())
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
func toCtyPassthrough(wrappedVal reflect.Value, wantTy cty.Type, path cty.Path) (cty.Value, error) {
 | 
						|
	if wrappedVal = toCtyUnwrapPointer(wrappedVal); !wrappedVal.IsValid() {
 | 
						|
		return cty.NullVal(wantTy), nil
 | 
						|
	}
 | 
						|
 | 
						|
	givenVal := wrappedVal.Interface().(cty.Value)
 | 
						|
 | 
						|
	val, err := convert.Convert(givenVal, wantTy)
 | 
						|
	if err != nil {
 | 
						|
		return cty.NilVal, path.NewErrorf("unsuitable value: %s", err)
 | 
						|
	}
 | 
						|
	return val, nil
 | 
						|
}
 | 
						|
 | 
						|
// toCtyUnwrapPointer is a helper for dealing with Go pointers. It has three
 | 
						|
// possible outcomes:
 | 
						|
//
 | 
						|
// - Given value isn't a pointer, so it's just returned as-is.
 | 
						|
// - Given value is a non-nil pointer, in which case it is dereferenced
 | 
						|
//   and the result returned.
 | 
						|
// - Given value is a nil pointer, in which case an invalid value is returned.
 | 
						|
//
 | 
						|
// For nested pointer types, like **int, they are all dereferenced in turn
 | 
						|
// until a non-pointer value is found, or until a nil pointer is encountered.
 | 
						|
func toCtyUnwrapPointer(val reflect.Value) reflect.Value {
 | 
						|
	for val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface {
 | 
						|
		if val.IsNil() {
 | 
						|
			return reflect.Value{}
 | 
						|
		}
 | 
						|
 | 
						|
		val = val.Elem()
 | 
						|
	}
 | 
						|
 | 
						|
	return val
 | 
						|
}
 |