123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- // 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 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, ".")
- }
|