Skip to content

Commit

Permalink
feat: a.sync and a.wait
Browse files Browse the repository at this point in the history
  • Loading branch information
aarondill committed Oct 28, 2024
1 parent 3c0ac0b commit 07e7119
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 53 deletions.
37 changes: 37 additions & 0 deletions a.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---@class AsyncModule
local a = {}
---Use like javascript's new Promise constructor (await(function(resolve) resolve(1) end))
---@generic A
---@param f fun(resolve: fun(a: A, ...: any))
---@return A, any
function a.wait(f)
local co = coroutine.running()
local ret
f(function(...)
if coroutine.status(co) == "running" then
ret = ret or table.pack(...)
else
coroutine.resume(co, ...)
end
end)
if ret then return table.unpack(ret, 1, ret.n) end
return coroutine.yield()
end

---Use to define an async function. Use with a.wait(function(resolve) resolve(1) end)
---The (optional) callback is the first argument, other arguments are passed to the function
---The callback will be called with the return value(s)
---Using this avoids the pyramid of doom, but screws with type checking
---@generic A, R
---@param f fun(...: A): R,...: unknown
---@return fun(cb: fun(r: R): any?,...: A )
function a.sync(f)
return coroutine.wrap(function(...)
local args = table.pack(...)
local callback = args[1]
-- NOTE: args[1] is the callback, so unpack from 2 to n
local val = table.pack(f(table.unpack(args, 2, args.n)))
if callback then return callback(table.unpack(val, 1, val.n)) end
end)
end
return a
18 changes: 0 additions & 18 deletions await.lua

This file was deleted.

5 changes: 1 addition & 4 deletions configuration/apps/open.lua
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
local require = require("util.rel_require")
--
local append_async = require("util.file.append_async")
local ascreen = require("awful.screen")
local await = require("await")
local concat_command = require("util.command.concat_command")
local default = require(..., "default") ---@module 'configuration.apps.default'
local lgi = require("lgi")
local new_file_for_path = require("util.file.new_file_for_path")
local notifs = require("util.notifs")
local path = require("util.path")
local rofi_command = require(..., "rofi_command") ---@module 'configuration.apps.rofi_command'
local spawn = require("util.spawn")
local widgets = require("util.awesome.widgets")
local xdg_user_dir = require("util.command.xdg_user_dir")
local GLib, Gio = lgi.GLib, lgi.Gio
local GLib = lgi.GLib

local open = {}

Expand Down
60 changes: 29 additions & 31 deletions widget/battery/dbus.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
local Gio = require("lgi").Gio
local await = require("await")
local a = require("a")
local parallel_async = require("util.parallel_async")
local properties = require("util.dbus.properties")
local properties_changed = require("util.dbus.properties_changed")
Expand All @@ -9,36 +9,34 @@ local M = {}
---@type table<table, SubscribeID>
local upower_listeners = setmetatable({}, { __mode = "k" })

---@param callback fun(bat_path?: string, err?: GError): unknown?
local function find_battery(callback)
return coroutine.wrap(function()
---@type GDBusConnection, GAsyncResult
local bus, gtask = await(function(resolve)
local name, path, iname = "org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower"
return Gio.bus_get_sync(Gio.BusType.SYSTEM)
:call(name, path, iname, "EnumerateDevices", nil, nil, 0, -1, nil, resolve)
end)
local result, err = bus:call_finish(gtask)
if not result or err then return callback(nil, err) end
local devices = result[1] --[[ @as string[] ]]
---@type table<string?, boolean>
local res = await(function(resolve)
return parallel_async(devices, function(dev, done)
return properties.get_all("org.freedesktop.UPower", dev, "org.freedesktop.UPower.Device", function(v_props)
local props = v_props[1] --[[ @as table<string, unknown> ]]
local Type, PowerSupply = props.Type, props.PowerSupply
assert(type(Type) == "number", "type is not a number") ---@cast Type number
assert(type(PowerSupply) == "boolean", "power_supply is not a boolean") ---@cast PowerSupply boolean
local is_battery = Type == 2
local is_laptop_battery = is_battery and PowerSupply
return done(is_laptop_battery)
end)
end, resolve)
end)
local _, bat = tables.find(res, function(is_battery) return is_battery end)
return callback(bat, nil)
end)()
end
---@type fun(callback: fun(bat_path?: string, err?: GError): unknown?)
local find_battery = a.sync(function()
---@type GDBusConnection, GAsyncResult
local bus, gtask = a.wait(function(resolve)
local name, path, iname = "org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower"
return Gio.bus_get_sync(Gio.BusType.SYSTEM)
:call(name, path, iname, "EnumerateDevices", nil, nil, 0, -1, nil, resolve)
end)
local result, err = bus:call_finish(gtask)
if not result or err then return nil, err end
local devices = result[1] --[[ @as string[] ]]
---@type table<string?, boolean>
local res = a.wait(function(resolve)
return parallel_async(devices, function(dev, done)
return properties.get_all("org.freedesktop.UPower", dev, "org.freedesktop.UPower.Device", function(v_props)
local props = v_props[1] --[[ @as table<string, unknown> ]]
local Type, PowerSupply = props.Type, props.PowerSupply
assert(type(Type) == "number", "type is not a number") ---@cast Type number
assert(type(PowerSupply) == "boolean", "power_supply is not a boolean") ---@cast PowerSupply boolean
local is_battery = Type == 2
local is_laptop_battery = is_battery and PowerSupply
return done(is_laptop_battery)
end)
end, resolve)
end)
local _, bat = tables.find(res, function(is_battery) return is_battery end)
return bat, nil
end)

---@param widget any
---@param callback fun(changed: {State: string}): any?
Expand Down

0 comments on commit 07e7119

Please sign in to comment.