update todo
[QuestHelper.git] / Generic / cron.lua
blob3fe1b5e7e23b3c036f8abd5276a01bf39e5c6269
1 -- Functions we use here.
2 local create = QuestHelper.create
3 local createSortedList = QuestHelper.createSortedList
4 local createCallback = QuestHelper.createCallback
5 local release = QuestHelper.release
6 local reference = QuestHelper.reference
7 local array = QuestHelper.array
8 local insert = table.insert
9 local erase = table.remove
10 local now = GetTime or os.time
12 -- The metatable for Cron objects.
13 local Cron = {}
15 local function jobCmp(a, b)
16 return a.time > b.time
17 end
19 function Cron:onCreate()
20 rawset(self, "jobs", createSortedList(jobCmp))
21 end
23 function Cron:onRelease()
24 local jobs = rawget(self, "jobs")
25 for i, job in ipairs(jobs) do
26 release(job.callback)
27 release(job)
28 end
29 release(jobs)
30 end
32 -- Will invoke callback 'wait' or more seconds from now, at some future invocation of poll.
33 --
34 -- If the callback returns a number, it will be invoked again in at least that number of seconds.
35 --
36 -- The callback is referenced and that reference will be released when the job is complete or
37 -- the cron object itself is released.
38 --
39 -- If callback is actually a function, a callback is created from it using the additional arguments.
40 -- Otherwise, any additional arguments are ignored.
41 --
42 -- You could probably get away with passing an event object here as if it were a callback.
43 --
44 -- Returns the passed or created callback.
45 function Cron:start(wait, callback, ...)
46 assert(type(wait) == "number", "Expected positive number.")
47 local job= array(delta, callback)
48 job.time = now()+wait
49 job.callback = type(callback) == "function" and createCallback(callback, ...) or reference(callback)
50 rawget(self, "jobs"):insert(job)
51 end
53 -- Attempts to find a job with the specified callback and stop it.
54 function Cron:stop(callback)
55 local jobs = rawget(self, "jobs")
56 for i, job in pairs(jobs) do
57 if job.callback == callback then
58 erase(jobs, i)
59 release(job.callback)
60 release(job)
61 return
62 end
63 end
65 assert(false, "Callback wasn't handled.")
66 end
68 -- Returns true if the cron object isn't tracking any objects.
69 function Cron:empty()
70 return #rawget(self, "jobs") == 0
71 end
73 -- Will invoke the next callback that needs to be called, returning true if something happened, nil otherwise.
74 function Cron:poll()
75 local t = now()
76 local jobs = rawget(self, "jobs")
77 local i = #jobs
79 if i > 0 then
80 local job = rawget(jobs, i)
82 if job.time < t then
83 erase(jobs, i)
84 local result = job.callback()
85 if result then
86 job.time = t+result
87 insert(temp, job)
88 else
89 release(job.callback)
90 release(job)
91 end
93 return true
94 end
95 end
96 end
98 -- Allow you to use cron object as if it were a function.
99 Cron.__call = Cron.poll
101 Cron.__newindex = function()
102 assert(false, "Shouldn't assign values.")
105 Cron.__index = function(_, key)
106 return rawget(Cron, key)
109 local function createCron()
110 return create(Cron)
113 QuestHelper.createCron = createCron