list.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package datastruct
  2. import (
  3. "strings"
  4. "github.com/xyproto/algernon/lua/convert"
  5. lua "github.com/xyproto/gopher-lua"
  6. "github.com/xyproto/pinterface"
  7. )
  8. // Identifier for the List class in Lua
  9. const lListClass = "LIST"
  10. // Get the first argument, "self", and cast it from userdata to a list.
  11. func checkList(L *lua.LState) pinterface.IList {
  12. ud := L.CheckUserData(1)
  13. if list, ok := ud.Value.(pinterface.IList); ok {
  14. return list
  15. }
  16. L.ArgError(1, "list expected")
  17. return nil
  18. }
  19. // Create a new list.
  20. // id is the name of the list.
  21. // dbindex is the Redis database index (typically 0).
  22. func newList(L *lua.LState, creator pinterface.ICreator, id string) (*lua.LUserData, error) {
  23. // Create a new list
  24. list, err := creator.NewList(id)
  25. if err != nil {
  26. return nil, err
  27. }
  28. // Create a new userdata struct
  29. ud := L.NewUserData()
  30. ud.Value = list
  31. L.SetMetatable(ud, L.GetTypeMetatable(lListClass))
  32. return ud, nil
  33. }
  34. // String representation
  35. // Returns the entire list as a comma separated string
  36. // tostring(list) -> string
  37. func listToString(L *lua.LState) int {
  38. list := checkList(L) // arg 1
  39. all, err := list.All()
  40. if err != nil {
  41. L.Push(lua.LString(""))
  42. return 1 // Number of returned values
  43. }
  44. L.Push(lua.LString(strings.Join(all, ", ")))
  45. return 1 // Number of returned values
  46. }
  47. // Add an element to the list
  48. // list:add(string)
  49. func listAdd(L *lua.LState) int {
  50. list := checkList(L) // arg 1
  51. value := L.ToString(2)
  52. list.Add(value)
  53. return 0 // Number of returned values
  54. }
  55. // Get all members of the list
  56. // list::getall() -> table
  57. func listAll(L *lua.LState) int {
  58. list := checkList(L) // arg 1
  59. all, err := list.All()
  60. if err != nil {
  61. // Return an empty table
  62. L.Push(L.NewTable())
  63. return 1 // Number of returned values
  64. }
  65. L.Push(convert.Strings2table(L, all))
  66. return 1 // Number of returned values
  67. }
  68. // Return the list as a JSON list (assumes the elements to be in JSON already)
  69. // list::json() -> string
  70. func listJSON(L *lua.LState) int {
  71. list := checkList(L) // arg 1
  72. all, err := list.All()
  73. if err != nil {
  74. // Return an empty JSON list
  75. L.Push(lua.LString("[]"))
  76. return 1 // Number of returned values
  77. }
  78. L.Push(lua.LString("[" + strings.Join(all, ",") + "]"))
  79. return 1 // Number of returned values
  80. }
  81. // Get the last element of the list
  82. // The returned value can be empty
  83. // list::getlast() -> string
  84. func listLast(L *lua.LState) int {
  85. list := checkList(L) // arg 1
  86. value, err := list.Last()
  87. if err != nil {
  88. value = ""
  89. }
  90. L.Push(lua.LString(value))
  91. return 1 // Number of returned values
  92. }
  93. // Get the N last elements of the list
  94. // list::getlastn(number) -> table
  95. func listLastN(L *lua.LState) int {
  96. list := checkList(L) // arg 1
  97. n := int(L.ToNumber(2)) // arg 2
  98. results, err := list.LastN(n)
  99. if err != nil {
  100. // Return an empty table
  101. L.Push(L.NewTable())
  102. return 1 // Number of returned values
  103. }
  104. L.Push(convert.Strings2table(L, results))
  105. return 1 // Number of returned values
  106. }
  107. // Remove the list itself. Returns true if successful.
  108. // list:remove() -> bool
  109. func listRemove(L *lua.LState) int {
  110. list := checkList(L) // arg 1
  111. L.Push(lua.LBool(nil == list.Remove()))
  112. return 1 // Number of returned values
  113. }
  114. // Clear the list. Returns true if successful.
  115. // list:clear() -> bool
  116. func listClear(L *lua.LState) int {
  117. list := checkList(L) // arg 1
  118. L.Push(lua.LBool(nil == list.Clear()))
  119. return 1 // Number of returned values
  120. }
  121. // The list methods that are to be registered
  122. var listMethods = map[string]lua.LGFunction{
  123. "__tostring": listToString,
  124. "add": listAdd,
  125. "getall": listAll,
  126. "getlast": listLast,
  127. "getlastn": listLastN,
  128. "remove": listRemove,
  129. "clear": listClear,
  130. "json": listJSON,
  131. }
  132. // LoadList makes functions related to HTTP requests and responses available to Lua scripts
  133. func LoadList(L *lua.LState, creator pinterface.ICreator) {
  134. // Register the list class and the methods that belongs with it.
  135. mt := L.NewTypeMetatable(lListClass)
  136. mt.RawSetH(lua.LString("__index"), mt)
  137. L.SetFuncs(mt, listMethods)
  138. // The constructor for new lists takes a name and an optional redis db index
  139. L.SetGlobal("List", L.NewFunction(func(L *lua.LState) int {
  140. name := L.CheckString(1)
  141. // Check if the optional argument is given
  142. if L.GetTop() == 2 {
  143. localDBIndex := L.ToInt(2)
  144. // Set the DB index, if possible
  145. switch rh := creator.(type) {
  146. case pinterface.IRedisCreator:
  147. rh.SelectDatabase(localDBIndex)
  148. }
  149. }
  150. // Create a new list in Lua
  151. userdata, err := newList(L, creator, name)
  152. if err != nil {
  153. L.Push(lua.LNil)
  154. L.Push(lua.LString(err.Error()))
  155. L.Push(lua.LNumber(1))
  156. return 3 // Number of returned values
  157. }
  158. // Return the list object
  159. L.Push(userdata)
  160. return 1 // Number of returned values
  161. }))
  162. }