H3lp Yours3lfDocs
example

Pooling and Signals

Borrow an event payload, consume it synchronously, and release it safely.

Use this pattern only when profiling identifies repeated payload allocations as a problem. For occasional notifications, an ordinary table and Signal are simpler.

local Pool = require 'scripts.s3.pool'
local Signal = require 'scripts.s3.signal'

local payloads = Pool.new(8)
local changed = Signal.new()
local total = 0

local handle = changed:connect(function(data)
    total = total + data.amount
end)

local function publish(amount)
    local data = payloads:acquire()
    data.amount = amount
    local ok, err = pcall(changed.fire, changed, data)
    payloads:release(data)
    if not ok then error(err, 0) end
end

publish(3)
publish(4)
assert(total == 7)
assert(payloads:available() == 8)
handle:disconnect()

The listener keeps a number, not the payload. fire completes synchronously, so the producer can release the table afterward. The protected call ensures release still happens if a listener raises; the error is then rethrown, not swallowed. This cleanup guarantee has overhead—measure the whole pattern, not just table allocations.

The pool's default reset clears released tables. Populate every needed field on each acquisition. Capacity limits idle objects retained, not total acquisitions; exhaustion allocates rather than blocking.

Read Pool for accounting and release constraints, Signal for listener behavior, and State and Context before introducing deferred work.