1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
-- From: https://github.com/ms-jpq/lua-async-await
-- Licensed under MIT
local co = coroutine
-- use with wrap
local pong = function(func, callback)
assert(type(func) == "function", "type error :: expected func")
local thread = co.create(func)
local step = nil
step = function(...)
local stat, ret = co.resume(thread, ...)
if not stat then
print(ret)
print(debug.traceback(thread))
end
assert(stat, ret)
if co.status(thread) == "dead" then
(callback or function() end)(ret)
else
assert(type(ret) == "function", "type error :: expected func")
ret(step)
end
end
step()
end
-- use with pong, creates thunk factory
local wrap = function(func)
assert(type(func) == "function", "type error :: expected func")
local factory = function(...)
local params = { ... }
local thunk = function(step)
table.insert(params, step)
return func(table.unpack(params))
end
return thunk
end
return factory
end
-- many thunks -> single thunk
local join = function(thunks)
local len = #thunks
local done = 0
local acc = {}
local thunk = function(step)
if len == 0 then
return step()
end
for i, tk in ipairs(thunks) do
assert(type(tk) == "function", "thunk must be function")
local callback = function(...)
acc[i] = ...
done = done + 1
if done == len then
step(acc)
end
end
tk(callback)
end
end
return thunk
end
-- sugar over coroutine
local await = function(defer)
local _, isMain = coroutine.running()
assert(not isMain,
"a.wait was called outside of a running coroutine. You need to start one using a.sync(my_function)() first")
assert(type(defer) == "function", "type error :: expected func :: was: " .. type(defer))
return co.yield(defer)
end
local await_all = function(defer)
local _, isMain = coroutine.running()
assert(not isMain,
"a.wait_all was called outside of a running coroutine. You need to start one using a.sync(my_function)() first")
assert(type(defer) == "table", "type error :: expected table")
return co.yield(join(defer))
end
return {
sync = wrap(pong),
wait = await,
wait_all = await_all,
wrap = wrap,
}
|