summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-09-03 20:39:14 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-09-03 20:39:14 -0400
commitf3896d37ca625a4f7060ee5139a8825c2f6e6a74 (patch)
treec10bce816c8e7834c1e485b6f71feccd48eb1906 /indra/newview
parent517163c126f7c0620f506532d67d9097083728d9 (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.lua22
-rw-r--r--indra/newview/scripts/lua/require/result_view.lua83
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