mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
124 lines
4.2 KiB
Zig
124 lines
4.2 KiB
Zig
const Loop = @This();
|
||
|
||
const std = @import("std");
|
||
const Allocator = std.mem.Allocator;
|
||
const testing = std.testing;
|
||
const c = @import("c.zig");
|
||
const errors = @import("error.zig");
|
||
|
||
loop: *c.uv_loop_t,
|
||
|
||
/// Initialize a new uv_loop.
|
||
pub fn init(alloc: Allocator) !Loop {
|
||
// The uv_loop_t type MUST be heap allocated and must not be copied.
|
||
// I can't find a definitive source on this, but the test suite starts
|
||
// hanging in weird places and doing bad things when it is copied.
|
||
const loop = try alloc.create(c.uv_loop_t);
|
||
try errors.convertError(c.uv_loop_init(loop));
|
||
return Loop{ .loop = loop };
|
||
}
|
||
|
||
/// Releases all internal loop resources. Call this function only when the
|
||
/// loop has finished executing and all open handles and requests have been
|
||
/// closed, or this will silently fail (in debug mode it will panic).
|
||
pub fn deinit(self: *Loop, alloc: Allocator) void {
|
||
// deinit functions idiomatically cannot fail in Zig, so we do the
|
||
// next best thing here and assert so that in debug mode you'll get
|
||
// a crash.
|
||
std.debug.assert(c.uv_loop_close(self.loop) >= 0);
|
||
alloc.destroy(self.loop);
|
||
self.* = undefined;
|
||
}
|
||
|
||
/// Returns true if the loop is still alive.
|
||
pub fn alive(self: Loop) !bool {
|
||
const res = c.uv_loop_alive(self.loop);
|
||
try errors.convertError(res);
|
||
return res > 0;
|
||
}
|
||
|
||
/// This function runs the event loop. See RunMode for mode documentation.
|
||
///
|
||
/// This is not reentrant. It must not be called from a callback.
|
||
pub fn run(self: Loop, mode: RunMode) !u32 {
|
||
const res = c.uv_run(self.loop, @enumToInt(mode));
|
||
try errors.convertError(res);
|
||
return @intCast(u32, res);
|
||
}
|
||
|
||
/// Stop the event loop, causing uv_run() to end as soon as possible. This
|
||
/// will happen not sooner than the next loop iteration. If this function was
|
||
/// called before blocking for i/o, the loop won’t block for i/o on this iteration.
|
||
pub fn stop(self: Loop) void {
|
||
c.uv_stop(self.loop);
|
||
}
|
||
|
||
/// Get backend file descriptor. Only kqueue, epoll and event ports are supported.
|
||
///
|
||
/// This can be used in conjunction with uv_run(loop, UV_RUN_NOWAIT) to poll
|
||
/// in one thread and run the event loop’s callbacks in another see
|
||
/// test/test-embed.c for an example.
|
||
pub fn backendFd(self: Loop) !c_int {
|
||
const res = c.uv_backend_fd(self.loop);
|
||
try errors.convertError(res);
|
||
return res;
|
||
}
|
||
|
||
/// Get the poll timeout. The return value is in milliseconds, or -1 for no
|
||
/// timeout.
|
||
pub fn backendTimeout(self: Loop) c_int {
|
||
return c.uv_backend_timeout(self.loop);
|
||
}
|
||
|
||
/// Return the current timestamp in milliseconds. The timestamp is cached at
|
||
/// the start of the event loop tick, see uv_update_time() for details and rationale.
|
||
///
|
||
/// The timestamp increases monotonically from some arbitrary point in time.
|
||
/// Don’t make assumptions about the starting point, you will only get disappointed.
|
||
pub fn now(self: Loop) u64 {
|
||
return c.uv_now(self.loop);
|
||
}
|
||
|
||
/// Update the event loop’s concept of “now”. Libuv caches the current time at
|
||
/// the start of the event loop tick in order to reduce the number of time-related
|
||
/// system calls.
|
||
///
|
||
/// You won’t normally need to call this function unless you have callbacks
|
||
/// that block the event loop for longer periods of time, where “longer” is
|
||
/// somewhat subjective but probably on the order of a millisecond or more.
|
||
pub fn updateTime(self: Loop) void {
|
||
return c.uv_update_time(self.loop);
|
||
}
|
||
|
||
/// Sets loop->data to data.
|
||
pub fn setData(self: Loop, pointer: ?*anyopaque) void {
|
||
c.uv_loop_set_data(self.loop, pointer);
|
||
}
|
||
|
||
/// Returns loop->data.
|
||
pub fn getData(self: Loop, comptime DT: type) ?*DT {
|
||
return if (c.uv_loop_get_data(self.loop)) |ptr|
|
||
@ptrCast(?*DT, @alignCast(@alignOf(DT), ptr))
|
||
else
|
||
null;
|
||
}
|
||
|
||
/// Mode used to run the loop with uv_run().
|
||
pub const RunMode = enum(c.uv_run_mode) {
|
||
default = c.UV_RUN_DEFAULT,
|
||
once = c.UV_RUN_ONCE,
|
||
nowait = c.UV_RUN_NOWAIT,
|
||
};
|
||
|
||
test {
|
||
var loop = try init(testing.allocator);
|
||
defer loop.deinit(testing.allocator);
|
||
|
||
var data: u8 = 42;
|
||
loop.setData(&data);
|
||
try testing.expect(loop.getData(u8).?.* == 42);
|
||
|
||
try testing.expect((try loop.backendFd()) > 0);
|
||
try testing.expectEqual(@as(u32, 0), try loop.run(.nowait));
|
||
}
|