ledisdb/_vendor/vendor/github.com/siddontang/golua/golua.go

253 lines
5.3 KiB
Go
Raw Normal View History

2014-09-13 10:11:05 +04:00
package lua
/*
#cgo CFLAGS: -Ilua
2014-09-13 10:11:05 +04:00
#include <lua.h>
#include <lualib.h>
#include <stdlib.h>
*/
import "C"
import (
"reflect"
"sync"
2014-09-13 10:11:05 +04:00
"unsafe"
)
// Type of allocation functions to use with NewStateAlloc
type Alloc func(ptr unsafe.Pointer, osize uint, nsize uint) unsafe.Pointer
// This is the type of go function that can be registered as lua functions
type LuaGoFunction func(L *State) int
// Wrapper to keep cgo from complaining about incomplete ptr type
//export State
type State struct {
// Wrapped lua_State object
s *C.lua_State
// index of this object inside the goStates array
Index uintptr
2014-09-13 10:11:05 +04:00
// Registry of go object that have been pushed to Lua VM
registry []interface{}
// Freelist for funcs indices, to allow for freeing
freeIndices []uint
}
var goStates map[uintptr]*State
var goStatesMutex sync.Mutex
func init() {
goStates = make(map[uintptr]*State, 16)
}
func registerGoState(L *State) {
goStatesMutex.Lock()
defer goStatesMutex.Unlock()
L.Index = uintptr(unsafe.Pointer(L))
goStates[L.Index] = L
}
func unregisterGoState(L *State) {
goStatesMutex.Lock()
defer goStatesMutex.Unlock()
delete(goStates, L.Index)
}
func getGoState(gostateindex uintptr) *State {
goStatesMutex.Lock()
defer goStatesMutex.Unlock()
return goStates[gostateindex]
}
2014-09-13 10:11:05 +04:00
//export golua_callgofunction
func golua_callgofunction(gostateindex uintptr, fid uint) int {
L1 := getGoState(gostateindex)
2014-09-13 10:11:05 +04:00
if fid < 0 {
panic(&LuaError{0, "Requested execution of an unknown function", L1.StackTrace()})
}
f := L1.registry[fid].(LuaGoFunction)
return f(L1)
}
//export golua_interface_newindex_callback
func golua_interface_newindex_callback(gostateindex uintptr, iid uint, field_name_cstr *C.char) int {
L := getGoState(gostateindex)
2014-09-13 10:11:05 +04:00
iface := L.registry[iid]
ifacevalue := reflect.ValueOf(iface).Elem()
field_name := C.GoString(field_name_cstr)
fval := ifacevalue.FieldByName(field_name)
if fval.Kind() == reflect.Ptr {
fval = fval.Elem()
}
luatype := LuaValType(C.lua_type(L.s, 3))
switch fval.Kind() {
case reflect.Bool:
if luatype == LUA_TBOOLEAN {
fval.SetBool(int(C.lua_toboolean(L.s, 3)) != 0)
return 1
} else {
L.PushString("Wrong assignment to field " + field_name)
return -1
}
case reflect.Int:
fallthrough
case reflect.Int8:
fallthrough
case reflect.Int16:
fallthrough
case reflect.Int32:
fallthrough
case reflect.Int64:
if luatype == LUA_TNUMBER {
fval.SetInt(int64(C.lua_tointeger(L.s, 3)))
return 1
} else {
L.PushString("Wrong assignment to field " + field_name)
return -1
}
case reflect.Uint:
fallthrough
case reflect.Uint8:
fallthrough
case reflect.Uint16:
fallthrough
case reflect.Uint32:
fallthrough
case reflect.Uint64:
if luatype == LUA_TNUMBER {
fval.SetUint(uint64(C.lua_tointeger(L.s, 3)))
return 1
} else {
L.PushString("Wrong assignment to field " + field_name)
return -1
}
case reflect.String:
if luatype == LUA_TSTRING {
fval.SetString(C.GoString(C.lua_tolstring(L.s, 3, nil)))
return 1
} else {
L.PushString("Wrong assignment to field " + field_name)
return -1
}
case reflect.Float32:
fallthrough
case reflect.Float64:
if luatype == LUA_TNUMBER {
fval.SetFloat(float64(C.lua_tonumber(L.s, 3)))
return 1
} else {
L.PushString("Wrong assignment to field " + field_name)
return -1
}
}
L.PushString("Unsupported type of field " + field_name + ": " + fval.Type().String())
return -1
}
//export golua_interface_index_callback
func golua_interface_index_callback(gostateindex uintptr, iid uint, field_name *C.char) int {
L := getGoState(gostateindex)
2014-09-13 10:11:05 +04:00
iface := L.registry[iid]
ifacevalue := reflect.ValueOf(iface).Elem()
fval := ifacevalue.FieldByName(C.GoString(field_name))
if fval.Kind() == reflect.Ptr {
fval = fval.Elem()
}
switch fval.Kind() {
case reflect.Bool:
L.PushBoolean(fval.Bool())
return 1
case reflect.Int:
fallthrough
case reflect.Int8:
fallthrough
case reflect.Int16:
fallthrough
case reflect.Int32:
fallthrough
case reflect.Int64:
L.PushInteger(fval.Int())
return 1
case reflect.Uint:
fallthrough
case reflect.Uint8:
fallthrough
case reflect.Uint16:
fallthrough
case reflect.Uint32:
fallthrough
case reflect.Uint64:
L.PushInteger(int64(fval.Uint()))
return 1
case reflect.String:
L.PushString(fval.String())
return 1
case reflect.Float32:
fallthrough
case reflect.Float64:
L.PushNumber(fval.Float())
return 1
}
L.PushString("Unsupported type of field: " + fval.Type().String())
return -1
}
//export golua_gchook
func golua_gchook(gostateindex uintptr, id uint) int {
L1 := getGoState(gostateindex)
2014-09-13 10:11:05 +04:00
L1.unregister(id)
return 0
}
//export golua_callpanicfunction
func golua_callpanicfunction(gostateindex uintptr, id uint) int {
L1 := getGoState(gostateindex)
2014-09-13 10:11:05 +04:00
f := L1.registry[id].(LuaGoFunction)
return f(L1)
}
//export golua_idtointerface
func golua_idtointerface(id uint) interface{} {
return id
}
//export golua_cfunctiontointerface
func golua_cfunctiontointerface(f *uintptr) interface{} {
return f
}
//export golua_callallocf
func golua_callallocf(fp uintptr, ptr uintptr, osize uint, nsize uint) uintptr {
return uintptr((*((*Alloc)(unsafe.Pointer(fp))))(unsafe.Pointer(ptr), osize, nsize))
}
//export go_panic_msghandler
func go_panic_msghandler(gostateindex uintptr, z *C.char) {
L := getGoState(gostateindex)
2014-09-13 10:11:05 +04:00
s := C.GoString(z)
panic(&LuaError{LUA_ERRERR, s, L.StackTrace()})
}