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