From 6b733537abec526a878c3fd2f62d7ec2386ded56 Mon Sep 17 00:00:00 2001 From: Brandon Black Date: Wed, 14 Jan 2026 18:18:29 -0600 Subject: [PATCH] Io.Select: add fn concurrent --- lib/std/Io.zig | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 38ed8c865a0eacee50db950cc707d9e2a32b3bc3..f757e747ca0f6b865b91fcc2a3f7dbd1b988cd59 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -1283,6 +1283,46 @@ pub fn Select(comptime U: type) type { s.io.vtable.groupAsync(s.io.userdata, &s.group, @ptrCast(&context), .of(Context), Context.start); } + /// Calls `function` with `args` concurrently. The resource spawned is + /// owned by the select. + /// + /// `function` must have return type matching the `field` field of `Union`. + /// + /// After this function returns successfully, it is guaranteed that + /// `function` has been assigned a unit of concurrency, and `await` or + /// `cancel` must be called before the select is deinitialized. + /// + /// + /// Threadsafe. + /// + /// Related: + /// * `Io.concurrent` + /// * `Group.concurrent` + pub fn concurrent( + s: *S, + comptime field: Field, + function: anytype, + args: std.meta.ArgsTuple(@TypeOf(function)), + ) ConcurrentError!void { + const Context = struct { + select: *S, + args: @TypeOf(args), + fn start(type_erased_context: *const anyopaque) Cancelable!void { + const context: *const @This() = @ptrCast(@alignCast(type_erased_context)); + const raw_result = @call(.auto, function, context.args); + const elem = @unionInit(U, @tagName(field), raw_result); + context.select.queue.putOneUncancelable(context.select.io, elem) catch |err| switch (err) { + error.Closed => unreachable, + }; + if (@typeInfo(@TypeOf(raw_result)) == .error_union) + raw_result catch |err| if (err == error.Canceled) return error.Canceled; + } + }; + const context: Context = .{ .select = s, .args = args }; + try s.io.vtable.groupConcurrent(s.io.userdata, &s.group, @ptrCast(&context), .of(Context), Context.start); + _ = @atomicRmw(usize, &s.outstanding, .Add, 1, .monotonic); + } + /// Blocks until another task of the select finishes. /// /// Asserts there is at least one more `outstanding` task. -- 2.54.0