-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathasync.lua
124 lines (116 loc) · 3.64 KB
/
async.lua
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
-- small async implementation using coroutines to suspend a function awaiting a callback
---@class promise
---@field done_callbacks table
---@field error_callbacks table
---@field executed boolean
---@field result any
---@field resolved boolean
---@private done_callbacks table
local promise = {}
promise.__index = promise
---creates a new promise that gets a resolve and a reject function passed
---@param fn function
---@return promise
function promise:new(fn)
local obj = setmetatable({
done_callbacks = {},
error_callbacks = {},
executed = false,
result = nil,
resolved = false,
}, promise)
fn(function(...)
obj.resolved = true
obj.result = { ... }
obj.executed = true
for i = 1, #obj.done_callbacks do
xpcall(obj.done_callbacks[i], function(err)
print("Error in done callback: ", err)
error("Uncaught error in done callback of promise")
end, ...)
end
end, function(...)
obj.result = { ... }
obj.executed = true
for i = 1, #obj.error_callbacks do
xpcall(obj.error_callbacks[i], function(err)
print("During the handling of: ", unpack(obj.result))
print("another error occured: ", err)
error("Uncaught error in done callback of promise")
end, ...)
end
if #obj.error_callbacks == 0 then
print("Error: ", ...)
error("Uncaught error in promise")
end
end)
return obj
end
---adds a done (resolve) callback to the promise
---@param callback function
---@return promise
function promise:done(callback)
if self.executed then
if self.resolved then
xpcall(callback, function(err)
print("Error in done callback: ", err)
error("Uncaught error in done callback of promise")
end, unpack(self.result))
end
return self
end
self.done_callbacks[#self.done_callbacks + 1] = callback
return self
end
---adds an error (reject) callback to the promise
---@param callback any
---@return table
function promise:err(callback)
if self.executed then
if not self.resolved then
xpcall(callback, function(err)
print("During the handling of: ", unpack(self.result))
print("another error occured: ", err)
error("Uncaught error in promise")
end, unpack(self.result))
end
return self
end
self.error_callbacks[#self.error_callbacks + 1] = callback
return self
end
local async = setmetatable({}, {
__call = function(_, fn)
return function(...)
local args = { ... }
local prom = promise:new(function(resolve, reject)
local co = coroutine.create(function()
local ret = { xpcall(fn, reject, unpack(args)) }
if ret[1] then
resolve(unpack(ret, 2))
end
end)
coroutine.resume(co)
end)
if prom.executed and not prom.resolved and #prom.error_callbacks == 0 then
error("Uncaught error in promise: " .. prom.result[1])
end
return prom
end
end,
})
async.await = function(prom)
if prom.executed then
return unpack(prom.result)
end
local co = coroutine.running()
if not co then
error("cannot await outide of an async function")
end
prom:done(function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield()
end
async.promise = promise
return async