From 239426692e3ab70dd7a30c688ae1d56352d3501e Mon Sep 17 00:00:00 2001 From: James Hillyerd Date: Wed, 8 Feb 2023 13:38:00 -0800 Subject: [PATCH] lua: Use table syntax for user object bindings (#325) * lua: update bind_message to use table syntax * lua: update bind_address to use table syntax --- pkg/extension/luahost/bind_address.go | 58 ++++++---- pkg/extension/luahost/bind_message.go | 158 ++++++++++---------------- pkg/extension/luahost/lua_test.go | 20 ++-- 3 files changed, 101 insertions(+), 135 deletions(-) diff --git a/pkg/extension/luahost/bind_address.go b/pkg/extension/luahost/bind_address.go index e3ed4c3..d659309 100644 --- a/pkg/extension/luahost/bind_address.go +++ b/pkg/extension/luahost/bind_address.go @@ -16,12 +16,8 @@ func registerMailAddressType(ls *lua.LState) { ls.SetField(mt, "new", ls.NewFunction(newMailAddress)) // Methods. - ls.SetField(mt, "__index", ls.SetFuncs(ls.NewTable(), mailAddressMethods)) -} - -var mailAddressMethods = map[string]lua.LGFunction{ - "address": mailAddressGetSetAddress, - "name": mailAddressGetSetName, + ls.SetField(mt, "__index", ls.NewFunction(mailAddressIndex)) + ls.SetField(mt, "__newindex", ls.NewFunction(mailAddressNewIndex)) } func newMailAddress(ls *lua.LState) int { @@ -48,8 +44,8 @@ func unwrapMailAddress(ud *lua.LUserData) (*mail.Address, bool) { return val, ok } -func checkMailAddress(ls *lua.LState) *mail.Address { - ud := ls.CheckUserData(1) +func checkMailAddress(ls *lua.LState, pos int) *mail.Address { + ud := ls.CheckUserData(pos) if val, ok := ud.Value.(*mail.Address); ok { return val } @@ -57,28 +53,40 @@ func checkMailAddress(ls *lua.LState) *mail.Address { return nil } -func mailAddressGetSetAddress(ls *lua.LState) int { - val := checkMailAddress(ls) - if ls.GetTop() == 2 { - // Setter. - val.Address = ls.CheckString(2) - return 0 +// Gets a field value from MailAddress user object. This emulates a Lua table, +// allowing `msg.subject` instead of a Lua object syntax of `msg:subject()`. +func mailAddressIndex(ls *lua.LState) int { + a := checkMailAddress(ls, 1) + field := ls.CheckString(2) + + // Push the requested field's value onto the stack. + switch field { + case "name": + ls.Push(lua.LString(a.Name)) + case "address": + ls.Push(lua.LString(a.Address)) + default: + // Unknown field. + ls.Push(lua.LNil) } - // Getter. - ls.Push(lua.LString(val.Address)) return 1 } -func mailAddressGetSetName(ls *lua.LState) int { - val := checkMailAddress(ls) - if ls.GetTop() == 2 { - // Setter. - val.Name = ls.CheckString(2) - return 0 +// Sets a field value on MailAddress user object. This emulates a Lua table, +// allowing `msg.subject = x` instead of a Lua object syntax of `msg:subject(x)`. +func mailAddressNewIndex(ls *lua.LState) int { + a := checkMailAddress(ls, 1) + index := ls.CheckString(2) + + switch index { + case "name": + a.Name = ls.CheckString(3) + case "address": + a.Address = ls.CheckString(3) + default: + ls.RaiseError("invalid index %q", index) } - // Getter. - ls.Push(lua.LString(val.Name)) - return 1 + return 0 } diff --git a/pkg/extension/luahost/bind_message.go b/pkg/extension/luahost/bind_message.go index 28ecfa2..bd308de 100644 --- a/pkg/extension/luahost/bind_message.go +++ b/pkg/extension/luahost/bind_message.go @@ -18,17 +18,8 @@ func registerMessageMetadataType(ls *lua.LState) { ls.SetField(mt, "new", ls.NewFunction(newMessageMetadata)) // Methods. - ls.SetField(mt, "__index", ls.SetFuncs(ls.NewTable(), messageMetadataMethods)) -} - -var messageMetadataMethods = map[string]lua.LGFunction{ - "mailbox": messageMetadataGetSetMailbox, - "id": messageMetadataGetSetID, - "from": messageMetadataGetSetFrom, - "to": messageMetadataGetSetTo, - "subject": messageMetadataGetSetSubject, - "date": messageMetadataGetSetDate, - "size": messageMetadataGetSetSize, + ls.SetField(mt, "__index", ls.NewFunction(messageMetadataIndex)) + ls.SetField(mt, "__newindex", ls.NewFunction(messageMetadataNewIndex)) } func newMessageMetadata(ls *lua.LState) int { @@ -47,8 +38,8 @@ func wrapMessageMetadata(ls *lua.LState, val *event.MessageMetadata) *lua.LUserD return ud } -func checkMessageMetadata(ls *lua.LState) *event.MessageMetadata { - ud := ls.CheckUserData(1) +func checkMessageMetadata(ls *lua.LState, pos int) *event.MessageMetadata { + ud := ls.CheckUserData(pos) if v, ok := ud.Value.(*event.MessageMetadata); ok { return v } @@ -56,51 +47,56 @@ func checkMessageMetadata(ls *lua.LState) *event.MessageMetadata { return nil } -func messageMetadataGetSetMailbox(ls *lua.LState) int { - val := checkMessageMetadata(ls) - if ls.GetTop() == 2 { - // Setter. - val.Mailbox = ls.CheckString(2) - return 0 +// Gets a field value from MessageMetadata user object. This emulates a Lua table, +// allowing `msg.subject` instead of a Lua object syntax of `msg:subject()`. +func messageMetadataIndex(ls *lua.LState) int { + m := checkMessageMetadata(ls, 1) + field := ls.CheckString(2) + + // Push the requested field's value onto the stack. + switch field { + case "mailbox": + ls.Push(lua.LString(m.Mailbox)) + case "id": + ls.Push(lua.LString(m.ID)) + case "from": + ls.Push(wrapMailAddress(ls, m.From)) + case "to": + lt := &lua.LTable{} + for _, v := range m.To { + lt.Append(wrapMailAddress(ls, v)) + } + ls.Push(lt) + case "date": + ls.Push(lua.LNumber(m.Date.Unix())) + case "subject": + ls.Push(lua.LString(m.Subject)) + case "size": + ls.Push(lua.LNumber(m.Size)) + default: + // Unknown field. + ls.Push(lua.LNil) } - // Getter. - ls.Push(lua.LString(val.Mailbox)) return 1 } -func messageMetadataGetSetID(ls *lua.LState) int { - val := checkMessageMetadata(ls) - if ls.GetTop() == 2 { - // Setter. - val.ID = ls.CheckString(2) - return 0 - } +// Sets a field value on MessageMetadata user object. This emulates a Lua table, +// allowing `msg.subject = x` instead of a Lua object syntax of `msg:subject(x)`. +func messageMetadataNewIndex(ls *lua.LState) int { + m := checkMessageMetadata(ls, 1) + index := ls.CheckString(2) - // Getter. - ls.Push(lua.LString(val.ID)) - return 1 -} - -func messageMetadataGetSetFrom(ls *lua.LState) int { - val := checkMessageMetadata(ls) - if ls.GetTop() == 2 { - // Setter. - val.From = checkMailAddress(ls) - return 0 - } - - // Getter. - ls.Push(wrapMailAddress(ls, val.From)) - return 1 -} - -func messageMetadataGetSetTo(ls *lua.LState) int { - val := checkMessageMetadata(ls) - if ls.GetTop() == 2 { - // Setter. - lt := ls.CheckTable(2) - to := make([]*mail.Address, lt.Len()) + switch index { + case "mailbox": + m.Mailbox = ls.CheckString(3) + case "id": + m.ID = ls.CheckString(3) + case "from": + m.From = checkMailAddress(ls, 3) + case "to": + lt := ls.CheckTable(3) + to := make([]*mail.Address, 0, 16) lt.ForEach(func(k, lv lua.LValue) { if ud, ok := lv.(*lua.LUserData); ok { if entry, ok := unwrapMailAddress(ud); ok { @@ -108,54 +104,16 @@ func messageMetadataGetSetTo(ls *lua.LState) int { } } }) - val.To = to - return 0 + m.To = to + case "date": + m.Date = time.Unix(ls.CheckInt64(3), 0) + case "subject": + m.Subject = ls.CheckString(3) + case "size": + m.Size = ls.CheckInt64(3) + default: + ls.RaiseError("invalid index %q", index) } - // Getter. - lt := &lua.LTable{} - for _, v := range val.To { - lt.Append(wrapMailAddress(ls, v)) - } - ls.Push(lt) - return 1 -} - -func messageMetadataGetSetSubject(ls *lua.LState) int { - val := checkMessageMetadata(ls) - if ls.GetTop() == 2 { - // Setter. - val.Subject = ls.CheckString(2) - return 0 - } - - // Getter. - ls.Push(lua.LString(val.Subject)) - return 1 -} - -func messageMetadataGetSetDate(ls *lua.LState) int { - val := checkMessageMetadata(ls) - if ls.GetTop() == 2 { - // Setter. - val.Date = time.Unix(ls.CheckInt64(2), 0) - return 0 - } - - // Getter. - ls.Push(lua.LNumber(val.Date.Unix())) - return 1 -} - -func messageMetadataGetSetSize(ls *lua.LState) int { - val := checkMessageMetadata(ls) - if ls.GetTop() == 2 { - // Setter. - val.Size = ls.CheckInt64(2) - return 0 - } - - // Getter. - ls.Push(lua.LNumber(val.Size)) - return 1 + return 0 } diff --git a/pkg/extension/luahost/lua_test.go b/pkg/extension/luahost/lua_test.go index 012af5d..b0de09d 100644 --- a/pkg/extension/luahost/lua_test.go +++ b/pkg/extension/luahost/lua_test.go @@ -35,19 +35,19 @@ func TestAfterMessageStored(t *testing.T) { end function after_message_stored(msg) - assert_eq(msg:mailbox(), "mb1") - assert_eq(msg:id(), "id1") - assert_eq(msg:subject(), "subj1") - assert_eq(msg:size(), 42) + assert_eq(msg.mailbox, "mb1") + assert_eq(msg.id, "id1") + assert_eq(msg.subject, "subj1") + assert_eq(msg.size, 42) - assert_eq(msg:from():name(), "name1") - assert_eq(msg:from():address(), "addr1") + assert_eq(msg.from.name, "name1") + assert_eq(msg.from.address, "addr1") - assert_eq(table.getn(msg:to()), 1) - assert_eq(msg:to()[1]:name(), "name2") - assert_eq(msg:to()[1]:address(), "addr2") + assert_eq(table.getn(msg.to), 1) + assert_eq(msg.to[1].name, "name2") + assert_eq(msg.to[1].address, "addr2") - assert_eq(msg:date(), 981173106) + assert_eq(msg.date, 981173106) notify:send(test_ok) end