-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfiber.lua
98 lines (80 loc) · 2.35 KB
/
fiber.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
--[[
Copyright 2012 The Luvit Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS-IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--]]
local coroutine = require('coroutine')
local debug = require 'debug'
local fiber = {}
function fiber.new(block, callback)
local paused
local co = coroutine.create(block)
local function formatError(err)
local stack = debug.traceback(co, tostring(err))
if type(err) == "table" then
err.message = stack
return err
end
return stack
end
local function check(success, ...)
if not success then
if callback then
return callback(formatError(...))
else
error(formatError(...))
end
end
if not paused then
return callback and callback(nil, ...)
end
paused = false
end
local function wait(fn, ...)
if type(fn) ~= "function" then
error("can only wait on functions")
end
local args = {...}
args[#args + 1] = function (...)
check(coroutine.resume(co, ...))
end
fn(unpack(args))
paused = true
return coroutine.yield()
end
local function wrap(fn, handleErrors)
if type(fn) == "table" then
return setmetatable({}, {
__index = function (table, key)
return fn[key] and wrap(fn[key], handleErrors)
end
})
end
if type(fn) ~= "function" then
error("Can only wrap functions or tables of functions")
end
-- Do a simple curry for the passthrough wait wrapper
if not handleErrors then
return function (...)
return wait(fn, ...)
end
end
-- Or magically pull out the error argument and throw it if it's there.
-- Return all other values if no error.
return function (...)
local result = {wait(fn, ...)}
local err = result[1]
if err then error(err) end
return unpack(result, 2)
end
end
check(coroutine.resume(co, wrap, wait))
end
return fiber