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 (
	
	
	
	
)

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 ( reflect.Type,  funcType) bool {
	if  == nil || .Kind() != reflect.Func || .IsVariadic() {
		return false
	}
	,  := .NumIn(), .NumOut()
	switch  {
	case tbFunc: // func(T) bool
		if  == 1 &&  == 1 && .Out(0) == boolType {
			return true
		}
	case ttbFunc: // func(T, T) bool
		if  == 2 &&  == 1 && .In(0) == .In(1) && .Out(0) == boolType {
			return true
		}
	case trbFunc: // func(T, R) bool
		if  == 2 &&  == 1 && .Out(0) == boolType {
			return true
		}
	case tibFunc: // func(T, I) bool
		if  == 2 &&  == 1 && .In(0).AssignableTo(.In(1)) && .Out(0) == boolType {
			return true
		}
	case trFunc: // func(T) R
		if  == 1 &&  == 1 {
			return true
		}
	}
	return false
}

var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`)
NameOf returns the name of the function value.
func ( reflect.Value) string {
	 := runtime.FuncForPC(.Pointer())
	if  == nil {
		return "<unknown>"
	}
	 := .Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm"
Method closures have a "-fm" suffix.
	 = strings.TrimSuffix(, "-fm")

	var  string
	for len() > 0 {
		 := strings.HasSuffix(, ")")
		 = strings.TrimSuffix(, ")")

		 := lastIdentRx.FindString()
		if  == "" {
			break
		}
		 =  + "." + 
		 = strings.TrimSuffix(, )

		if  := strings.LastIndexByte(, '(');  &&  >= 0 {
			 = [:]
		}
		 = strings.TrimSuffix(, ".")
	}
	return strings.TrimSuffix(, ".")