diff options
Diffstat (limited to 'vendor/github.com/google/go-cmp/cmp/internal')
8 files changed, 955 insertions, 0 deletions
| diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go new file mode 100644 index 000000000..36062a604 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go @@ -0,0 +1,18 @@ +// 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 file. + +//go:build !cmp_debug +// +build !cmp_debug + +package diff + +var debug debugger + +type debugger struct{} + +func (debugger) Begin(_, _ int, f EqualFunc, _, _ *EditScript) EqualFunc { +	return f +} +func (debugger) Update() {} +func (debugger) Finish() {} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go new file mode 100644 index 000000000..a3b97a1ad --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go @@ -0,0 +1,123 @@ +// 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 file. + +//go:build cmp_debug +// +build cmp_debug + +package diff + +import ( +	"fmt" +	"strings" +	"sync" +	"time" +) + +// The algorithm can be seen running in real-time by enabling debugging: +//	go test -tags=cmp_debug -v +// +// Example output: +//	=== RUN   TestDifference/#34 +//	┌───────────────────────────────┐ +//	│ \ · · · · · · · · · · · · · · │ +//	│ · # · · · · · · · · · · · · · │ +//	│ · \ · · · · · · · · · · · · · │ +//	│ · · \ · · · · · · · · · · · · │ +//	│ · · · X # · · · · · · · · · · │ +//	│ · · · # \ · · · · · · · · · · │ +//	│ · · · · · # # · · · · · · · · │ +//	│ · · · · · # \ · · · · · · · · │ +//	│ · · · · · · · \ · · · · · · · │ +//	│ · · · · · · · · \ · · · · · · │ +//	│ · · · · · · · · · \ · · · · · │ +//	│ · · · · · · · · · · \ · · # · │ +//	│ · · · · · · · · · · · \ # # · │ +//	│ · · · · · · · · · · · # # # · │ +//	│ · · · · · · · · · · # # # # · │ +//	│ · · · · · · · · · # # # # # · │ +//	│ · · · · · · · · · · · · · · \ │ +//	└───────────────────────────────┘ +//	[.Y..M.XY......YXYXY.|] +// +// The grid represents the edit-graph where the horizontal axis represents +// list X and the vertical axis represents list Y. The start of the two lists +// is the top-left, while the ends are the bottom-right. The '·' represents +// an unexplored node in the graph. The '\' indicates that the two symbols +// from list X and Y are equal. The 'X' indicates that two symbols are similar +// (but not exactly equal) to each other. The '#' indicates that the two symbols +// are different (and not similar). The algorithm traverses this graph trying to +// make the paths starting in the top-left and the bottom-right connect. +// +// The series of '.', 'X', 'Y', and 'M' characters at the bottom represents +// the currently established path from the forward and reverse searches, +// separated by a '|' character. + +const ( +	updateDelay  = 100 * time.Millisecond +	finishDelay  = 500 * time.Millisecond +	ansiTerminal = true // ANSI escape codes used to move terminal cursor +) + +var debug debugger + +type debugger struct { +	sync.Mutex +	p1, p2           EditScript +	fwdPath, revPath *EditScript +	grid             []byte +	lines            int +} + +func (dbg *debugger) Begin(nx, ny int, f EqualFunc, p1, p2 *EditScript) EqualFunc { +	dbg.Lock() +	dbg.fwdPath, dbg.revPath = p1, p2 +	top := "┌─" + strings.Repeat("──", nx) + "┐\n" +	row := "│ " + strings.Repeat("· ", nx) + "│\n" +	btm := "└─" + strings.Repeat("──", nx) + "┘\n" +	dbg.grid = []byte(top + strings.Repeat(row, ny) + btm) +	dbg.lines = strings.Count(dbg.String(), "\n") +	fmt.Print(dbg) + +	// Wrap the EqualFunc so that we can intercept each result. +	return func(ix, iy int) (r Result) { +		cell := dbg.grid[len(top)+iy*len(row):][len("│ ")+len("· ")*ix:][:len("·")] +		for i := range cell { +			cell[i] = 0 // Zero out the multiple bytes of UTF-8 middle-dot +		} +		switch r = f(ix, iy); { +		case r.Equal(): +			cell[0] = '\\' +		case r.Similar(): +			cell[0] = 'X' +		default: +			cell[0] = '#' +		} +		return +	} +} + +func (dbg *debugger) Update() { +	dbg.print(updateDelay) +} + +func (dbg *debugger) Finish() { +	dbg.print(finishDelay) +	dbg.Unlock() +} + +func (dbg *debugger) String() string { +	dbg.p1, dbg.p2 = *dbg.fwdPath, dbg.p2[:0] +	for i := len(*dbg.revPath) - 1; i >= 0; i-- { +		dbg.p2 = append(dbg.p2, (*dbg.revPath)[i]) +	} +	return fmt.Sprintf("%s[%v|%v]\n\n", dbg.grid, dbg.p1, dbg.p2) +} + +func (dbg *debugger) print(d time.Duration) { +	if ansiTerminal { +		fmt.Printf("\x1b[%dA", dbg.lines) // Reset terminal cursor +	} +	fmt.Print(dbg) +	time.Sleep(d) +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go new file mode 100644 index 000000000..a248e5436 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go @@ -0,0 +1,402 @@ +// 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 file. + +// Package diff implements an algorithm for producing edit-scripts. +// The edit-script is a sequence of operations needed to transform one list +// of symbols into another (or vice-versa). The edits allowed are insertions, +// deletions, and modifications. The summation of all edits is called the +// Levenshtein distance as this problem is well-known in computer science. +// +// This package prioritizes performance over accuracy. That is, the run time +// is more important than obtaining a minimal Levenshtein distance. +package diff + +import ( +	"math/rand" +	"time" + +	"github.com/google/go-cmp/cmp/internal/flags" +) + +// EditType represents a single operation within an edit-script. +type EditType uint8 + +const ( +	// Identity indicates that a symbol pair is identical in both list X and Y. +	Identity EditType = iota +	// UniqueX indicates that a symbol only exists in X and not Y. +	UniqueX +	// UniqueY indicates that a symbol only exists in Y and not X. +	UniqueY +	// Modified indicates that a symbol pair is a modification of each other. +	Modified +) + +// EditScript represents the series of differences between two lists. +type EditScript []EditType + +// String returns a human-readable string representing the edit-script where +// Identity, UniqueX, UniqueY, and Modified are represented by the +// '.', 'X', 'Y', and 'M' characters, respectively. +func (es EditScript) String() string { +	b := make([]byte, len(es)) +	for i, e := range es { +		switch e { +		case Identity: +			b[i] = '.' +		case UniqueX: +			b[i] = 'X' +		case UniqueY: +			b[i] = 'Y' +		case Modified: +			b[i] = 'M' +		default: +			panic("invalid edit-type") +		} +	} +	return string(b) +} + +// stats returns a histogram of the number of each type of edit operation. +func (es EditScript) stats() (s struct{ NI, NX, NY, NM int }) { +	for _, e := range es { +		switch e { +		case Identity: +			s.NI++ +		case UniqueX: +			s.NX++ +		case UniqueY: +			s.NY++ +		case Modified: +			s.NM++ +		default: +			panic("invalid edit-type") +		} +	} +	return +} + +// Dist is the Levenshtein distance and is guaranteed to be 0 if and only if +// lists X and Y are equal. +func (es EditScript) Dist() int { return len(es) - es.stats().NI } + +// LenX is the length of the X list. +func (es EditScript) LenX() int { return len(es) - es.stats().NY } + +// LenY is the length of the Y list. +func (es EditScript) LenY() int { return len(es) - es.stats().NX } + +// EqualFunc reports whether the symbols at indexes ix and iy are equal. +// When called by Difference, the index is guaranteed to be within nx and ny. +type EqualFunc func(ix int, iy int) Result + +// Result is the result of comparison. +// NumSame is the number of sub-elements that are equal. +// NumDiff is the number of sub-elements that are not equal. +type Result struct{ NumSame, NumDiff int } + +// BoolResult returns a Result that is either Equal or not Equal. +func BoolResult(b bool) Result { +	if b { +		return Result{NumSame: 1} // Equal, Similar +	} else { +		return Result{NumDiff: 2} // Not Equal, not Similar +	} +} + +// Equal indicates whether the symbols are equal. Two symbols are equal +// if and only if NumDiff == 0. If Equal, then they are also Similar. +func (r Result) Equal() bool { return r.NumDiff == 0 } + +// Similar indicates whether two symbols are similar and may be represented +// by using the Modified type. As a special case, we consider binary comparisons +// (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar. +// +// The exact ratio of NumSame to NumDiff to determine similarity may change. +func (r Result) Similar() bool { +	// Use NumSame+1 to offset NumSame so that binary comparisons are similar. +	return r.NumSame+1 >= r.NumDiff +} + +var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 + +// Difference reports whether two lists of lengths nx and ny are equal +// given the definition of equality provided as f. +// +// This function returns an edit-script, which is a sequence of operations +// needed to convert one list into the other. The following invariants for +// the edit-script are maintained: +//   - eq == (es.Dist()==0) +//   - nx == es.LenX() +//   - ny == es.LenY() +// +// This algorithm is not guaranteed to be an optimal solution (i.e., one that +// produces an edit-script with a minimal Levenshtein distance). This algorithm +// favors performance over optimality. The exact output is not guaranteed to +// be stable and may change over time. +func Difference(nx, ny int, f EqualFunc) (es EditScript) { +	// This algorithm is based on traversing what is known as an "edit-graph". +	// See Figure 1 from "An O(ND) Difference Algorithm and Its Variations" +	// by Eugene W. Myers. Since D can be as large as N itself, this is +	// effectively O(N^2). Unlike the algorithm from that paper, we are not +	// interested in the optimal path, but at least some "decent" path. +	// +	// For example, let X and Y be lists of symbols: +	//	X = [A B C A B B A] +	//	Y = [C B A B A C] +	// +	// The edit-graph can be drawn as the following: +	//	   A B C A B B A +	//	  ┌─────────────┐ +	//	C │_|_|\|_|_|_|_│ 0 +	//	B │_|\|_|_|\|\|_│ 1 +	//	A │\|_|_|\|_|_|\│ 2 +	//	B │_|\|_|_|\|\|_│ 3 +	//	A │\|_|_|\|_|_|\│ 4 +	//	C │ | |\| | | | │ 5 +	//	  └─────────────┘ 6 +	//	   0 1 2 3 4 5 6 7 +	// +	// List X is written along the horizontal axis, while list Y is written +	// along the vertical axis. At any point on this grid, if the symbol in +	// list X matches the corresponding symbol in list Y, then a '\' is drawn. +	// The goal of any minimal edit-script algorithm is to find a path from the +	// top-left corner to the bottom-right corner, while traveling through the +	// fewest horizontal or vertical edges. +	// A horizontal edge is equivalent to inserting a symbol from list X. +	// A vertical edge is equivalent to inserting a symbol from list Y. +	// A diagonal edge is equivalent to a matching symbol between both X and Y. + +	// Invariants: +	//   - 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx +	//   - 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny +	// +	// In general: +	//   - fwdFrontier.X < revFrontier.X +	//   - fwdFrontier.Y < revFrontier.Y +	// +	// Unless, it is time for the algorithm to terminate. +	fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)} +	revPath := path{-1, point{nx, ny}, make(EditScript, 0)} +	fwdFrontier := fwdPath.point // Forward search frontier +	revFrontier := revPath.point // Reverse search frontier + +	// Search budget bounds the cost of searching for better paths. +	// The longest sequence of non-matching symbols that can be tolerated is +	// approximately the square-root of the search budget. +	searchBudget := 4 * (nx + ny) // O(n) + +	// Running the tests with the "cmp_debug" build tag prints a visualization +	// of the algorithm running in real-time. This is educational for +	// understanding how the algorithm works. See debug_enable.go. +	f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) + +	// The algorithm below is a greedy, meet-in-the-middle algorithm for +	// computing sub-optimal edit-scripts between two lists. +	// +	// The algorithm is approximately as follows: +	//   - Searching for differences switches back-and-forth between +	//     a search that starts at the beginning (the top-left corner), and +	//     a search that starts at the end (the bottom-right corner). +	//     The goal of the search is connect with the search +	//     from the opposite corner. +	//   - As we search, we build a path in a greedy manner, +	//     where the first match seen is added to the path (this is sub-optimal, +	//     but provides a decent result in practice). When matches are found, +	//     we try the next pair of symbols in the lists and follow all matches +	//     as far as possible. +	//   - When searching for matches, we search along a diagonal going through +	//     through the "frontier" point. If no matches are found, +	//     we advance the frontier towards the opposite corner. +	//   - This algorithm terminates when either the X coordinates or the +	//     Y coordinates of the forward and reverse frontier points ever intersect. + +	// This algorithm is correct even if searching only in the forward direction +	// or in the reverse direction. We do both because it is commonly observed +	// that two lists commonly differ because elements were added to the front +	// or end of the other list. +	// +	// Non-deterministically start with either the forward or reverse direction +	// to introduce some deliberate instability so that we have the flexibility +	// to change this algorithm in the future. +	if flags.Deterministic || randBool { +		goto forwardSearch +	} else { +		goto reverseSearch +	} + +forwardSearch: +	{ +		// Forward search from the beginning. +		if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { +			goto finishSearch +		} +		for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { +			// Search in a diagonal pattern for a match. +			z := zigzag(i) +			p := point{fwdFrontier.X + z, fwdFrontier.Y - z} +			switch { +			case p.X >= revPath.X || p.Y < fwdPath.Y: +				stop1 = true // Hit top-right corner +			case p.Y >= revPath.Y || p.X < fwdPath.X: +				stop2 = true // Hit bottom-left corner +			case f(p.X, p.Y).Equal(): +				// Match found, so connect the path to this point. +				fwdPath.connect(p, f) +				fwdPath.append(Identity) +				// Follow sequence of matches as far as possible. +				for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { +					if !f(fwdPath.X, fwdPath.Y).Equal() { +						break +					} +					fwdPath.append(Identity) +				} +				fwdFrontier = fwdPath.point +				stop1, stop2 = true, true +			default: +				searchBudget-- // Match not found +			} +			debug.Update() +		} +		// Advance the frontier towards reverse point. +		if revPath.X-fwdFrontier.X >= revPath.Y-fwdFrontier.Y { +			fwdFrontier.X++ +		} else { +			fwdFrontier.Y++ +		} +		goto reverseSearch +	} + +reverseSearch: +	{ +		// Reverse search from the end. +		if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { +			goto finishSearch +		} +		for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { +			// Search in a diagonal pattern for a match. +			z := zigzag(i) +			p := point{revFrontier.X - z, revFrontier.Y + z} +			switch { +			case fwdPath.X >= p.X || revPath.Y < p.Y: +				stop1 = true // Hit bottom-left corner +			case fwdPath.Y >= p.Y || revPath.X < p.X: +				stop2 = true // Hit top-right corner +			case f(p.X-1, p.Y-1).Equal(): +				// Match found, so connect the path to this point. +				revPath.connect(p, f) +				revPath.append(Identity) +				// Follow sequence of matches as far as possible. +				for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { +					if !f(revPath.X-1, revPath.Y-1).Equal() { +						break +					} +					revPath.append(Identity) +				} +				revFrontier = revPath.point +				stop1, stop2 = true, true +			default: +				searchBudget-- // Match not found +			} +			debug.Update() +		} +		// Advance the frontier towards forward point. +		if revFrontier.X-fwdPath.X >= revFrontier.Y-fwdPath.Y { +			revFrontier.X-- +		} else { +			revFrontier.Y-- +		} +		goto forwardSearch +	} + +finishSearch: +	// Join the forward and reverse paths and then append the reverse path. +	fwdPath.connect(revPath.point, f) +	for i := len(revPath.es) - 1; i >= 0; i-- { +		t := revPath.es[i] +		revPath.es = revPath.es[:i] +		fwdPath.append(t) +	} +	debug.Finish() +	return fwdPath.es +} + +type path struct { +	dir   int // +1 if forward, -1 if reverse +	point     // Leading point of the EditScript path +	es    EditScript +} + +// connect appends any necessary Identity, Modified, UniqueX, or UniqueY types +// to the edit-script to connect p.point to dst. +func (p *path) connect(dst point, f EqualFunc) { +	if p.dir > 0 { +		// Connect in forward direction. +		for dst.X > p.X && dst.Y > p.Y { +			switch r := f(p.X, p.Y); { +			case r.Equal(): +				p.append(Identity) +			case r.Similar(): +				p.append(Modified) +			case dst.X-p.X >= dst.Y-p.Y: +				p.append(UniqueX) +			default: +				p.append(UniqueY) +			} +		} +		for dst.X > p.X { +			p.append(UniqueX) +		} +		for dst.Y > p.Y { +			p.append(UniqueY) +		} +	} else { +		// Connect in reverse direction. +		for p.X > dst.X && p.Y > dst.Y { +			switch r := f(p.X-1, p.Y-1); { +			case r.Equal(): +				p.append(Identity) +			case r.Similar(): +				p.append(Modified) +			case p.Y-dst.Y >= p.X-dst.X: +				p.append(UniqueY) +			default: +				p.append(UniqueX) +			} +		} +		for p.X > dst.X { +			p.append(UniqueX) +		} +		for p.Y > dst.Y { +			p.append(UniqueY) +		} +	} +} + +func (p *path) append(t EditType) { +	p.es = append(p.es, t) +	switch t { +	case Identity, Modified: +		p.add(p.dir, p.dir) +	case UniqueX: +		p.add(p.dir, 0) +	case UniqueY: +		p.add(0, p.dir) +	} +	debug.Update() +} + +type point struct{ X, Y int } + +func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy } + +// zigzag maps a consecutive sequence of integers to a zig-zag sequence. +// +//	[0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...] +func zigzag(x int) int { +	if x&1 != 0 { +		x = ^x +	} +	return x >> 1 +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go new file mode 100644 index 000000000..d8e459c9b --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go @@ -0,0 +1,9 @@ +// Copyright 2019, 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 file. + +package flags + +// Deterministic controls whether the output of Diff should be deterministic. +// This is only used for testing. +var Deterministic bool diff --git a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go new file mode 100644 index 000000000..d127d4362 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go @@ -0,0 +1,99 @@ +// 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 file. + +// Package function provides functionality for identifying function types. +package function + +import ( +	"reflect" +	"regexp" +	"runtime" +	"strings" +) + +type funcType int + +const ( +	_ funcType = iota + +	tbFunc  // func(T) bool +	ttbFunc // func(T, T) bool +	trbFunc // func(T, R) bool +	tibFunc // func(T, I) bool +	trFunc  // func(T) R + +	Equal             = ttbFunc // func(T, T) bool +	EqualAssignable   = tibFunc // func(T, I) bool; encapsulates func(T, T) bool +	Transformer       = trFunc  // func(T) R +	ValueFilter       = ttbFunc // func(T, T) bool +	Less              = ttbFunc // func(T, T) bool +	ValuePredicate    = tbFunc  // func(T) bool +	KeyValuePredicate = trbFunc // func(T, R) bool +) + +var boolType = reflect.TypeOf(true) + +// IsType reports whether the reflect.Type is of the specified function type. +func IsType(t reflect.Type, ft funcType) bool { +	if t == nil || t.Kind() != reflect.Func || t.IsVariadic() { +		return false +	} +	ni, no := t.NumIn(), t.NumOut() +	switch ft { +	case tbFunc: // func(T) bool +		if ni == 1 && no == 1 && t.Out(0) == boolType { +			return true +		} +	case ttbFunc: // func(T, T) bool +		if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType { +			return true +		} +	case trbFunc: // func(T, R) bool +		if ni == 2 && no == 1 && t.Out(0) == boolType { +			return true +		} +	case tibFunc: // func(T, I) bool +		if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType { +			return true +		} +	case trFunc: // func(T) R +		if ni == 1 && no == 1 { +			return true +		} +	} +	return false +} + +var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`) + +// NameOf returns the name of the function value. +func NameOf(v reflect.Value) string { +	fnc := runtime.FuncForPC(v.Pointer()) +	if fnc == nil { +		return "<unknown>" +	} +	fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm" + +	// Method closures have a "-fm" suffix. +	fullName = strings.TrimSuffix(fullName, "-fm") + +	var name string +	for len(fullName) > 0 { +		inParen := strings.HasSuffix(fullName, ")") +		fullName = strings.TrimSuffix(fullName, ")") + +		s := lastIdentRx.FindString(fullName) +		if s == "" { +			break +		} +		name = s + "." + name +		fullName = strings.TrimSuffix(fullName, s) + +		if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 { +			fullName = fullName[:i] +		} +		fullName = strings.TrimSuffix(fullName, ".") +	} +	return strings.TrimSuffix(name, ".") +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/name.go b/vendor/github.com/google/go-cmp/cmp/internal/value/name.go new file mode 100644 index 000000000..7b498bb2c --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/name.go @@ -0,0 +1,164 @@ +// Copyright 2020, 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 file. + +package value + +import ( +	"reflect" +	"strconv" +) + +var anyType = reflect.TypeOf((*interface{})(nil)).Elem() + +// TypeString is nearly identical to reflect.Type.String, +// but has an additional option to specify that full type names be used. +func TypeString(t reflect.Type, qualified bool) string { +	return string(appendTypeName(nil, t, qualified, false)) +} + +func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte { +	// BUG: Go reflection provides no way to disambiguate two named types +	// of the same name and within the same package, +	// but declared within the namespace of different functions. + +	// Use the "any" alias instead of "interface{}" for better readability. +	if t == anyType { +		return append(b, "any"...) +	} + +	// Named type. +	if t.Name() != "" { +		if qualified && t.PkgPath() != "" { +			b = append(b, '"') +			b = append(b, t.PkgPath()...) +			b = append(b, '"') +			b = append(b, '.') +			b = append(b, t.Name()...) +		} else { +			b = append(b, t.String()...) +		} +		return b +	} + +	// Unnamed type. +	switch k := t.Kind(); k { +	case reflect.Bool, reflect.String, reflect.UnsafePointer, +		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, +		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, +		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: +		b = append(b, k.String()...) +	case reflect.Chan: +		if t.ChanDir() == reflect.RecvDir { +			b = append(b, "<-"...) +		} +		b = append(b, "chan"...) +		if t.ChanDir() == reflect.SendDir { +			b = append(b, "<-"...) +		} +		b = append(b, ' ') +		b = appendTypeName(b, t.Elem(), qualified, false) +	case reflect.Func: +		if !elideFunc { +			b = append(b, "func"...) +		} +		b = append(b, '(') +		for i := 0; i < t.NumIn(); i++ { +			if i > 0 { +				b = append(b, ", "...) +			} +			if i == t.NumIn()-1 && t.IsVariadic() { +				b = append(b, "..."...) +				b = appendTypeName(b, t.In(i).Elem(), qualified, false) +			} else { +				b = appendTypeName(b, t.In(i), qualified, false) +			} +		} +		b = append(b, ')') +		switch t.NumOut() { +		case 0: +			// Do nothing +		case 1: +			b = append(b, ' ') +			b = appendTypeName(b, t.Out(0), qualified, false) +		default: +			b = append(b, " ("...) +			for i := 0; i < t.NumOut(); i++ { +				if i > 0 { +					b = append(b, ", "...) +				} +				b = appendTypeName(b, t.Out(i), qualified, false) +			} +			b = append(b, ')') +		} +	case reflect.Struct: +		b = append(b, "struct{ "...) +		for i := 0; i < t.NumField(); i++ { +			if i > 0 { +				b = append(b, "; "...) +			} +			sf := t.Field(i) +			if !sf.Anonymous { +				if qualified && sf.PkgPath != "" { +					b = append(b, '"') +					b = append(b, sf.PkgPath...) +					b = append(b, '"') +					b = append(b, '.') +				} +				b = append(b, sf.Name...) +				b = append(b, ' ') +			} +			b = appendTypeName(b, sf.Type, qualified, false) +			if sf.Tag != "" { +				b = append(b, ' ') +				b = strconv.AppendQuote(b, string(sf.Tag)) +			} +		} +		if b[len(b)-1] == ' ' { +			b = b[:len(b)-1] +		} else { +			b = append(b, ' ') +		} +		b = append(b, '}') +	case reflect.Slice, reflect.Array: +		b = append(b, '[') +		if k == reflect.Array { +			b = strconv.AppendUint(b, uint64(t.Len()), 10) +		} +		b = append(b, ']') +		b = appendTypeName(b, t.Elem(), qualified, false) +	case reflect.Map: +		b = append(b, "map["...) +		b = appendTypeName(b, t.Key(), qualified, false) +		b = append(b, ']') +		b = appendTypeName(b, t.Elem(), qualified, false) +	case reflect.Ptr: +		b = append(b, '*') +		b = appendTypeName(b, t.Elem(), qualified, false) +	case reflect.Interface: +		b = append(b, "interface{ "...) +		for i := 0; i < t.NumMethod(); i++ { +			if i > 0 { +				b = append(b, "; "...) +			} +			m := t.Method(i) +			if qualified && m.PkgPath != "" { +				b = append(b, '"') +				b = append(b, m.PkgPath...) +				b = append(b, '"') +				b = append(b, '.') +			} +			b = append(b, m.Name...) +			b = appendTypeName(b, m.Type, qualified, true) +		} +		if b[len(b)-1] == ' ' { +			b = b[:len(b)-1] +		} else { +			b = append(b, ' ') +		} +		b = append(b, '}') +	default: +		panic("invalid kind: " + k.String()) +	} +	return b +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer.go new file mode 100644 index 000000000..e5dfff69a --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer.go @@ -0,0 +1,34 @@ +// Copyright 2018, 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 file. + +package value + +import ( +	"reflect" +	"unsafe" +) + +// Pointer is an opaque typed pointer and is guaranteed to be comparable. +type Pointer struct { +	p unsafe.Pointer +	t reflect.Type +} + +// PointerOf returns a Pointer from v, which must be a +// reflect.Ptr, reflect.Slice, or reflect.Map. +func PointerOf(v reflect.Value) Pointer { +	// The proper representation of a pointer is unsafe.Pointer, +	// which is necessary if the GC ever uses a moving collector. +	return Pointer{unsafe.Pointer(v.Pointer()), v.Type()} +} + +// IsNil reports whether the pointer is nil. +func (p Pointer) IsNil() bool { +	return p.p == nil +} + +// Uintptr returns the pointer as a uintptr. +func (p Pointer) Uintptr() uintptr { +	return uintptr(p.p) +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go new file mode 100644 index 000000000..98533b036 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go @@ -0,0 +1,106 @@ +// 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 file. + +package value + +import ( +	"fmt" +	"math" +	"reflect" +	"sort" +) + +// SortKeys sorts a list of map keys, deduplicating keys if necessary. +// The type of each value must be comparable. +func SortKeys(vs []reflect.Value) []reflect.Value { +	if len(vs) == 0 { +		return vs +	} + +	// Sort the map keys. +	sort.SliceStable(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) }) + +	// Deduplicate keys (fails for NaNs). +	vs2 := vs[:1] +	for _, v := range vs[1:] { +		if isLess(vs2[len(vs2)-1], v) { +			vs2 = append(vs2, v) +		} +	} +	return vs2 +} + +// isLess is a generic function for sorting arbitrary map keys. +// The inputs must be of the same type and must be comparable. +func isLess(x, y reflect.Value) bool { +	switch x.Type().Kind() { +	case reflect.Bool: +		return !x.Bool() && y.Bool() +	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: +		return x.Int() < y.Int() +	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: +		return x.Uint() < y.Uint() +	case reflect.Float32, reflect.Float64: +		// NOTE: This does not sort -0 as less than +0 +		// since Go maps treat -0 and +0 as equal keys. +		fx, fy := x.Float(), y.Float() +		return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy) +	case reflect.Complex64, reflect.Complex128: +		cx, cy := x.Complex(), y.Complex() +		rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy) +		if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) { +			return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy) +		} +		return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry) +	case reflect.Ptr, reflect.UnsafePointer, reflect.Chan: +		return x.Pointer() < y.Pointer() +	case reflect.String: +		return x.String() < y.String() +	case reflect.Array: +		for i := 0; i < x.Len(); i++ { +			if isLess(x.Index(i), y.Index(i)) { +				return true +			} +			if isLess(y.Index(i), x.Index(i)) { +				return false +			} +		} +		return false +	case reflect.Struct: +		for i := 0; i < x.NumField(); i++ { +			if isLess(x.Field(i), y.Field(i)) { +				return true +			} +			if isLess(y.Field(i), x.Field(i)) { +				return false +			} +		} +		return false +	case reflect.Interface: +		vx, vy := x.Elem(), y.Elem() +		if !vx.IsValid() || !vy.IsValid() { +			return !vx.IsValid() && vy.IsValid() +		} +		tx, ty := vx.Type(), vy.Type() +		if tx == ty { +			return isLess(x.Elem(), y.Elem()) +		} +		if tx.Kind() != ty.Kind() { +			return vx.Kind() < vy.Kind() +		} +		if tx.String() != ty.String() { +			return tx.String() < ty.String() +		} +		if tx.PkgPath() != ty.PkgPath() { +			return tx.PkgPath() < ty.PkgPath() +		} +		// This can happen in rare situations, so we fallback to just comparing +		// the unique pointer for a reflect.Type. This guarantees deterministic +		// ordering within a program, but it is obviously not stable. +		return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer() +	default: +		// Must be Func, Map, or Slice; which are not comparable. +		panic(fmt.Sprintf("%T is not comparable", x.Type())) +	} +} | 
