diff options
Diffstat (limited to 'lua/mason-core/async/control.lua')
| -rw-r--r-- | lua/mason-core/async/control.lua | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/lua/mason-core/async/control.lua b/lua/mason-core/async/control.lua new file mode 100644 index 00000000..3252c070 --- /dev/null +++ b/lua/mason-core/async/control.lua @@ -0,0 +1,75 @@ +local a = require "mason-core.async" + +---@class Condvar +local Condvar = {} +Condvar.__index = Condvar + +function Condvar.new() + return setmetatable({ handles = {}, queue = {}, is_notifying = false }, Condvar) +end + +---@async +function Condvar:wait() + a.wait(function(resolve) + if self.is_notifying then + self.queue[resolve] = true + else + self.handles[resolve] = true + end + end) +end + +function Condvar:notify_all() + self.is_notifying = true + for handle in pairs(self.handles) do + handle() + end + self.handles = self.queue + self.queue = {} + self.is_notifying = false +end + +local Permit = {} +Permit.__index = Permit + +function Permit.new(semaphore) + return setmetatable({ semaphore = semaphore }, Permit) +end + +function Permit:forget() + local semaphore = self.semaphore + semaphore.permits = semaphore.permits + 1 + + if semaphore.permits > 0 and #semaphore.handles > 0 then + semaphore.permits = semaphore.permits - 1 + local release = table.remove(semaphore.handles, 1) + release(Permit.new(semaphore)) + end +end + +---@class Semaphore +local Semaphore = {} +Semaphore.__index = Semaphore + +---@param permits integer +function Semaphore.new(permits) + return setmetatable({ permits = permits, handles = {} }, Semaphore) +end + +---@async +function Semaphore:acquire() + if self.permits > 0 then + self.permits = self.permits - 1 + else + return a.wait(function(resolve) + table.insert(self.handles, resolve) + end) + end + + return Permit.new(self) +end + +return { + Condvar = Condvar, + Semaphore = Semaphore, +} |
