Blame vendor/github.com/google/go-cmp/cmp/internal/function/func.go

Packit 63bb0d
// Copyright 2017, The Go Authors. All rights reserved.
Packit 63bb0d
// Use of this source code is governed by a BSD-style
Packit 63bb0d
// license that can be found in the LICENSE.md file.
Packit 63bb0d
Packit 63bb0d
// Package function provides functionality for identifying function types.
Packit 63bb0d
package function
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"reflect"
Packit 63bb0d
	"regexp"
Packit 63bb0d
	"runtime"
Packit 63bb0d
	"strings"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
type funcType int
Packit 63bb0d
Packit 63bb0d
const (
Packit 63bb0d
	_ funcType = iota
Packit 63bb0d
Packit 63bb0d
	tbFunc  // func(T) bool
Packit 63bb0d
	ttbFunc // func(T, T) bool
Packit 63bb0d
	trbFunc // func(T, R) bool
Packit 63bb0d
	tibFunc // func(T, I) bool
Packit 63bb0d
	trFunc  // func(T) R
Packit 63bb0d
Packit 63bb0d
	Equal             = ttbFunc // func(T, T) bool
Packit 63bb0d
	EqualAssignable   = tibFunc // func(T, I) bool; encapsulates func(T, T) bool
Packit 63bb0d
	Transformer       = trFunc  // func(T) R
Packit 63bb0d
	ValueFilter       = ttbFunc // func(T, T) bool
Packit 63bb0d
	Less              = ttbFunc // func(T, T) bool
Packit 63bb0d
	ValuePredicate    = tbFunc  // func(T) bool
Packit 63bb0d
	KeyValuePredicate = trbFunc // func(T, R) bool
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
var boolType = reflect.TypeOf(true)
Packit 63bb0d
Packit 63bb0d
// IsType reports whether the reflect.Type is of the specified function type.
Packit 63bb0d
func IsType(t reflect.Type, ft funcType) bool {
Packit 63bb0d
	if t == nil || t.Kind() != reflect.Func || t.IsVariadic() {
Packit 63bb0d
		return false
Packit 63bb0d
	}
Packit 63bb0d
	ni, no := t.NumIn(), t.NumOut()
Packit 63bb0d
	switch ft {
Packit 63bb0d
	case tbFunc: // func(T) bool
Packit 63bb0d
		if ni == 1 && no == 1 && t.Out(0) == boolType {
Packit 63bb0d
			return true
Packit 63bb0d
		}
Packit 63bb0d
	case ttbFunc: // func(T, T) bool
Packit 63bb0d
		if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType {
Packit 63bb0d
			return true
Packit 63bb0d
		}
Packit 63bb0d
	case trbFunc: // func(T, R) bool
Packit 63bb0d
		if ni == 2 && no == 1 && t.Out(0) == boolType {
Packit 63bb0d
			return true
Packit 63bb0d
		}
Packit 63bb0d
	case tibFunc: // func(T, I) bool
Packit 63bb0d
		if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType {
Packit 63bb0d
			return true
Packit 63bb0d
		}
Packit 63bb0d
	case trFunc: // func(T) R
Packit 63bb0d
		if ni == 1 && no == 1 {
Packit 63bb0d
			return true
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return false
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`)
Packit 63bb0d
Packit 63bb0d
// NameOf returns the name of the function value.
Packit 63bb0d
func NameOf(v reflect.Value) string {
Packit 63bb0d
	fnc := runtime.FuncForPC(v.Pointer())
Packit 63bb0d
	if fnc == nil {
Packit 63bb0d
		return "<unknown>"
Packit 63bb0d
	}
Packit 63bb0d
	fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm"
Packit 63bb0d
Packit 63bb0d
	// Method closures have a "-fm" suffix.
Packit 63bb0d
	fullName = strings.TrimSuffix(fullName, "-fm")
Packit 63bb0d
Packit 63bb0d
	var name string
Packit 63bb0d
	for len(fullName) > 0 {
Packit 63bb0d
		inParen := strings.HasSuffix(fullName, ")")
Packit 63bb0d
		fullName = strings.TrimSuffix(fullName, ")")
Packit 63bb0d
Packit 63bb0d
		s := lastIdentRx.FindString(fullName)
Packit 63bb0d
		if s == "" {
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
		name = s + "." + name
Packit 63bb0d
		fullName = strings.TrimSuffix(fullName, s)
Packit 63bb0d
Packit 63bb0d
		if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 {
Packit 63bb0d
			fullName = fullName[:i]
Packit 63bb0d
		}
Packit 63bb0d
		fullName = strings.TrimSuffix(fullName, ".")
Packit 63bb0d
	}
Packit 63bb0d
	return strings.TrimSuffix(name, ".")
Packit 63bb0d
}