Files
aego/script/bind/method.go
T

163 lines
4.1 KiB
Go

package bind
import (
"errors"
"reflect"
"aego/schema"
"aego/script/abi"
"aego/script/vm"
)
var errMethodModule = errors.New("component methods cannot live in a method module")
func missing[T any](name string) string {
return name + ": the " + reflect.TypeFor[T]().Name() + " reference is nil, its node is destroyed or the component was removed"
}
func receiver[T any](mc *vm.Machine, w []vm.Value, typ schema.TypeID, miss string) (*Ctx, *T, error) {
x, err := ctxOf(mc)
if err != nil {
return nil, nil, err
}
if x.Scene == nil {
return nil, nil, errNoTarget
}
h := NodeOf(w[0])
if !x.Scene.IsAlive(h) {
return nil, nil, &vm.Fault{Code: vm.CodeNil, Message: miss}
}
p, ok := x.Scene.GetByType(h, typ)
if !ok {
return nil, nil, &vm.Fault{Code: vm.CodeNil, Message: miss}
}
x.Recv = h
return x, (*T)(p), nil
}
func (m *Module) component(name string) bool {
if m.method {
m.valid(name, errMethodModule)
return false
}
return true
}
func Guard(m *Module, fn func()) error {
before := len(m.reg.errs)
fn()
if len(m.reg.errs) == before {
return nil
}
err := errors.Join(m.reg.errs[before:]...)
m.reg.errs = m.reg.errs[:before]
return err
}
func nodeParams(rest ...abi.TypeRef) []abi.TypeRef {
return append([]abi.TypeRef{abi.T(abi.NodeRef)}, rest...)
}
func Method0[T, R any](m *Module, name string, typ schema.TypeID, f func(*Ctx, *T) R, opts ...Option) {
cr, er := codecOf[R](m.reg)
if !m.component(name) || !m.valid(name, er) {
return
}
miss := missing[T](name)
m.addRecv(name, nodeParams(), cr.ref, func(mc *vm.Machine, w []vm.Value) error {
x, p, err := receiver[T](mc, w, typ, miss)
if p == nil {
return err
}
cr.put(mc, w, f(x, p))
return x.finish()
}, opts)
}
func Method1[T, A, R any](m *Module, name string, typ schema.TypeID, f func(*Ctx, *T, A) R, opts ...Option) {
ca, ea := codecOf[A](m.reg)
cr, er := codecOf[R](m.reg)
if !m.component(name) || !m.valid(name, ea, er) {
return
}
miss := missing[T](name)
m.addRecv(name, nodeParams(ca.ref), cr.ref, func(mc *vm.Machine, w []vm.Value) error {
x, p, err := receiver[T](mc, w, typ, miss)
if p == nil {
return err
}
a := ca.get(mc, w[1:])
cr.put(mc, w, f(x, p, a))
return x.finish()
}, opts)
}
func Method2[T, A, B, R any](m *Module, name string, typ schema.TypeID, f func(*Ctx, *T, A, B) R, opts ...Option) {
ca, ea := codecOf[A](m.reg)
cb, eb := codecOf[B](m.reg)
cr, er := codecOf[R](m.reg)
if !m.component(name) || !m.valid(name, ea, eb, er) {
return
}
miss := missing[T](name)
ob := 1 + ca.slots
m.addRecv(name, nodeParams(ca.ref, cb.ref), cr.ref, func(mc *vm.Machine, w []vm.Value) error {
x, p, err := receiver[T](mc, w, typ, miss)
if p == nil {
return err
}
a, b := ca.get(mc, w[1:]), cb.get(mc, w[ob:])
cr.put(mc, w, f(x, p, a, b))
return x.finish()
}, opts)
}
func MethodProc0[T any](m *Module, name string, typ schema.TypeID, f func(*Ctx, *T), opts ...Option) {
if !m.component(name) {
return
}
miss := missing[T](name)
m.addRecv(name, nodeParams(), abi.T(abi.Void), func(mc *vm.Machine, w []vm.Value) error {
x, p, err := receiver[T](mc, w, typ, miss)
if p == nil {
return err
}
f(x, p)
return x.finish()
}, opts)
}
func MethodProc1[T, A any](m *Module, name string, typ schema.TypeID, f func(*Ctx, *T, A), opts ...Option) {
ca, ea := codecOf[A](m.reg)
if !m.component(name) || !m.valid(name, ea) {
return
}
miss := missing[T](name)
m.addRecv(name, nodeParams(ca.ref), abi.T(abi.Void), func(mc *vm.Machine, w []vm.Value) error {
x, p, err := receiver[T](mc, w, typ, miss)
if p == nil {
return err
}
f(x, p, ca.get(mc, w[1:]))
return x.finish()
}, opts)
}
func MethodProc2[T, A, B any](m *Module, name string, typ schema.TypeID, f func(*Ctx, *T, A, B), opts ...Option) {
ca, ea := codecOf[A](m.reg)
cb, eb := codecOf[B](m.reg)
if !m.component(name) || !m.valid(name, ea, eb) {
return
}
miss := missing[T](name)
ob := 1 + ca.slots
m.addRecv(name, nodeParams(ca.ref, cb.ref), abi.T(abi.Void), func(mc *vm.Machine, w []vm.Value) error {
x, p, err := receiver[T](mc, w, typ, miss)
if p == nil {
return err
}
f(x, p, ca.get(mc, w[1:]), cb.get(mc, w[ob:]))
return x.finish()
}, opts)
}