-- Manage Lua coroutines local coro = {} coro._coros = {} -- Launch a Lua coroutine: create and resume. -- Returns: new coroutine, values yielded or returned from initial resume() -- If initial resume() encountered an error, propagates the error. function coro.launch(func, ...) local co = coroutine.create(func) table.insert(coro._coros, co) return co, coro.resume(co, ...) end -- resume() wrapper to propagate errors function coro.resume(co, ...) -- if there's an idiom other than table.pack() to assign an arbitrary -- number of return values, I don't yet know it local ok_result = table.pack(coroutine.resume(co, ...)) if not ok_result[1] then -- if [1] is false, then [2] is the error message error(ok_result[2]) end -- ok is true, whew, just return the rest of the values return table.unpack(ok_result, 2) end -- yield to other coroutines even if you don't know whether you're in a -- created coroutine or the main coroutine function coro.yield(...) if coroutine.running() then -- this is a real coroutine, yield normally return coroutine.yield(...) else -- This is the main coroutine: coroutine.yield() doesn't work. -- But we can take a spin through previously-launched coroutines. -- Walk a copy of coro._coros in case any of these coroutines launches -- another: next() forbids creating new entries during traversal. for co in coro._live_coros_iter, table.clone(coro._coros) do coro.resume(co) end end end -- Walk coro._coros table, returning running or suspended coroutines. -- Once a coroutine becomes dead, remove it from _coros and don't return it. function coro._live_coros() return coro._live_coros_iter, coro._coros end -- iterator function for _live_coros() function coro._live_coros_iter(t, idx) local k, co = next(t, idx) while k and coroutine.status(co) == 'dead' do -- t[k] = nil -- See coro.yield(): sometimes we traverse a copy of _coros, but if we -- discover a dead coroutine in that copy, delete it from _coros -- anyway. Deleting it from a temporary copy does nothing. coro._coros[k] = nil coroutine.close(co) k, co = next(t, k) end return co end return coro