|
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 |
}
|