1*88d15eacSSasha Smundak// Copyright 2017, The Go Authors. All rights reserved. 2*88d15eacSSasha Smundak// Use of this source code is governed by a BSD-style 3*88d15eacSSasha Smundak// license that can be found in the LICENSE file. 4*88d15eacSSasha Smundak 5*88d15eacSSasha Smundak// Package function provides functionality for identifying function types. 6*88d15eacSSasha Smundakpackage function 7*88d15eacSSasha Smundak 8*88d15eacSSasha Smundakimport ( 9*88d15eacSSasha Smundak "reflect" 10*88d15eacSSasha Smundak "regexp" 11*88d15eacSSasha Smundak "runtime" 12*88d15eacSSasha Smundak "strings" 13*88d15eacSSasha Smundak) 14*88d15eacSSasha Smundak 15*88d15eacSSasha Smundaktype funcType int 16*88d15eacSSasha Smundak 17*88d15eacSSasha Smundakconst ( 18*88d15eacSSasha Smundak _ funcType = iota 19*88d15eacSSasha Smundak 20*88d15eacSSasha Smundak tbFunc // func(T) bool 21*88d15eacSSasha Smundak ttbFunc // func(T, T) bool 22*88d15eacSSasha Smundak trbFunc // func(T, R) bool 23*88d15eacSSasha Smundak tibFunc // func(T, I) bool 24*88d15eacSSasha Smundak trFunc // func(T) R 25*88d15eacSSasha Smundak 26*88d15eacSSasha Smundak Equal = ttbFunc // func(T, T) bool 27*88d15eacSSasha Smundak EqualAssignable = tibFunc // func(T, I) bool; encapsulates func(T, T) bool 28*88d15eacSSasha Smundak Transformer = trFunc // func(T) R 29*88d15eacSSasha Smundak ValueFilter = ttbFunc // func(T, T) bool 30*88d15eacSSasha Smundak Less = ttbFunc // func(T, T) bool 31*88d15eacSSasha Smundak ValuePredicate = tbFunc // func(T) bool 32*88d15eacSSasha Smundak KeyValuePredicate = trbFunc // func(T, R) bool 33*88d15eacSSasha Smundak) 34*88d15eacSSasha Smundak 35*88d15eacSSasha Smundakvar boolType = reflect.TypeOf(true) 36*88d15eacSSasha Smundak 37*88d15eacSSasha Smundak// IsType reports whether the reflect.Type is of the specified function type. 38*88d15eacSSasha Smundakfunc IsType(t reflect.Type, ft funcType) bool { 39*88d15eacSSasha Smundak if t == nil || t.Kind() != reflect.Func || t.IsVariadic() { 40*88d15eacSSasha Smundak return false 41*88d15eacSSasha Smundak } 42*88d15eacSSasha Smundak ni, no := t.NumIn(), t.NumOut() 43*88d15eacSSasha Smundak switch ft { 44*88d15eacSSasha Smundak case tbFunc: // func(T) bool 45*88d15eacSSasha Smundak if ni == 1 && no == 1 && t.Out(0) == boolType { 46*88d15eacSSasha Smundak return true 47*88d15eacSSasha Smundak } 48*88d15eacSSasha Smundak case ttbFunc: // func(T, T) bool 49*88d15eacSSasha Smundak if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType { 50*88d15eacSSasha Smundak return true 51*88d15eacSSasha Smundak } 52*88d15eacSSasha Smundak case trbFunc: // func(T, R) bool 53*88d15eacSSasha Smundak if ni == 2 && no == 1 && t.Out(0) == boolType { 54*88d15eacSSasha Smundak return true 55*88d15eacSSasha Smundak } 56*88d15eacSSasha Smundak case tibFunc: // func(T, I) bool 57*88d15eacSSasha Smundak if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType { 58*88d15eacSSasha Smundak return true 59*88d15eacSSasha Smundak } 60*88d15eacSSasha Smundak case trFunc: // func(T) R 61*88d15eacSSasha Smundak if ni == 1 && no == 1 { 62*88d15eacSSasha Smundak return true 63*88d15eacSSasha Smundak } 64*88d15eacSSasha Smundak } 65*88d15eacSSasha Smundak return false 66*88d15eacSSasha Smundak} 67*88d15eacSSasha Smundak 68*88d15eacSSasha Smundakvar lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`) 69*88d15eacSSasha Smundak 70*88d15eacSSasha Smundak// NameOf returns the name of the function value. 71*88d15eacSSasha Smundakfunc NameOf(v reflect.Value) string { 72*88d15eacSSasha Smundak fnc := runtime.FuncForPC(v.Pointer()) 73*88d15eacSSasha Smundak if fnc == nil { 74*88d15eacSSasha Smundak return "<unknown>" 75*88d15eacSSasha Smundak } 76*88d15eacSSasha Smundak fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm" 77*88d15eacSSasha Smundak 78*88d15eacSSasha Smundak // Method closures have a "-fm" suffix. 79*88d15eacSSasha Smundak fullName = strings.TrimSuffix(fullName, "-fm") 80*88d15eacSSasha Smundak 81*88d15eacSSasha Smundak var name string 82*88d15eacSSasha Smundak for len(fullName) > 0 { 83*88d15eacSSasha Smundak inParen := strings.HasSuffix(fullName, ")") 84*88d15eacSSasha Smundak fullName = strings.TrimSuffix(fullName, ")") 85*88d15eacSSasha Smundak 86*88d15eacSSasha Smundak s := lastIdentRx.FindString(fullName) 87*88d15eacSSasha Smundak if s == "" { 88*88d15eacSSasha Smundak break 89*88d15eacSSasha Smundak } 90*88d15eacSSasha Smundak name = s + "." + name 91*88d15eacSSasha Smundak fullName = strings.TrimSuffix(fullName, s) 92*88d15eacSSasha Smundak 93*88d15eacSSasha Smundak if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 { 94*88d15eacSSasha Smundak fullName = fullName[:i] 95*88d15eacSSasha Smundak } 96*88d15eacSSasha Smundak fullName = strings.TrimSuffix(fullName, ".") 97*88d15eacSSasha Smundak } 98*88d15eacSSasha Smundak return strings.TrimSuffix(name, ".") 99*88d15eacSSasha Smundak} 100