Skip to content

Instantly share code, notes, and snippets.

@alexshen
Created March 23, 2014 12:30
Show Gist options
  • Save alexshen/9722467 to your computer and use it in GitHub Desktop.
Save alexshen/9722467 to your computer and use it in GitHub Desktop.
#! /usr/bin/lua
--[[
A simple coroutine manager inspired by Unity and the example in <<Python Essential Reference>>.
--]]
--for debugging coroutine in ZeroBrane
--require('mobdebug').coro()
__call_mt = {}
__task_mt = {}
local function new_task(f, ...)
local args = { ... }
local o = {}
o.target = coroutine.create(function()
return f(table.unpack(args))
end)
o.stack = {}
-- return true if running
-- return false if stopped
o.running = function(self)
if type(self.target) == 'thread' then
return coroutine.status(self.target) ~= 'dead'
else
return self.target:running()
end
end
o.push = function(self, f)
if type(f) == 'thread' then
-- save current coroutine, transfer control to the returned coroutine
self:_push(f)
elseif getmetatable(f) == __task_mt then
-- save current coroutine, transfer control to the returned task
self:_push(f)
else
error('invalid argument')
end
end
o._push = function(self, f)
table.insert(self.stack, self.target)
self.target = f
end
o.next = function(self)
if #self.stack ~= 0 then
self.target = self.stack[#self.stack]
self.stack[#self.stack] = nil
return true
end
end
o.run = function (self)
-- we depend on another task, check if that target is completed
if getmetatable(self.target) == __task_mt then
if not self.target:running() then
return self:next()
else
return true
end
else
local status, result = coroutine.resume(self.target)
-- special call, need return to manager
if getmetatable(result) == __call_mt then
return result
elseif getmetatable(result) == __task_mt then
self:_push(result)
return true
elseif type(result) == 'thread' then
self:_push(result)
return true
elseif coroutine.status(self.target) == 'dead' then
return self:next()
else
return true
end
end
end
setmetatable(o, __task_mt)
return o
end
-- start a couroutine and add to current manager
function start(f, ...)
local o = {}
setmetatable(o, __call_mt)
o.args = {...}
o.call = function(self, mgr, task)
task:push(mgr:start(f, table.unpack(self.args)))
end
return o
end
function wait_for_seconds(sec)
return coroutine.create(function ()
local end_time = os.clock() + sec
while os.clock() < end_time do
coroutine.yield()
end
end)
end
function yield(res)
coroutine.yield(res)
end
function new_comgr()
local o = {}
o._tasks = {}
o.start = function(self, f, ...)
local t = new_task(f, ...)
table.insert(self._tasks, t)
return t
end
o.update = function(self)
local i = #self._tasks
while i > 0 do
local res = self._tasks[i]:run()
if not res then
table.remove(self._tasks, i)
elseif getmetatable(res) == __call_mt then
res:call(self, self._tasks[i])
end
i = i - 1
end
end
return o
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment