summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunwox <me@unwox.com>2024-09-14 15:51:23 +0600
committerunwox <me@unwox.com>2024-09-14 15:51:23 +0600
commit986522e417406956e83362e08adbd6a18ec904a5 (patch)
tree598fd241569c845acd6a604cdf88942e146237de
parenta6412f9fc48f410ba4e3b39938d8d3f6a5597066 (diff)
better handling of args coming from lua with l.Scan
-rw-r--r--lua.go72
-rw-r--r--main.go35
2 files changed, 86 insertions, 21 deletions
diff --git a/lua.go b/lua.go
index 875aac0..8401d37 100644
--- a/lua.go
+++ b/lua.go
@@ -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 () {
diff --git a/main.go b/main.go
index 96e8a38..bde394e 100644
--- a/main.go
+++ b/main.go
@@ -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 {