93 lines
1.8 KiB
Go
93 lines
1.8 KiB
Go
package functions
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"reflect"
|
|
)
|
|
|
|
type Function interface {
|
|
Name() string
|
|
Types() map[string]string
|
|
Definition() string
|
|
IsAsync() bool
|
|
Arguments() []reflect.Type
|
|
Call(context.Context, []any) (any, error)
|
|
}
|
|
|
|
type GoFunc[A Args, R any] func(context.Context, A) (R, error)
|
|
|
|
type Args interface {
|
|
Validate() error
|
|
}
|
|
|
|
type functionImpl[A Args, R any] struct {
|
|
name string
|
|
fn GoFunc[A, R]
|
|
definition string
|
|
types map[string]string
|
|
isAsync bool
|
|
}
|
|
|
|
func (b *functionImpl[A, R]) Name() string {
|
|
return b.name
|
|
}
|
|
|
|
func (b *functionImpl[A, R]) Types() map[string]string {
|
|
return b.types
|
|
}
|
|
|
|
func (b *functionImpl[A, R]) Definition() string {
|
|
return b.definition
|
|
}
|
|
|
|
func (b *functionImpl[A, R]) IsAsync() bool {
|
|
return b.isAsync
|
|
}
|
|
|
|
func (b *functionImpl[A, R]) Function() any {
|
|
return b.fn
|
|
}
|
|
|
|
func (b *functionImpl[A, R]) Arguments() []reflect.Type {
|
|
// Collect Argument Types
|
|
var allTypes []reflect.Type
|
|
|
|
rType := reflect.TypeFor[A]()
|
|
for i := range rType.NumField() {
|
|
allTypes = append(allTypes, rType.Field(i).Type)
|
|
}
|
|
|
|
return allTypes
|
|
}
|
|
|
|
func (b *functionImpl[A, R]) Call(ctx context.Context, allArgs []any) (any, error) {
|
|
return b.CallGeneric(ctx, allArgs)
|
|
}
|
|
|
|
func (b *functionImpl[A, R]) CallGeneric(ctx context.Context, allArgs []any) (zeroR R, err error) {
|
|
// Populate Arguments
|
|
var fnArgs A
|
|
aVal := reflect.ValueOf(&fnArgs).Elem()
|
|
|
|
// Populate Fields
|
|
for i := range min(aVal.NumField(), len(allArgs)) {
|
|
field := aVal.Field(i)
|
|
|
|
// Validate Field is Settable
|
|
if !field.CanSet() {
|
|
return zeroR, errors.New("cannot set field")
|
|
}
|
|
|
|
// Validate and Set Field Value
|
|
argVal := reflect.ValueOf(allArgs[i])
|
|
if !argVal.Type().AssignableTo(field.Type()) {
|
|
return zeroR, errors.New("cannot assign field")
|
|
}
|
|
field.Set(argVal)
|
|
}
|
|
|
|
// Execute Function
|
|
return b.fn(ctx, fnArgs)
|
|
}
|