mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-09-06 17:16:44 +00:00
![Paddy](/assets/img/avatar_default.png)
Switch to using Go modules. This migrates our vendor.json to use Go 1.11's modules system, and replaces the vendor folder with the output of go mod vendor. The vendored code should remain basically the same; I believe some tree shaking of packages and support scripts/licenses/READMEs/etc. happened. This also fixes Travis and our Makefile to no longer use govendor.
310 lines
8.7 KiB
Go
310 lines
8.7 KiB
Go
// Copyright 2017, The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE.md file.
|
|
|
|
package cmp
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
type (
|
|
// Path is a list of PathSteps describing the sequence of operations to get
|
|
// from some root type to the current position in the value tree.
|
|
// The first Path element is always an operation-less PathStep that exists
|
|
// simply to identify the initial type.
|
|
//
|
|
// When traversing structs with embedded structs, the embedded struct will
|
|
// always be accessed as a field before traversing the fields of the
|
|
// embedded struct themselves. That is, an exported field from the
|
|
// embedded struct will never be accessed directly from the parent struct.
|
|
Path []PathStep
|
|
|
|
// PathStep is a union-type for specific operations to traverse
|
|
// a value's tree structure. Users of this package never need to implement
|
|
// these types as values of this type will be returned by this package.
|
|
PathStep interface {
|
|
String() string
|
|
Type() reflect.Type // Resulting type after performing the path step
|
|
isPathStep()
|
|
}
|
|
|
|
// SliceIndex is an index operation on a slice or array at some index Key.
|
|
SliceIndex interface {
|
|
PathStep
|
|
Key() int // May return -1 if in a split state
|
|
|
|
// SplitKeys returns the indexes for indexing into slices in the
|
|
// x and y values, respectively. These indexes may differ due to the
|
|
// insertion or removal of an element in one of the slices, causing
|
|
// all of the indexes to be shifted. If an index is -1, then that
|
|
// indicates that the element does not exist in the associated slice.
|
|
//
|
|
// Key is guaranteed to return -1 if and only if the indexes returned
|
|
// by SplitKeys are not the same. SplitKeys will never return -1 for
|
|
// both indexes.
|
|
SplitKeys() (x int, y int)
|
|
|
|
isSliceIndex()
|
|
}
|
|
// MapIndex is an index operation on a map at some index Key.
|
|
MapIndex interface {
|
|
PathStep
|
|
Key() reflect.Value
|
|
isMapIndex()
|
|
}
|
|
// TypeAssertion represents a type assertion on an interface.
|
|
TypeAssertion interface {
|
|
PathStep
|
|
isTypeAssertion()
|
|
}
|
|
// StructField represents a struct field access on a field called Name.
|
|
StructField interface {
|
|
PathStep
|
|
Name() string
|
|
Index() int
|
|
isStructField()
|
|
}
|
|
// Indirect represents pointer indirection on the parent type.
|
|
Indirect interface {
|
|
PathStep
|
|
isIndirect()
|
|
}
|
|
// Transform is a transformation from the parent type to the current type.
|
|
Transform interface {
|
|
PathStep
|
|
Name() string
|
|
Func() reflect.Value
|
|
|
|
// Option returns the originally constructed Transformer option.
|
|
// The == operator can be used to detect the exact option used.
|
|
Option() Option
|
|
|
|
isTransform()
|
|
}
|
|
)
|
|
|
|
func (pa *Path) push(s PathStep) {
|
|
*pa = append(*pa, s)
|
|
}
|
|
|
|
func (pa *Path) pop() {
|
|
*pa = (*pa)[:len(*pa)-1]
|
|
}
|
|
|
|
// Last returns the last PathStep in the Path.
|
|
// If the path is empty, this returns a non-nil PathStep that reports a nil Type.
|
|
func (pa Path) Last() PathStep {
|
|
return pa.Index(-1)
|
|
}
|
|
|
|
// Index returns the ith step in the Path and supports negative indexing.
|
|
// A negative index starts counting from the tail of the Path such that -1
|
|
// refers to the last step, -2 refers to the second-to-last step, and so on.
|
|
// If index is invalid, this returns a non-nil PathStep that reports a nil Type.
|
|
func (pa Path) Index(i int) PathStep {
|
|
if i < 0 {
|
|
i = len(pa) + i
|
|
}
|
|
if i < 0 || i >= len(pa) {
|
|
return pathStep{}
|
|
}
|
|
return pa[i]
|
|
}
|
|
|
|
// String returns the simplified path to a node.
|
|
// The simplified path only contains struct field accesses.
|
|
//
|
|
// For example:
|
|
// MyMap.MySlices.MyField
|
|
func (pa Path) String() string {
|
|
var ss []string
|
|
for _, s := range pa {
|
|
if _, ok := s.(*structField); ok {
|
|
ss = append(ss, s.String())
|
|
}
|
|
}
|
|
return strings.TrimPrefix(strings.Join(ss, ""), ".")
|
|
}
|
|
|
|
// GoString returns the path to a specific node using Go syntax.
|
|
//
|
|
// For example:
|
|
// (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField
|
|
func (pa Path) GoString() string {
|
|
var ssPre, ssPost []string
|
|
var numIndirect int
|
|
for i, s := range pa {
|
|
var nextStep PathStep
|
|
if i+1 < len(pa) {
|
|
nextStep = pa[i+1]
|
|
}
|
|
switch s := s.(type) {
|
|
case *indirect:
|
|
numIndirect++
|
|
pPre, pPost := "(", ")"
|
|
switch nextStep.(type) {
|
|
case *indirect:
|
|
continue // Next step is indirection, so let them batch up
|
|
case *structField:
|
|
numIndirect-- // Automatic indirection on struct fields
|
|
case nil:
|
|
pPre, pPost = "", "" // Last step; no need for parenthesis
|
|
}
|
|
if numIndirect > 0 {
|
|
ssPre = append(ssPre, pPre+strings.Repeat("*", numIndirect))
|
|
ssPost = append(ssPost, pPost)
|
|
}
|
|
numIndirect = 0
|
|
continue
|
|
case *transform:
|
|
ssPre = append(ssPre, s.trans.name+"(")
|
|
ssPost = append(ssPost, ")")
|
|
continue
|
|
case *typeAssertion:
|
|
// As a special-case, elide type assertions on anonymous types
|
|
// since they are typically generated dynamically and can be very
|
|
// verbose. For example, some transforms return interface{} because
|
|
// of Go's lack of generics, but typically take in and return the
|
|
// exact same concrete type.
|
|
if s.Type().PkgPath() == "" {
|
|
continue
|
|
}
|
|
}
|
|
ssPost = append(ssPost, s.String())
|
|
}
|
|
for i, j := 0, len(ssPre)-1; i < j; i, j = i+1, j-1 {
|
|
ssPre[i], ssPre[j] = ssPre[j], ssPre[i]
|
|
}
|
|
return strings.Join(ssPre, "") + strings.Join(ssPost, "")
|
|
}
|
|
|
|
type (
|
|
pathStep struct {
|
|
typ reflect.Type
|
|
}
|
|
|
|
sliceIndex struct {
|
|
pathStep
|
|
xkey, ykey int
|
|
}
|
|
mapIndex struct {
|
|
pathStep
|
|
key reflect.Value
|
|
}
|
|
typeAssertion struct {
|
|
pathStep
|
|
}
|
|
structField struct {
|
|
pathStep
|
|
name string
|
|
idx int
|
|
|
|
// These fields are used for forcibly accessing an unexported field.
|
|
// pvx, pvy, and field are only valid if unexported is true.
|
|
unexported bool
|
|
force bool // Forcibly allow visibility
|
|
pvx, pvy reflect.Value // Parent values
|
|
field reflect.StructField // Field information
|
|
}
|
|
indirect struct {
|
|
pathStep
|
|
}
|
|
transform struct {
|
|
pathStep
|
|
trans *transformer
|
|
}
|
|
)
|
|
|
|
func (ps pathStep) Type() reflect.Type { return ps.typ }
|
|
func (ps pathStep) String() string {
|
|
if ps.typ == nil {
|
|
return "<nil>"
|
|
}
|
|
s := ps.typ.String()
|
|
if s == "" || strings.ContainsAny(s, "{}\n") {
|
|
return "root" // Type too simple or complex to print
|
|
}
|
|
return fmt.Sprintf("{%s}", s)
|
|
}
|
|
|
|
func (si sliceIndex) String() string {
|
|
switch {
|
|
case si.xkey == si.ykey:
|
|
return fmt.Sprintf("[%d]", si.xkey)
|
|
case si.ykey == -1:
|
|
// [5->?] means "I don't know where X[5] went"
|
|
return fmt.Sprintf("[%d->?]", si.xkey)
|
|
case si.xkey == -1:
|
|
// [?->3] means "I don't know where Y[3] came from"
|
|
return fmt.Sprintf("[?->%d]", si.ykey)
|
|
default:
|
|
// [5->3] means "X[5] moved to Y[3]"
|
|
return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey)
|
|
}
|
|
}
|
|
func (mi mapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) }
|
|
func (ta typeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
|
|
func (sf structField) String() string { return fmt.Sprintf(".%s", sf.name) }
|
|
func (in indirect) String() string { return "*" }
|
|
func (tf transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
|
|
|
|
func (si sliceIndex) Key() int {
|
|
if si.xkey != si.ykey {
|
|
return -1
|
|
}
|
|
return si.xkey
|
|
}
|
|
func (si sliceIndex) SplitKeys() (x, y int) { return si.xkey, si.ykey }
|
|
func (mi mapIndex) Key() reflect.Value { return mi.key }
|
|
func (sf structField) Name() string { return sf.name }
|
|
func (sf structField) Index() int { return sf.idx }
|
|
func (tf transform) Name() string { return tf.trans.name }
|
|
func (tf transform) Func() reflect.Value { return tf.trans.fnc }
|
|
func (tf transform) Option() Option { return tf.trans }
|
|
|
|
func (pathStep) isPathStep() {}
|
|
func (sliceIndex) isSliceIndex() {}
|
|
func (mapIndex) isMapIndex() {}
|
|
func (typeAssertion) isTypeAssertion() {}
|
|
func (structField) isStructField() {}
|
|
func (indirect) isIndirect() {}
|
|
func (transform) isTransform() {}
|
|
|
|
var (
|
|
_ SliceIndex = sliceIndex{}
|
|
_ MapIndex = mapIndex{}
|
|
_ TypeAssertion = typeAssertion{}
|
|
_ StructField = structField{}
|
|
_ Indirect = indirect{}
|
|
_ Transform = transform{}
|
|
|
|
_ PathStep = sliceIndex{}
|
|
_ PathStep = mapIndex{}
|
|
_ PathStep = typeAssertion{}
|
|
_ PathStep = structField{}
|
|
_ PathStep = indirect{}
|
|
_ PathStep = transform{}
|
|
)
|
|
|
|
// isExported reports whether the identifier is exported.
|
|
func isExported(id string) bool {
|
|
r, _ := utf8.DecodeRuneInString(id)
|
|
return unicode.IsUpper(r)
|
|
}
|
|
|
|
// isValid reports whether the identifier is valid.
|
|
// Empty and underscore-only strings are not valid.
|
|
func isValid(id string) bool {
|
|
ok := id != "" && id != "_"
|
|
for j, c := range id {
|
|
ok = ok && (j > 0 || !unicode.IsDigit(c))
|
|
ok = ok && (c == '_' || unicode.IsLetter(c) || unicode.IsDigit(c))
|
|
}
|
|
return ok
|
|
}
|