OpenComputers Von Neumann Machine Programs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
4.7 KiB

1 year ago
1 year ago
  1. local coroutine = require("coroutine")
  2. local computer = require("computer")
  3. local event = require("event")
  4. local ll = require("liblua")
  5. local os = require("os")
  6. local table = require("table")
  7. local async = {}
  8. -- TODO FINISH THIS
  9. -- An async wrapper for event.pullFiltered
  10. function async.pullFiltered(...)
  11. -- Check if we're in a coroutine or not
  12. _, status = coroutine.running()
  13. local start = computer.uptime()
  14. local args = {...}
  15. -- Break on interrupts
  16. function f(name, ...)
  17. -- if args[1] happens to be "interrupted" already the second won't trigger
  18. if name == args[1] or name == "interrupted" then
  19. return true
  20. end
  21. end
  22. if type(args[1]) == "string" then
  23. -- Check if not in a coroutine
  24. if not status then return event.pullFiltered(f, ...) end
  25. print("Testing")
  26. repeat
  27. coroutine.yield()
  28. tmp = {event.pullFiltered(.01, f, ...)}
  29. until #tmp > 0
  30. else
  31. local timeout = nil
  32. if type(args[1]) == "number" then
  33. timeout = args[1]
  34. args = ll.slice({...}, 2)
  35. -- For speed purposes check up here even though it's more repeated code
  36. elseif type(args[1]) == "function" then
  37. -- Wrap other function so this will handle interrupts
  38. function g(name, ...)
  39. local a = ll.slice(args, 2)
  40. -- Handle interrupt
  41. if name == "interrupted" then
  42. return true
  43. end
  44. -- Otherwise run other function
  45. return args[1](name, ...)
  46. end
  47. if timeout ~= nil then
  48. -- Check if not in a coroutine
  49. if not status then
  50. return event.pullFiltered(timeout, g, table.unpack(args))
  51. end
  52. repeat
  53. coroutine.yield()
  54. tmp = {event.pullFiltered(.01, g, table.unpack(args))}
  55. until #tmp > 0 or computer.uptime() - start >= timeout
  56. else
  57. -- Check if not in a coroutine
  58. if not status then
  59. return event.pullFiltered(g, ...)
  60. end
  61. repeat
  62. coroutine.yield()
  63. tmp = {event.pullFiltered(.01, g, table.unpack(args))}
  64. until #tmp > 0
  65. end
  66. else
  67. if timeout ~= nil then
  68. -- Check if not in a coroutine
  69. if not status then
  70. return event.pullFiltered(timeout, f, table.unpack(args))
  71. end
  72. repeat
  73. coroutine.yield()
  74. tmp = {event.pullFiltered(.01, f, table.unpack(args))}
  75. until #tmp > 0 or computer.uptime() - start >= timeout
  76. else
  77. -- Check if not in a coroutine
  78. if not status then
  79. return event.pullFiltered(f, table.unpack(args))
  80. end
  81. repeat
  82. coroutine.yield()
  83. tmp = {event.pullFiltered(.01, f, table.unpack(args))}
  84. until #tmp > 0
  85. end
  86. end
  87. end
  88. return table.unpack(tmp)
  89. end
  90. -- An alias for async.pullFiltered which does all of the logic for both functions
  91. async.pull = async.pullFiltered
  92. -- Sleep in a coroutine friendly way
  93. function async.sleep(s)
  94. local _, status = coroutine.running()
  95. -- If not a coroutine just regular sleep
  96. if status then
  97. os.sleep(s)
  98. return
  99. end
  100. local start = computer.uptime()
  101. repeat
  102. coroutine.yield()
  103. until (computer.uptime() - start > s)
  104. end
  105. -- Simple loop
  106. local loop = {
  107. bundles = {},
  108. live = {},
  109. dead = {},
  110. add = function(self, ...)
  111. local bs = {...}
  112. -- Insert both into bundles and live so no deep copy needs to occur later
  113. for _, v in ipairs(bs) do
  114. table.insert(self.bundles, #self.bundles+1, v)
  115. table.insert(self.live, #self.live+1, v)
  116. end
  117. end
  118. }
  119. -- Used to pack function and args into a nice container for the loop and schedulers
  120. function async.bundle(f, ...)
  121. return {
  122. coro = coroutine.create(f),
  123. args = {...},
  124. results = {}
  125. }
  126. end
  127. -- Return a new loop
  128. function async.getLoop()
  129. return setmetatable({}, {__index=loop})
  130. end
  131. -- Most simple scheduling
  132. function async.roundRobin(loop, ignoreError)
  133. -- Ignore a function throwing an error
  134. if ignoreError == nil then
  135. ignoreError = false
  136. end
  137. local i = 1
  138. repeat
  139. local b = loop.live[i]
  140. local r = {coroutine.resume(b.coro, table.unpack(b.args))}
  141. local status, results = r[1], ll.slice(r, 2)
  142. -- Fail and exit if a function is bad
  143. if not status and not ignoreError then
  144. io.stderr:write(results[1])
  145. return
  146. -- Don't exit but print the bad message
  147. elseif not status then
  148. print(results[1])
  149. end
  150. -- Stop running dead coroutines and add the results
  151. if coroutine.status(b.coro) == "dead" then
  152. b.results = results
  153. table.insert(loop.dead, #loop.dead+1, table.remove(loop.live, i))
  154. else
  155. i = (i % (#loop.live)) + 1
  156. end
  157. until #loop.live == 0
  158. return loop
  159. end
  160. return async
  161. -- wget -f http://mc.bashed.rocks:13699/lib/async.lua /usr/lib/async.lua