-
-
Notifications
You must be signed in to change notification settings - Fork 331
async await using libuv #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 5 commits
Commits
Show all changes
61 commits
Select commit
Hold shift + click to select a range
a096073
started branch
oberblastmeister b363ee0
added bench
oberblastmeister 621bfb9
added plenary. ahead
oberblastmeister b226549
changed naming
oberblastmeister eea0b24
added work future and test
oberblastmeister 3fe213a
fixed await_all, added more benches and tests
oberblastmeister db2f958
ntoes
oberblastmeister 02e938e
more notes
oberblastmeister 7b9c2ac
added doc
oberblastmeister 2ccda6b
added M
oberblastmeister 4fe5f84
added some more uv functions
oberblastmeister 23553f3
start of counting semaphore
oberblastmeister 7062489
more docs
oberblastmeister dab2d92
use join in run_all
oberblastmeister de8ac26
started branch
oberblastmeister 430a2d0
fixed tests
oberblastmeister 1bc875a
removed unneeded
oberblastmeister 68af03b
small changes
oberblastmeister 8915094
async: refactor futures without object
bfredl e1e44b1
maded naming more consistent
oberblastmeister 9234048
added argc
oberblastmeister 6906da0
added argc for wrap
oberblastmeister 60368ff
added argc for all functions
oberblastmeister 53ab866
put in main loop
oberblastmeister b682e78
made timeout work
oberblastmeister 7fc1214
added runned
oberblastmeister 02fe675
removed convert
oberblastmeister 1c4559b
added nvim future to be able to call api
oberblastmeister 0fd0f1a
added select
oberblastmeister dc68752
fixed wrong argc in select function
oberblastmeister c5efd4d
added block on
oberblastmeister 83378a0
updated waiting time for blockon
oberblastmeister 2e3ef66
Merge remote-tracking branch 'upstream/master' into async
oberblastmeister bab7509
added protect and block_on
oberblastmeister 578cd63
added api helper
oberblastmeister 0c96921
updated benchs for api
oberblastmeister 8384d3d
fixed protected
oberblastmeister fbd402c
validate sender
oberblastmeister 1666282
add in_fast_event check
oberblastmeister e24a703
removed unneeded asset file
oberblastmeister f74b094
removed comment
oberblastmeister 522a7b8
change name to scheduler
oberblastmeister ffcf332
removed idle and work related stuff for now
oberblastmeister 2c9f3a9
removed work tests and changed name to util
oberblastmeister 58ac59d
added scope and void
oberblastmeister 73c4c81
added check to condvar
oberblastmeister e3e3e8f
removed unnecesary concats
oberblastmeister 14c734d
removed long bench file
oberblastmeister 79640e9
added better errors
oberblastmeister 92afbb9
added many docs
oberblastmeister fc4557f
moved block_on and fixed oneshot channel
oberblastmeister 4767627
added async tests
oberblastmeister 60ea7d9
updated tests and added describe it
oberblastmeister 1752ae5
fixed channel and added more tests
oberblastmeister df921db
more tests
oberblastmeister 374d7cd
added counter channel
oberblastmeister 981a291
changed counter api and added tests
oberblastmeister 2765ee5
added more deque methods and tests
oberblastmeister 6dfa6fc
added mspc channel
oberblastmeister 5f2d6e5
woops forgot to commit
oberblastmeister 5233604
remove runned
oberblastmeister File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| local co = coroutine | ||
| local uv = vim.loop | ||
|
|
||
| local thread_loop = function(thread, callback) | ||
| local idle = uv.new_idle() | ||
| idle:start(function() | ||
| local success = co.resume(thread) | ||
| assert(success, "Coroutine failed") | ||
|
|
||
| if co.status(thread) == "dead" then | ||
| idle:stop() | ||
| callback() | ||
| end | ||
| end) | ||
| end | ||
|
|
||
| -- use with wrap | ||
| local pong = function(func, callback) | ||
| assert(type(func) == "function", "type error :: expected func") | ||
| local thread = co.create(func) | ||
| local step | ||
| step = function(...) | ||
| local res = {co.resume(thread, ...)} | ||
| local stat = res[1] | ||
| local ret = {select(2, unpack(res))} | ||
| assert(stat, "Status should be true") | ||
| if co.status(thread) == "dead" then | ||
| (callback or function() end)(unpack(ret)) | ||
| else | ||
| assert(#ret == 1, "expected a single return value") | ||
| assert(type(ret[1]) == "function", "type error :: expected func") | ||
| ret[1](step) | ||
| end | ||
| end | ||
| step() | ||
| end | ||
|
|
||
| -- use with pong, creates thunk factory | ||
| local wrap = function(func) | ||
| assert(type(func) == "function", "type error :: expected func, got " .. type(func)) | ||
|
|
||
| return function(...) | ||
| local params = {...} | ||
| return function(step) | ||
| table.insert(params, step) | ||
| return func(unpack(params)) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| local thread_loop_async = wrap(thread_loop) | ||
|
|
||
| -- 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 | ||
|
|
||
| local function run(future) | ||
| future() | ||
| end | ||
|
|
||
| local function run_all(futures) | ||
| for _, future in ipairs(futures) do | ||
| future() | ||
| end | ||
| end | ||
|
|
||
| -- sugar over coroutine | ||
| local await = function(defer) | ||
| assert(type(defer) == "function", "type error :: expected func") | ||
| return co.yield(defer) | ||
| end | ||
|
|
||
|
|
||
| local await_all = function(defer) | ||
| assert(type(defer) == "table", "type error :: expected table") | ||
| return co.yield(join(defer)) | ||
| end | ||
|
|
||
| local async = function(func) | ||
| return function(...) | ||
| local args = {...} | ||
| return wrap(pong)(function() | ||
| return func(unpack(args)) | ||
| end) | ||
| end | ||
| end | ||
|
|
||
| local pong_loop = async(function(func, callback) | ||
| assert(type(func) == "function", "type error :: expected func") | ||
| local thread = co.create(func) | ||
|
|
||
| local _step | ||
| _step = function(...) | ||
| local res = {co.resume(thread, ...)} | ||
| local stat = res[1] | ||
| local ret = {select(2, unpack(res))} | ||
| assert(stat, "Status should be true") | ||
| if co.status(thread) == "dead" then | ||
| (callback or function() end)(unpack(ret)) | ||
| else | ||
| assert(#ret == 1, "expected a single return value") | ||
| assert(type(ret[1]) == "function", "type error :: expected func") | ||
| -- yield before calling the next one | ||
| co.yield() | ||
| ret[1](_step) | ||
| end | ||
| end | ||
|
|
||
| local step = function() | ||
| thread_loop(co.create(_step)) | ||
| end | ||
|
|
||
| step() | ||
| end) | ||
|
|
||
| --- because idle is a bad name | ||
| local spawn = wrap(pong_loop) | ||
|
|
||
| return { | ||
| async = async, | ||
| join = join, | ||
| await = await, | ||
| await_all = await_all, | ||
| run = run, | ||
| run_all = run_all, | ||
| spawn = spawn, | ||
| wrap = wrap, | ||
| wait_for_textlock = wrap(vim.schedule) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| local M = {} | ||
|
|
||
| VecDeque = {} | ||
| VecDeque.__index = VecDeque | ||
|
|
||
| function VecDeque.new() | ||
| return setmetatable({first = 0, last = -1}, VecDeque) | ||
| end | ||
|
|
||
| function VecDeque:pushleft(value) | ||
| local first = self.first - 1 | ||
| self.first = first | ||
| self[first] = value | ||
| end | ||
|
|
||
| function VecDeque:pushright(value) | ||
| local last = self.last + 1 | ||
| self.last = last | ||
| self[last] = value | ||
| end | ||
|
|
||
| function VecDeque:popleft() | ||
| local first = self.first | ||
| if first > self.last then return nil end | ||
| local value = self[first] | ||
| self[first] = nil -- to allow garbage collection | ||
| self.first = first + 1 | ||
| return value | ||
| end | ||
|
|
||
| function VecDeque:is_empty() | ||
| return self.first > self.last | ||
| end | ||
|
|
||
| function VecDeque:popright() | ||
| local last = self.last | ||
| if self.first > last then return nil end | ||
| local value = self[last] | ||
| self[last] = nil -- to allow garbage collection | ||
| self.last = last - 1 | ||
| return value | ||
| end | ||
|
|
||
| function VecDeque:len() | ||
| return self.last - self.first | ||
| end | ||
|
|
||
| M.VecDeque = VecDeque | ||
|
|
||
| return M |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| local exports = require('plenary.async_lib.async') | ||
| exports.uv = require('plenary.async_lib.uv_async') | ||
| exports.utils = require('plenary.async_lib.utils') | ||
| exports.lsp = require('plenary.async_lib.lsp') | ||
| exports.work = require('plenary.async_lib.work') | ||
|
|
||
| return exports |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| local a = require('plenary.async_lib.async') | ||
|
|
||
| local M = {} | ||
|
|
||
| M.buf_request = a.wrap(vim.lsp.buf_request) | ||
|
|
||
| return M |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| local a = require('plenary.async_lib.async') | ||
| local async = a.async | ||
| local co = coroutine | ||
| local VecDeque = require('plenary.async_lib.helpers').VecDeque | ||
| local uv = vim.loop | ||
|
|
||
| local M = {} | ||
|
|
||
| M.sleep = a.wrap(function(ms, callback) | ||
| local timer = uv.new_timer() | ||
| uv.timer_start(timer, ms, 0, function() | ||
| uv.timer_stop(timer) | ||
| uv.close(timer) | ||
| callback() | ||
| end) | ||
| end) | ||
|
|
||
| M.timer = function(ms) | ||
| return async(function() | ||
| a.wait(M.sleep(ms)) | ||
| end) | ||
| end | ||
|
|
||
| M.id = async(function(...) | ||
| return ... | ||
| end) | ||
|
|
||
| M.thread_loop = function(thread, callback) | ||
| local idle = uv.new_idle() | ||
| idle:start(function() | ||
| local success = co.resume(thread) | ||
| assert(success, "Coroutine failed") | ||
|
|
||
| if co.status(thread) == "dead" then | ||
| idle:stop() | ||
| callback() | ||
| end | ||
| end) | ||
| end | ||
|
|
||
| M.thread_loop_async = a.wrap(M.thread_loop) | ||
|
|
||
| M.yield_now = async(function() | ||
| a.wait(M.id()) | ||
| end) | ||
|
|
||
| local Condvar = {} | ||
| Condvar.__index = Condvar | ||
|
|
||
| function Condvar.new() | ||
| return setmetatable({handles = {}}, Condvar) | ||
| end | ||
|
|
||
| --- async function | ||
| --- blocks the thread until a notification is received | ||
| Condvar.wait = a.wrap(function(self, callback) | ||
| -- not calling the callback will block the coroutine | ||
| table.insert(self.handles, callback) | ||
| end) | ||
|
|
||
| --- not an async function | ||
| function Condvar:notify_all() | ||
|
oberblastmeister marked this conversation as resolved.
Outdated
|
||
| for _, callback in ipairs(self.handles) do | ||
| callback() | ||
| end | ||
| self.handles = {} -- reset all handles as they have been used up | ||
| end | ||
|
|
||
| --- not an async function | ||
| function Condvar:notify_one() | ||
| if #self.handles == 0 then return end | ||
|
|
||
| local idx = math.random(#self.handles) | ||
| self.handles[idx]() | ||
| table.remove(self.handles, idx) | ||
| end | ||
|
|
||
| M.Condvar = Condvar | ||
|
|
||
| M.channel = {} | ||
|
|
||
| ---comment | ||
| ---@return function | ||
| ---@return any | ||
| M.channel.oneshot = function() | ||
| local val = nil | ||
| local saved_callback = nil | ||
|
|
||
| --- sender is not async | ||
| --- sends a value | ||
| local sender = function(t) | ||
| if val ~= nil then | ||
| error('Oneshot channel can only send one value!') | ||
| end | ||
|
|
||
| val = t | ||
| saved_callback(val) | ||
| end | ||
|
|
||
| --- receiver is async | ||
| --- blocks until a value is received | ||
| local receiver = a.wrap(function(callback) | ||
| if callback ~= nil then | ||
| error('Oneshot channel can only receive one value!') | ||
| end | ||
|
|
||
| saved_callback = callback | ||
| end) | ||
|
|
||
| return sender, receiver | ||
| end | ||
|
|
||
| M.channel.mpsc = function() | ||
| end | ||
|
|
||
| return M | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.