diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2020-09-18 17:07:11 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2020-09-18 17:07:11 +0800 |
commit | 32dd2af081a40813683ced02a82a129efb604174 (patch) | |
tree | 6134c900c7dd93680dd34d855bbae4815e6da4dd /script-beta/await.lua | |
parent | 8dc4b5d3f8145e679ae27b2b7e8a85cc122f7044 (diff) | |
download | lua-language-server-32dd2af081a40813683ced02a82a129efb604174.zip |
重新设计await的任务中断
Diffstat (limited to 'script-beta/await.lua')
-rw-r--r-- | script-beta/await.lua | 131 |
1 files changed, 81 insertions, 50 deletions
diff --git a/script-beta/await.lua b/script-beta/await.lua index ff45a141..b8c6ac17 100644 --- a/script-beta/await.lua +++ b/script-beta/await.lua @@ -1,12 +1,12 @@ -local timer = require 'timer' +local timer = require 'timer' +local util = require 'utility' ---@class await local m = {} m.type = 'await' -m.coTracker = setmetatable({}, { __mode = 'k' }) -m.coPriority = setmetatable({}, { __mode = 'k' }) -m.coDelayer = setmetatable({}, { __mode = 'k' }) +m.coMap = setmetatable({}, { __mode = 'k' }) +m.idMap = {} m.delayQueue = {} m.delayQueueIndex = 1 @@ -25,40 +25,85 @@ function m.checkResult(co, ...) end --- 创建一个任务 -function m.create(callback, ...) +function m.call(callback, ...) local co = coroutine.create(callback) - m.coTracker[co] = true - return m.checkResult(co, coroutine.resume(co, ...)) + local closers = {} + m.coMap[co] = { + closers = closers, + priority = false, + } + for i = 1, select('#', ...) do + local id = select(i, ...) + if not id then + break + end + m.setID(id, co) + end + + local currentCo = coroutine.running() + local current = m.coMap[currentCo] + if current then + for closer in pairs(current.closers) do + closers[closer] = true + closer(co) + end + end + return m.checkResult(co, coroutine.resume(co)) end ---- 对当前任务设置一个延迟检查器,当延迟前后检查器的返回值不同时,放弃此任务 -function m.setDelayer(callback) - local co = coroutine.running() - m.coDelayer[co] = callback +--- 创建一个任务,并挂起当前线程,当任务完成后再延续当前线程/若任务被关闭,则返回nil +function m.await(callback, ...) + return m.wait(function (waker, ...) + m.call(function () + local returnNil <close> = util.defer(waker) + waker(callback()) + end, ...) + end, ...) +end + +--- 设置一个可继承的关闭器,在设置时,以及创建子协程时会调用 +function m.setCloser(callback, co) + co = co or coroutine.running() + local current = m.coMap[co] + current[callback] = true + callback(co) +end + +--- 设置一个id,用于批量关闭任务 +function m.setID(id, co) + co = co or coroutine.running() + if not m.idMap[id] then + m.idMap[id] = setmetatable({}, { __mode = 'k' }) + end + m.idMap[id][co] = true +end + +--- 根据id批量关闭任务 +function m.close(id) + local map = m.idMap[id] + if not map then + return + end + for co in pairs(map) do + map[co] = nil + coroutine.close(co) + end end --- 休眠一段时间 ---@param time number -function m.sleep(time, getVersion) +function m.sleep(time) if not coroutine.isyieldable() then if m.errorHandle then m.errorHandle(debug.traceback('Cannot yield')) end return end - local version = getVersion and getVersion() local co = coroutine.running() - local delayer = m.coDelayer[co] - local dVersion = delayer and delayer() timer.wait(time, function () - if version == (getVersion and getVersion()) - and dVersion == (delayer and delayer()) then - return m.checkResult(co, coroutine.resume(co)) - else - coroutine.close(co) - end + return m.checkResult(co, coroutine.resume(co)) end) - return coroutine.yield(getVersion) + return coroutine.yield() end --- 等待直到唤醒 @@ -68,51 +113,37 @@ function m.wait(callback, ...) return end local co = coroutine.running() + local waked callback(function (...) + if waked then + return + end + waked = true return m.checkResult(co, coroutine.resume(co, ...)) - end) - return coroutine.yield(...) + end, ...) + return coroutine.yield() end --- 延迟 -function m.delay(getVersion) +function m.delay() if not coroutine.isyieldable() then return end local co = coroutine.running() + local current = m.coMap[co] -- TODO - if m.coPriority[co] then + if current.priority then return end - local version = getVersion and getVersion() - local delayer = m.coDelayer[co] - local dVersion = delayer and delayer() m.delayQueue[#m.delayQueue+1] = function () - if version == (getVersion and getVersion()) - and dVersion == (delayer and delayer()) then - return m.checkResult(co, coroutine.resume(co)) - else - coroutine.close(co) + if coroutine.status(co) ~= 'suspended' then + return end + return m.checkResult(co, coroutine.resume(co)) end return coroutine.yield() end -local function getCo(waker) - local co - for i = 1, 100 do - local n, v = debug.getupvalue(waker, i) - if not n then - return nil - end - if n == 'co' then - co = v - break - end - end - return co -end - --- 步进 function m.step() local waker = m.delayQueue[m.delayQueueIndex] @@ -134,7 +165,7 @@ function m.step() end function m.setPriority(n) - m.coPriority[coroutine.running()] = n + m.coMap[coroutine.running()].priority = true end return m |