Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #257 from luvit/coro-sugar
Make fiber sugar more useful.
  • Loading branch information
creationix committed Jun 25, 2012
2 parents 43e6d4d + 417f36f commit 7fbdb5a
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 25 deletions.
55 changes: 33 additions & 22 deletions examples/fs-coroutines.lua
@@ -1,47 +1,58 @@
local fs = require('fs')
local timer = require('timer')
local fiber = require('fiber')
local fiber = require 'fiber'

fiber.new(function (resume, wait)
local function logic(wrap)
-- Wrap some functions for sync-style calling
local sleep = wrap(require('timer').setTimeout)
-- Can wrap modules too
local fs = wrap(require('fs'), true) -- true means to auto-handle errors

print("opening...")
fs.open(__dirname .. "/../LICENSE.txt", "r", "0644", resume)
local err, fd = wait()

p("on_open", {err=err,fd=fd})
local fd = fs.open(__filename, "r", "0644")
p("on_open", {fd=fd})

print("fstatting...")
fs.fstat(fd, resume)
local err, stat = wait()
p("stat", {err=err,stat=stat})
local stat = fs.fstat(fd)
p("stat", {stat=stat})

print("reading...")
local offset = 0
repeat
fs.read(fd, offset, 72, resume)
local err, chunk, length = wait()
p("on_read", {err=err,chunk=chunk, offset=offset, length=length})
local chunk, length = fs.read(fd, offset, 40)
p("on_read", {chunk=chunk, offset=offset, length=length})
offset = offset + length
until length == 0

print("pausing...")
timer.setTimeout(400, resume)
wait()
sleep(1000)

print("closing...")
fs.close(fd, resume)
local err = wait()
p("on_close", {err=err})
fs.close(fd)
p("on_close", {})

return fd, stat, offset

end

print "Starting fiber."
fiber.new(logic, function (err, fd, stat, offset)
if err then
p("ERROR", err)
error(err)
else
p("SUCCESS", { fd = fd, stat = stat, offset = offset })
end
end)
print "started."

fiber.new(function (resume, wait)
print "Starting another fiber."
fiber.new(function (wrap)

local readdir = wrap(require('fs').readdir)
print("scanning directory...")
fs.readdir(".", resume)
local err, files = wait()
local err, files = readdir(".")
p("on_open", {err=err,files=files})

end)
print "started second."


77 changes: 74 additions & 3 deletions lib/luvit/fiber.lua
Expand Up @@ -17,11 +17,82 @@ limitations under the License.
--]]
local coroutine = require('coroutine')
local debug = require 'debug'
local fiber = {}
function fiber.new(fn)
local resume = coroutine.wrap(fn)
resume(resume, coroutine.yield)
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
Expand Down

0 comments on commit 7fbdb5a

Please sign in to comment.