diff options
| author | unwox <me@unwox.com> | 2024-09-14 15:51:23 +0600 |
|---|---|---|
| committer | unwox <me@unwox.com> | 2024-09-14 15:51:23 +0600 |
| commit | 986522e417406956e83362e08adbd6a18ec904a5 (patch) | |
| tree | 598fd241569c845acd6a604cdf88942e146237de | |
| parent | a6412f9fc48f410ba4e3b39938d8d3f6a5597066 (diff) | |
better handling of args coming from lua with l.Scan
| -rw-r--r-- | lua.go | 72 | ||||
| -rw-r--r-- | main.go | 35 |
2 files changed, 86 insertions, 21 deletions
@@ -22,7 +22,9 @@ import "C" import ( "errors" "fmt" + "reflect" "runtime/cgo" + "slices" "unsafe" ) @@ -231,6 +233,76 @@ func (l *Lua) LoadString(code string) error { return nil } +// Scan scans values from the Lua stack into vars according to their types. +func (l *Lua) Scan(vars ...any) error { + slices.Reverse(vars) + for i, v := range vars { + t := reflect.TypeOf(v) + // unwrap pointers + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + tk := t.Kind() + if t.Name() == "LuaRef" { + if l.IsFunction(-1) == false { + return fmt.Errorf( + "passed arg #%d must be function", + len(vars)-i, + ) + } + *v.(*LuaRef) = l.PopToRef() + } else if tk == reflect.String { + if l.IsString(-1) == false { + return fmt.Errorf( + "passed arg #%d must be string", + len(vars)-i, + ) + } + *v.(*string) = l.ToString(-1) + l.Pop(1) + } else if tk == reflect.Int { + if l.IsNumber(-1) == false { + return fmt.Errorf( + "passed arg #%d must be number", + len(vars)-i, + ) + } + *v.(*int) = l.ToInt(-1) + l.Pop(1) + } else if tk == reflect.Map && t.Key().Kind() == reflect.String { + // TODO: should be possible to use maps with any types + // of value, not only strings. + vm, _ := v.(*map[string]string) + l.PushNil() + for l.Next() { + if !l.IsString(-1) { + return fmt.Errorf( + "map arg #%d must only have string values", + len(vars)-i, + ) + } + if !l.IsString(-2) { + return fmt.Errorf( + "map arg #%d must only have string keys", + len(vars)-i, + ) + } + iv := l.ToString(-1) + l.Pop(1) + // We must not pop the item key from the stack + // because otherwise C.lua_next won't work + // properly. + k := l.ToString(-1) + (*vm)[k] = iv + } + l.Pop(1) + } else { + return fmt.Errorf("unknown var type: %s", t) + } + } + return nil +} + // RestoreStackFunc remembers the Lua stack size and then restores it when a // returned function is called. It's a helper function to avoid stack leakage. func (l *Lua) RestoreStackFunc() func () { @@ -37,9 +37,14 @@ func main() { // define luna.router module routeModule := make(map[string]any) routeModule["route"] = func (l *Lua) int { - fn := l.PopToRef() - route := l.ToString(-1) - l.Pop(1) + var route string + var fn LuaRef + err := l.Scan(&route, &fn) + if err != nil { + fmt.Println("error:", err) + // FIXME: handle + return 0 + } // find corresponding worker for the lua context var wrk *Worker for _, wrk = range wrks { @@ -84,26 +89,14 @@ func main() { // define luna.http module httpModule := make(map[string]any) httpModule["request"] = func (l *Lua) int { - body := l.ToString(-1) - url := l.ToString(-3) - method := l.ToString(-4) - l.Pop(1) + var method, url, body string headers := make(map[string]string) - l.PushNil() - for l.Next() { - if !l.IsString(-2) || !l.IsString(-2) { - l.Pop(1) - continue - } - v := l.ToString(-1) - l.Pop(1) - // We must not pop the item key from the stack - // because otherwise C.lua_next won't work - // properly. - k := l.ToString(-1) - headers[k] = v + err := l.Scan(&method, &url, &headers, &body) + if err != nil { + // FIXME: handle + fmt.Println("error:", err) + return 0 } - l.Pop(2) req, err := http.NewRequest(method, url, strings.NewReader(body)) if err != nil { |
