package task import ( "fmt" "reflect" "runtime" "sync" ) type TaskTarget struct { Name string targetFunc interface{} paramTypes map[string]reflect.Type } // Params returns the list of parameter types func (t *TaskTarget) Params() []reflect.Type { ft := reflect.TypeOf(t.targetFunc) paramTypes := make([]reflect.Type, ft.NumIn()) for idx := 0; idx < ft.NumIn(); idx++ { in := ft.In(idx) paramTypes[idx] = in } return paramTypes } type TaskTargetRegistry struct { targetFuncs sync.Map } // Add appends the function to the registry after resolving specific information about this function. func (r *TaskTargetRegistry) Add(targetFunc interface{}) (*TaskTarget, error) { fv := reflect.ValueOf(targetFunc) if fv.Kind() != reflect.Func { return nil, fmt.Errorf("Provided function value is not an actual function") } name := runtime.FuncForPC(fv.Pointer()).Name() funcInstance, err := r.Get(name) if err == nil { return funcInstance, nil } taskTarget := &TaskTarget{ Name: name, targetFunc: targetFunc, paramTypes: r.resolveParamTypes(targetFunc), } r.targetFuncs.Store(name, taskTarget) return taskTarget, nil } // Get returns the TaskTarget instance which holds all information about any single registered task function. func (r *TaskTargetRegistry) Get(name string) (*TaskTarget, error) { taskTarget, ok := r.targetFuncs.Load(name) if ok { return taskTarget.(*TaskTarget), nil } return nil, fmt.Errorf("Function %s not found", name) } // Exists checks if a function with provided name exists. func (r *TaskTargetRegistry) Exists(name string) bool { _, ok := r.targetFuncs.Load(name) if ok { return true } return false } func (r *TaskTargetRegistry) resolveParamTypes(targetFunc interface{}) map[string]reflect.Type { paramTypes := make(map[string]reflect.Type) funcType := reflect.TypeOf(targetFunc) for idx := 0; idx < funcType.NumIn(); idx++ { in := funcType.In(idx) paramTypes[in.Name()] = in } return paramTypes }