// GoLuaFunc converts an arbitrary Go function into a Lua-compatible GoFunction.
// There are special optimized cases for functions that go from strings to strings,
// and doubles to doubles, but otherwise Go
// reflection is used to provide a generic wrapper function
func GoLuaFunc(L *lua.State, fun interface{}) lua.GoFunction {
	switch f := fun.(type) {
	case func(*lua.State) int:
		return f
	case func(string) string:
		return func(L *lua.State) int {
			L.PushString(f(L.ToString(1)))
			return 1
		}
	case func(float64) float64:
		return func(L *lua.State) int {
			L.PushNumber(f(L.ToNumber(1)))
			return 1
		}
	default:
	}
	var funv reflect.Value
	switch ff := fun.(type) {
	case reflect.Value:
		funv = ff
	default:
		funv = valueOf(fun)
	}
	funt := funv.Type()
	targs, tout := functionArgRetTypes(funt)
	return func(L *lua.State) int {
		var lastT reflect.Type
		isVariadic := funt.IsVariadic()
		if isVariadic {
			lastT = targs[len(targs)-1].Elem()
			targs = targs[0 : len(targs)-1]
		}
		args := make([]reflect.Value, len(targs))
		for i, t := range targs {
			val := LuaToGo(L, t, i+1)
			args[i] = valueOf(val)
		}
		if isVariadic {
			n := L.GetTop()
			for i := len(targs) + 1; i <= n; i++ {
				val := valueOf(LuaToGo(L, lastT, i))
				args = append(args, val)
			}
		}
		resv := funv.Call(args)
		for i, val := range resv {
			GoToLua(L, tout[i], val)
		}
		return len(resv)
	}
}
Exemple #2
0
// Push a Go value 'val' of type 't' on the Lua stack.
func GoToLua(L *lua.State, t reflect.Type, val reflect.Value) {
	if t == nil {
		t = val.Type()
	}
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	switch t.Kind() {
	case reflect.Float64:
	case reflect.Float32:
		{
			L.PushNumber(val.Float())
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
		{
			L.PushNumber(float64(val.Int()))
		}
	case reflect.Uint, reflect.Uint8:
		{
			L.PushNumber(float64(val.Uint()))
		}
	case reflect.String:
		{
			L.PushString(val.String())
		}
	case reflect.Bool:
		{
			L.PushBoolean(val.Bool())
		}
	case reflect.Slice:
		{
			makeValueProxy(L, val, SLICE_META)
		}
	case reflect.Map:
		{
			makeValueProxy(L, val, MAP_META)
		}
	case reflect.Struct:
		{
			makeValueProxy(L, val, STRUCT_META)
		}
	default:
		{
			// fmt.Println("unhandled go type",t,t.Kind())
			if val.IsNil() {
				L.PushNil()
			} else {
				makeValueProxy(L, val, INTERFACE_META)
			}
		}
	}
}
// Push a Go value 'val' of type 't' on the Lua stack.
// If we haven't been given a concrete type, use the type of the value
// and unbox any interfaces.
func GoToLua(L *lua.State, t reflect.Type, val reflect.Value) {
	proxify := true
	if t == nil {
		t = val.Type()
		if t.Kind() == reflect.Interface { // unbox interfaces!
			val = valueOf(val.Interface())
			t = val.Type()
		}
		proxify = false
	}
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	switch t.Kind() {
	case reflect.Float64:
	case reflect.Float32:
		{
			L.PushNumber(val.Float())
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
		{
			L.PushNumber(float64(val.Int()))
		}
	case reflect.Uint, reflect.Uint8:
		{
			L.PushNumber(float64(val.Uint()))
		}
	case reflect.String:
		{
			L.PushString(val.String())
		}
	case reflect.Bool:
		{
			L.PushBoolean(val.Bool())
		}
	case reflect.Slice:
		{
			if proxify {
				makeValueProxy(L, val, SLICE_META)
			} else {
				CopySliceToTable(L, val)
			}
		}
	case reflect.Map:
		{
			if proxify {
				makeValueProxy(L, val, MAP_META)
			} else {
				CopyMapToTable(L, val)
			}
		}
	case reflect.Struct:
		{
			makeValueProxy(L, val, STRUCT_META)
		}
	default:
		{
			if val.IsNil() {
				L.PushNil()
			} else {
				makeValueProxy(L, val, INTERFACE_META)
			}
		}
	}
}