diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2024-09-03 20:39:14 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2024-09-03 20:39:14 -0400 |
commit | f3896d37ca625a4f7060ee5139a8825c2f6e6a74 (patch) | |
tree | c10bce816c8e7834c1e485b6f71feccd48eb1906 /indra/newview | |
parent | 517163c126f7c0620f506532d67d9097083728d9 (diff) |
Generalize Lua-side result-set machinery for other use cases.
Change `result_view()` from a simple function to a callable table so we can
add conventional/default functions to it: `result_view.fetch()` is a generic
`fetch()` function suitable for use with `result_view()`, and `result_view.close()`
is a variadic function that closes result sets for whichever keys are passed.
This arises from the fact that any `LL::ResultSet` subclass is accessed
generically through its base class, therefore we don't need distinct
"getSlice" and "closeResult" operations for different `LLEventAPI` listeners.
(It might make sense to relocate those operations to a new generic listener,
but for now "LLInventory" works.)
That lets `result_view()`'s caller omit the `fetch` parameter unless it
requires special behavior. Omitting it uses the generic `result_view.fetch()`
function.
Moreover, every view returned by `result_view()` now contains a close()
function that closes that view's result set.
The table returned by LLInventory.lua's `result()` function has a `close()`
method; that method can now call `result_view.close()` with the two keys of
interest. That table's `__index()` metamethod can now leverage `result_view()`'s
default `fetch` function.
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/scripts/lua/require/LLInventory.lua | 22 | ||||
-rw-r--r-- | indra/newview/scripts/lua/require/result_view.lua | 83 |
2 files changed, 62 insertions, 43 deletions
diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua index ce501e75f3..9cf72a8678 100644 --- a/indra/newview/scripts/lua/require/LLInventory.lua +++ b/indra/newview/scripts/lua/require/LLInventory.lua @@ -15,9 +15,7 @@ local function result(keys) -- call result:close() to release result sets before garbage -- collection or script completion close = function(self) - leap.send('LLInventory', - {op='closeResult', - result={self._categories[1], self._items[1]}}) + result_view.close(self._categories[1], self._items[1]) end }, -- The caller of one of our methods that returns a result set @@ -31,17 +29,9 @@ local function result(keys) if not table.find({'categories', 'items'}, field) then return nil end - local view = result_view( - -- We cleverly saved the result set {key, length} pair in - -- a field with the same name but an underscore prefix. - t['_' .. field], - function(key, start) - local fetched = leap.request( - 'LLInventory', - {op='getSlice', result=key, index=start}) - return fetched.slice, fetched.start - end - ) + -- We cleverly saved the result set {key, length} pair in + -- a field with the same name but an underscore prefix. + local view = result_view(t['_' .. field]) -- cache that view for future reference t[field] = view return view @@ -51,8 +41,8 @@ local function result(keys) -- When the table-with-metatable above is destroyed, tell LLInventory -- we're done with its result sets -- whether or not we ever fetched -- either of them. - function(keys) - keys:close() + function(res) + res:close() end ) end diff --git a/indra/newview/scripts/lua/require/result_view.lua b/indra/newview/scripts/lua/require/result_view.lua index c719681c66..5301d7838c 100644 --- a/indra/newview/scripts/lua/require/result_view.lua +++ b/indra/newview/scripts/lua/require/result_view.lua @@ -1,34 +1,36 @@ +local leap = require 'leap' + -- metatable for every result_view() table local mt = { - __len = function(this) - return this.length + __len = function(self) + return self.length end, - __index = function(this, i) + __index = function(self, i) -- right away, convert to 0-relative indexing i -= 1 -- can we find this index within the current slice? - local reli = i - this.start - if 0 <= reli and reli < #this.slice then + local reli = i - self.start + if 0 <= reli and reli < #self.slice then -- Lua 1-relative indexing - return this.slice[reli + 1] + return self.slice[reli + 1] end -- is this index outside the overall result set? - if not (0 <= i and i < this.length) then + if not (0 <= i and i < self.length) then return nil end -- fetch a new slice starting at i, using provided fetch() local start - this.slice, start = this.fetch(this.key, i) + self.slice, start = self.fetch(self.key, i) -- It's possible that caller-provided fetch() function forgot -- to return the adjusted start index of the new slice. In -- Lua, 0 tests as true, so if fetch() returned (slice, 0), - -- we'll duly reset this.start to 0. Otherwise, assume the + -- we'll duly reset self.start to 0. Otherwise, assume the -- requested index was not adjusted: that the returned slice -- really does start at i. - this.start = start or i + self.start = start or i -- Hopefully this slice contains the desired i. -- Back to 1-relative indexing. - return this.slice[i - this.start + 1] + return self.slice[i - self.start + 1] end, -- We purposely avoid putting any array entries (int keys) into -- our table so that access to any int key will always call our @@ -40,7 +42,7 @@ local mt = { -- This result set provides read-only access. -- We do not support pushing updates to individual items back to -- C++; for the intended use cases, that makes no sense. - __newindex = function(this, i, value) + __newindex = function(self, i, value) error("result_view is a read-only data structure", 2) end } @@ -50,20 +52,47 @@ local mt = { -- access to the entire result set. -- key_length: {result set key, total result set length} -- fetch: function(key, start) that returns (slice, adjusted start) -local function result_view(key_length, fetch) - return setmetatable( - { - key=key_length[1], - length=key_length[2], - -- C++ result sets use 0-based indexing, so internally we do too - start=0, - -- start with a dummy array with length 0 - slice={}, - fetch=fetch - }, - -- use our special metatable - mt - ) -end +local result_view = setmetatable( + { + -- generic fetch() function + fetch = function(key, start) + local fetched = leap.request( + 'LLInventory', + {op='getSlice', result=key, index=start}) + return fetched.slice, fetched.start + end, + -- generic close() function accepting variadic result-set keys + close = function(...) + local keys = table.pack(...) + -- table.pack() produces a table with an array entry for every + -- parameter, PLUS an 'n' key with the count. Unfortunately that + -- 'n' key bollixes our conversion to LLSD, which requires either + -- all int keys (for an array) or all string keys (for a map). + keys.n = nil + leap.send('LLInventory', {op='closeResult', result=keys}) + end + }, + { + -- result_view(key_length, fetch) calls this + __call = function(class, key_length, fetch) + return setmetatable( + { + key=key_length[1], + length=key_length[2], + -- C++ result sets use 0-based indexing, so internally we do too + start=0, + -- start with a dummy array with length 0 + slice={}, + -- if caller didn't pass fetch() function, use generic + fetch=fetch or class.fetch, + -- returned view:close() will close result set with passed key + close=function(self) class.close(key_length[1]) end + }, + -- use our special metatable + mt + ) + end + } +) return result_view |