diff --git a/src/libuv/Timer.zig b/src/libuv/Timer.zig index 6b6db57fd..9d2195d28 100644 --- a/src/libuv/Timer.zig +++ b/src/libuv/Timer.zig @@ -25,13 +25,55 @@ pub fn deinit(self: *Timer, alloc: Allocator) void { self.* = undefined; } +/// Start the timer. timeout and repeat are in milliseconds. +/// +/// If timeout is zero, the callback fires on the next event loop iteration. +/// If repeat is non-zero, the callback fires first after timeout milliseconds +/// and then repeatedly after repeat milliseconds. +pub fn start( + self: Timer, + comptime cb: fn (Timer) void, + timeout: u64, + repeat: u64, +) !void { + const Wrapper = struct { + pub fn callback(handle: [*c]c.uv_timer_t) callconv(.C) void { + const newSelf: Timer = .{ .handle = handle }; + @call(.{ .modifier = .always_inline }, cb, .{newSelf}); + } + }; + + try errors.convertError(c.uv_timer_start( + self.handle, + Wrapper.callback, + timeout, + repeat, + )); +} + +/// Stop the timer, the callback will not be called anymore. +pub fn stop(self: Timer) !void { + try errors.convertError(c.uv_timer_stop(self.handle)); +} + test "Timer" { var loop = try Loop.init(testing.allocator); defer loop.deinit(testing.allocator); var timer = try init(testing.allocator, loop); defer timer.deinit(testing.allocator); - timer.close(null); + + var called: bool = false; + timer.setData(&called); + try timer.start((struct { + fn callback(t: Timer) void { + t.getData(bool).?.* = true; + t.close(null); + } + }).callback, 10, 1000); + _ = try loop.run(.default); + + try testing.expect(called); } test "Timer: close callback" { @@ -43,7 +85,7 @@ test "Timer: close callback" { var data: u8 = 42; timer.setData(&data); timer.close((struct { - fn callback(v: *Timer) void { + fn callback(v: Timer) void { var dataPtr = v.getData(u8).?; dataPtr.* = 24; } diff --git a/src/libuv/handle.zig b/src/libuv/handle.zig index bfec0e8dc..adb088300 100644 --- a/src/libuv/handle.zig +++ b/src/libuv/handle.zig @@ -23,16 +23,15 @@ pub fn Handle(comptime T: type) type { // // In-progress requests, like uv_connect_t or uv_write_t, are cancelled // and have their callbacks called asynchronously with status=UV_ECANCELED. - pub fn close(self: *T, comptime cb: ?fn (*T) void) void { + pub fn close(self: T, comptime cb: ?fn (T) void) void { const cbParam = if (cb) |f| (struct { pub fn callback(handle: [*c]c.uv_handle_t) callconv(.C) void { // We get the raw handle, so we need to reconstruct // the T. This is mutable because a lot of the libuv APIs // are non-const but modifying it makes no sense. - var param: T = .{ .handle = @ptrCast(HandleType, handle) }; - - @call(.{ .modifier = .always_inline }, f, .{¶m}); + const param: T = .{ .handle = @ptrCast(HandleType, handle) }; + @call(.{ .modifier = .always_inline }, f, .{param}); } }).callback else @@ -42,7 +41,7 @@ pub fn Handle(comptime T: type) type { } /// Sets handle->data to data. - pub fn setData(self: *T, pointer: ?*anyopaque) void { + pub fn setData(self: T, pointer: ?*anyopaque) void { c.uv_handle_set_data( @ptrCast(*c.uv_handle_t, self.handle), pointer, @@ -50,7 +49,7 @@ pub fn Handle(comptime T: type) type { } /// Returns handle->data. - pub fn getData(self: *T, comptime DT: type) ?*DT { + pub fn getData(self: T, comptime DT: type) ?*DT { return if (c.uv_handle_get_data(@ptrCast(*c.uv_handle_t, self.handle))) |ptr| @ptrCast(?*DT, @alignCast(@alignOf(DT), ptr)) else