aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core/async/control.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/mason-core/async/control.lua')
-rw-r--r--lua/mason-core/async/control.lua75
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,
+}