-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsync.lua
More file actions
125 lines (104 loc) · 2.48 KB
/
Copy pathsync.lua
File metadata and controls
125 lines (104 loc) · 2.48 KB
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
125
local co = coroutine
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(unpack(params))
end
return thunk
end
return factory
end
local function async(func)
local m = {
error_handler = nil,
}
local async_thunk_factory = wrap(function(handler, parent_handler_callback)
assert(type(handler) == "function", "type error :: expected func")
local thread = co.create(handler)
local step = nil
step = function(...)
local ok, thunk = co.resume(thread, ...)
-- when an error() is thrown after co-routine is resumed, obviously further
-- processing stops, and resume returns ok(false) and thunk(error) returns
-- the error message
if not ok then
if m.error_handler then
m.error_handler(thunk)
return
end
if parent_handler_callback then
parent_handler_callback(thunk)
return
end
error("unhandled error " .. thunk)
end
assert(ok, thunk)
if co.status(thread) == "dead" then
if parent_handler_callback then
parent_handler_callback(thunk)
end
else
assert(type(thunk) == "function", "type error :: expected func")
thunk(step)
end
end
step()
return m
end)
m.run = async_thunk_factory(func)
m.catch = function(error_handler)
m.error_handler = error_handler
return m
end
return m
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(unpack(acc))
end
end
tk(callback)
end
end
return thunk
end
-- sugar over coroutine
local await = function(defer)
assert(type(defer) == "function", "type error :: expected func")
return co.yield(defer)
end
local await_handle_error = function(defer)
assert(type(defer) == "function", "type error :: expected func")
local err, value = co.yield(defer)
if err then
error(err)
end
return value
end
local await_all = function(defer)
assert(type(defer) == "table", "type error :: expected table")
return co.yield(join(defer))
end
return {
sync = async,
wait_handle_error = await_handle_error,
wait = await,
wait_all = await_all,
wrap = wrap,
}