package luajit /* #include #include #include extern int goFunctionWrapper(lua_State* L); static int get_upvalue_index(int i) { return -10002 - i; // LUA_GLOBALSINDEX - i } */ import "C" import ( "fmt" "sync" "unsafe" ) type GoFunction func(*State) int var ( functionRegistry = struct { sync.RWMutex funcs map[unsafe.Pointer]GoFunction }{ funcs: make(map[unsafe.Pointer]GoFunction), } ) //export goFunctionWrapper func goFunctionWrapper(L *C.lua_State) C.int { state := &State{L: L, safeStack: true} // Get upvalue using standard Lua 5.1 macro ptr := C.lua_touserdata(L, C.get_upvalue_index(1)) if ptr == nil { state.PushString("error: function not found") return -1 } functionRegistry.RLock() fn, ok := functionRegistry.funcs[ptr] functionRegistry.RUnlock() if !ok { state.PushString("error: function not found in registry") return -1 } result := fn(state) return C.int(result) } func (s *State) PushGoFunction(fn GoFunction) error { // Push lightuserdata as upvalue and create closure ptr := C.malloc(1) if ptr == nil { return fmt.Errorf("failed to allocate memory for function pointer") } functionRegistry.Lock() functionRegistry.funcs[ptr] = fn functionRegistry.Unlock() C.lua_pushlightuserdata(s.L, ptr) C.lua_pushcclosure(s.L, (*[0]byte)(C.goFunctionWrapper), 1) return nil } func (s *State) RegisterGoFunction(name string, fn GoFunction) error { if err := s.PushGoFunction(fn); err != nil { return err } cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) C.lua_setfield(s.L, C.LUA_GLOBALSINDEX, cname) return nil } func (s *State) UnregisterGoFunction(name string) { s.PushNil() cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) C.lua_setfield(s.L, C.LUA_GLOBALSINDEX, cname) } func (s *State) Cleanup() { functionRegistry.Lock() defer functionRegistry.Unlock() for ptr := range functionRegistry.funcs { C.free(ptr) } functionRegistry.funcs = make(map[unsafe.Pointer]GoFunction) }