Advertisement
Tocuto

Lua Asyncio (library)

Apr 25th, 2019
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 4.43 KB | None | 0 0
  1. local Task
  2. do
  3.     local time = os.time
  4.     local unpack = table.unpack
  5.     local status = coroutine.status
  6.     local resume = coroutine.resume
  7.     local create = coroutine.create
  8.  
  9.     Task = function(func, ...)
  10.         local self = setmetatable({
  11.             type="task",
  12.             coro=create(func),
  13.             args={...},
  14.             runtime=0,
  15.             started_call=0,
  16.             iteration=0,
  17.             cancelled=false,
  18.             done=false,
  19.             is_error_handler=false,
  20.             result=nil,
  21.             after_done=nil
  22.         }, {
  23.             __call = function(self)
  24.                 assert(not self.cancelled, "Cannot resume a cancelled task")
  25.                 assert(not self.done, "Cannot resume a finished task")
  26.  
  27.                 self.started_call = time()
  28.                 local done, result = resume(self.coro, unpack(self.args))
  29.                 local _end = time() - self.started_call
  30.  
  31.                 self.runtime = self.runtime + _end
  32.                 local current = self
  33.                 while current.after_done do
  34.                     current = current.after_done
  35.                     current.runtime = current.runtime + _end
  36.                 end
  37.  
  38.                 if (not done) or status(self.coro) == "dead" then
  39.                     self.done = true
  40.                     self.result = {done, result}
  41.                 end
  42.                 return done, result
  43.             end
  44.         })
  45.  
  46.         self.get_result = function()
  47.             assert(self.done, "The task has not finished yet")
  48.             assert(self.result[1], self.result[2])
  49.  
  50.             return unpack(result, 2)
  51.         end
  52.  
  53.         self.real_runtime = function()
  54.             return time() - self.started_call + self.runtime
  55.         end
  56.  
  57.         return self
  58.     end
  59. end
  60.  
  61. local Loop
  62. do
  63.     local time = os.time
  64.     local unpack = table.unpack
  65.     local remove = table.remove
  66.     local yield = coroutine.yield
  67.  
  68.     Loop = function()
  69.         local self = {
  70.             max_runtime=10,
  71.             iteration_cooldown=0,
  72.             remove_later=0,
  73.             iteration_no=0,
  74.             last_accepted=0,
  75.             used_runtime=0,
  76.             tasks={},
  77.             waiting={},
  78.             current_task=nil,
  79.             accept_faster=true,
  80.             error_handler=function(msg)
  81.                 print("An error happened.")
  82.                 print(msg)
  83.             end
  84.         }
  85.  
  86.         self.add_task = function(task)
  87.             self.tasks[#self.tasks + 1] = task
  88.         end
  89.  
  90.         self.sleep = function(sleep_for)
  91.             if not sleep_for then
  92.                 self.waiting[#self.waiting + 1] = {time(), self.current_task}
  93.             else
  94.                 self.waiting[#self.waiting + 1] = {time() + sleep_for, self.current_task}
  95.             end
  96.             yield()
  97.         end
  98.  
  99.         self.power_nap = function()
  100.             self.add_task(self.current_task)
  101.             yield()
  102.         end
  103.  
  104.         self._accept_iteration = function(start, max)
  105.             for index = self.remove_later, 1, -1 do
  106.                 remove(self.tasks, index)
  107.             end
  108.             self.remove_later = 0
  109.  
  110.             for index = #self.waiting, 1, -1 do
  111.                 if time() >= self.waiting[index][1] then
  112.                     self.tasks[#self.tasks + 1] = self.waiting[index][2]
  113.                     remove(self.waiting, index)
  114.                 end
  115.             end
  116.  
  117.             local index = 0
  118.             while ((time() - start) < max) and #self.tasks > index do
  119.                 index = index + 1
  120.                 local task = self.tasks[index]
  121.                 self.current_task = task
  122.  
  123.                 if (not task.cancelled) and (not task.done) then
  124.                     task.iteration = self.iteration_no
  125.                     local task_done, task_result = task()
  126.                     if not task_done then
  127.                         if task.is_error_handler then
  128.                             error("The error handler threw an error: " .. task_result)
  129.                         else
  130.                             local t = Task(self.error_handler, task_result)
  131.                             t.is_error_handler = true
  132.                             self.tasks[#self.tasks + 1] = t
  133.                         end
  134.                     end
  135.  
  136.                     if not task.done then
  137.                         if type(task_result) == "table" and task_result.type == "task" then
  138.                             task_result.after_done = task
  139.                             self.tasks[#self.tasks + 1] = task_result
  140.                         end
  141.                     end
  142.                 end
  143.  
  144.                 self.remove_later = self.remove_later + 1
  145.                 if (task.done or task.cancelled) then
  146.                     if task.after_done then
  147.                         task.after_done.args = task.result
  148.                         self.tasks[#self.tasks + 1] = task.after_done
  149.                     end
  150.                 end
  151.             end
  152.  
  153.             self.iteration_no = self.iteration_no + 1
  154.         end
  155.  
  156.         self.run_tasks = function(start)
  157.             local start = (not start) and time() or start
  158.  
  159.             if self.accept_faster then
  160.                 local do_reset = false
  161.                 if start - self.last_accepted >= self.iteration_cooldown then
  162.                     do_reset = true
  163.                     self.used_runtime = 0
  164.                 end
  165.  
  166.                 local used = (time() - start + self.used_runtime)
  167.                 if used < self.max_runtime then
  168.                     local accept_start = time()
  169.                     self._accept_iteration(start, self.max_runtime - used)
  170.  
  171.                     self.used_runtime = used + (time() - accept_start)
  172.  
  173.                     if do_reset then
  174.                         self.last_accepted = time()
  175.                     end
  176.                 end
  177.             elseif start - self.last_accepted >= self.iteration_cooldown then
  178.                 self._accept_iteration(start, self.max_runtime)
  179.             end
  180.         end
  181.  
  182.         return self
  183.     end
  184. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement