hashmap.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 Hash class in Lua
  9. const lHashClass = "HASH"
  10. // Get the first argument, "self", and cast it from userdata to a hash map.
  11. func checkHash(L *lua.LState) pinterface.IHashMap {
  12. ud := L.CheckUserData(1)
  13. if hash, ok := ud.Value.(pinterface.IHashMap); ok {
  14. return hash
  15. }
  16. L.ArgError(1, "hash map expected")
  17. return nil
  18. }
  19. // Create a new hash map.
  20. // id is the name of the hash map.
  21. // dbindex is the Redis database index (typically 0).
  22. func newHashMap(L *lua.LState, creator pinterface.ICreator, id string) (*lua.LUserData, error) {
  23. // Create a new hash map
  24. hash, err := creator.NewHashMap(id)
  25. if err != nil {
  26. return nil, err
  27. }
  28. // Create a new userdata struct
  29. ud := L.NewUserData()
  30. ud.Value = hash
  31. L.SetMetatable(ud, L.GetTypeMetatable(lHashClass))
  32. return ud, nil
  33. }
  34. // String representation
  35. // Returns all keys in the hash map as a comma separated string
  36. // tostring(hash) -> string
  37. func hashToString(L *lua.LState) int {
  38. hash := checkHash(L) // arg 1
  39. all, err := hash.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. // For a given element id (for instance a user id), set a key (for instance "password") and a value.
  48. // Returns true if successful.
  49. // hash:set(string, string, string) -> bool
  50. func hashSet(L *lua.LState) int {
  51. hash := checkHash(L) // arg 1
  52. elementid := L.CheckString(2)
  53. key := L.CheckString(3)
  54. value := L.ToString(4)
  55. L.Push(lua.LBool(nil == hash.Set(elementid, key, value)))
  56. return 1 // Number of returned values
  57. }
  58. // For a given element id (for instance a user id), and a key (for instance "password"), return a value.
  59. // Returns a value only if they key was found and if there were no errors.
  60. // hash:get(string, string) -> string
  61. func hashGet(L *lua.LState) int {
  62. hash := checkHash(L) // arg 1
  63. elementid := L.CheckString(2)
  64. key := L.CheckString(3)
  65. retval, err := hash.Get(elementid, key)
  66. if err != nil {
  67. retval = ""
  68. }
  69. L.Push(lua.LString(retval))
  70. return 1 // Number of returned values
  71. }
  72. // For a given element id (for instance a user id), and a key (for instance "password"), check if it exists in the hash map.
  73. // Returns true only if it exists and there were no errors.
  74. // hash:has(string, string) -> bool
  75. func hashHas(L *lua.LState) int {
  76. hash := checkHash(L) // arg 1
  77. elementid := L.CheckString(2)
  78. key := L.CheckString(3)
  79. b, err := hash.Has(elementid, key)
  80. if err != nil {
  81. b = false
  82. }
  83. L.Push(lua.LBool(b))
  84. return 1 // Number of returned values
  85. }
  86. // For a given element id (for instance a user id), check if it exists in the hash map.
  87. // Returns true only if it exists and there were no errors.
  88. // hash:exists(string) -> bool
  89. func hashExists(L *lua.LState) int {
  90. hash := checkHash(L) // arg 1
  91. elementid := L.CheckString(2)
  92. b, err := hash.Exists(elementid)
  93. if err != nil {
  94. b = false
  95. }
  96. L.Push(lua.LBool(b))
  97. return 1 // Number of returned values
  98. }
  99. // Get all keys of the hash map
  100. // hash::getall() -> table
  101. func hashAll(L *lua.LState) int {
  102. hash := checkHash(L) // arg 1
  103. all, err := hash.All()
  104. if err != nil {
  105. // Return an empty table
  106. L.Push(L.NewTable())
  107. return 1 // Number of returned values
  108. }
  109. L.Push(convert.Strings2table(L, all))
  110. return 1 // Number of returned values
  111. }
  112. // Get all subkeys of the hash map
  113. // hash::keys() -> table
  114. func hashKeys(L *lua.LState) int {
  115. hash := checkHash(L) // arg 1
  116. elementid := L.CheckString(2)
  117. keys, err := hash.Keys(elementid)
  118. if err != nil {
  119. // Return an empty table
  120. L.Push(L.NewTable())
  121. return 1 // Number of returned values
  122. }
  123. L.Push(convert.Strings2table(L, keys))
  124. return 1 // Number of returned values
  125. }
  126. // Remove a key for an entry in a hash map (for instance the email field for a user)
  127. // Returns true if successful
  128. // hash:delkey(string, string) -> bool
  129. func hashDelKey(L *lua.LState) int {
  130. hash := checkHash(L) // arg 1
  131. elementid := L.CheckString(2)
  132. key := L.CheckString(3)
  133. L.Push(lua.LBool(nil == hash.DelKey(elementid, key)))
  134. return 1 // Number of returned values
  135. }
  136. // Remove an element (for instance a user)
  137. // Returns true if successful
  138. // hash:del(string) -> bool
  139. func hashDel(L *lua.LState) int {
  140. hash := checkHash(L) // arg 1
  141. elementid := L.CheckString(2)
  142. L.Push(lua.LBool(nil == hash.Del(elementid)))
  143. return 1 // Number of returned values
  144. }
  145. // Remove the hash map itself. Returns true if successful.
  146. // hash:remove() -> bool
  147. func hashRemove(L *lua.LState) int {
  148. hash := checkHash(L) // arg 1
  149. L.Push(lua.LBool(nil == hash.Remove()))
  150. return 1 // Number of returned values
  151. }
  152. // Clear the hash map. Returns true if successful.
  153. // hash:clear() -> bool
  154. func hashClear(L *lua.LState) int {
  155. hash := checkHash(L) // arg 1
  156. L.Push(lua.LBool(nil == hash.Clear()))
  157. return 1 // Number of returned values
  158. }
  159. // The hash map methods that are to be registered
  160. var hashMethods = map[string]lua.LGFunction{
  161. "__tostring": hashToString,
  162. "set": hashSet,
  163. "get": hashGet,
  164. "has": hashHas,
  165. "exists": hashExists,
  166. "getall": hashAll,
  167. "keys": hashKeys,
  168. "delkey": hashDelKey,
  169. "del": hashDel,
  170. "remove": hashRemove,
  171. "clear": hashClear,
  172. }
  173. // LoadHash makes functions related to HTTP requests and responses available to Lua scripts
  174. func LoadHash(L *lua.LState, creator pinterface.ICreator) {
  175. // Register the hash map class and the methods that belongs with it.
  176. mt := L.NewTypeMetatable(lHashClass)
  177. mt.RawSetH(lua.LString("__index"), mt)
  178. L.SetFuncs(mt, hashMethods)
  179. // The constructor for new hash maps takes a name and an optional redis db index
  180. L.SetGlobal("HashMap", L.NewFunction(func(L *lua.LState) int {
  181. name := L.CheckString(1)
  182. // Check if the optional argument is given
  183. if L.GetTop() == 2 {
  184. localDBIndex := L.ToInt(2)
  185. // Set the DB index, if possible
  186. switch rh := creator.(type) {
  187. case pinterface.IRedisCreator:
  188. rh.SelectDatabase(localDBIndex)
  189. }
  190. }
  191. // Create a new hash map in Lua
  192. userdata, err := newHashMap(L, creator, name)
  193. if err != nil {
  194. L.Push(lua.LNil)
  195. L.Push(lua.LString(err.Error()))
  196. L.Push(lua.LNumber(1))
  197. return 3 // Number of returned values
  198. }
  199. // Return the hash map object
  200. L.Push(userdata)
  201. return 1 // Number of returned values
  202. }))
  203. }