authorgravatar for bblack@wikimedia.orgBrandon Black <bblack@wikimedia.org> 2026-01-14 18:18:29-06:00
committergravatar for bblack@wikimedia.orgBrandon Black <bblack@wikimedia.org> 2026-01-14 18:25:49-06:00
log6b733537abec526a878c3fd2f62d7ec2386ded56
treeed6a1707641c44b1ca412b8893533352e5656e78
parent376320a5e9bfc32162c81b592784e6f54aeae62b

Io.Select: add fn concurrent


1 files changed, 40 insertions(+), 0 deletions(-)

lib/std/Io.zig+40
......@@ -1283,6 +1283,46 @@ pub fn Select(comptime U: type) type {
12831283 s.io.vtable.groupAsync(s.io.userdata, &s.group, @ptrCast(&context), .of(Context), Context.start);
12841284 }
12851285
1286 /// Calls `function` with `args` concurrently. The resource spawned is
1287 /// owned by the select.
1288 ///
1289 /// `function` must have return type matching the `field` field of `Union`.
1290 ///
1291 /// After this function returns successfully, it is guaranteed that
1292 /// `function` has been assigned a unit of concurrency, and `await` or
1293 /// `cancel` must be called before the select is deinitialized.
1294 ///
1295 ///
1296 /// Threadsafe.
1297 ///
1298 /// Related:
1299 /// * `Io.concurrent`
1300 /// * `Group.concurrent`
1301 pub fn concurrent(
1302 s: *S,
1303 comptime field: Field,
1304 function: anytype,
1305 args: std.meta.ArgsTuple(@TypeOf(function)),
1306 ) ConcurrentError!void {
1307 const Context = struct {
1308 select: *S,
1309 args: @TypeOf(args),
1310 fn start(type_erased_context: *const anyopaque) Cancelable!void {
1311 const context: *const @This() = @ptrCast(@alignCast(type_erased_context));
1312 const raw_result = @call(.auto, function, context.args);
1313 const elem = @unionInit(U, @tagName(field), raw_result);
1314 context.select.queue.putOneUncancelable(context.select.io, elem) catch |err| switch (err) {
1315 error.Closed => unreachable,
1316 };
1317 if (@typeInfo(@TypeOf(raw_result)) == .error_union)
1318 raw_result catch |err| if (err == error.Canceled) return error.Canceled;
1319 }
1320 };
1321 const context: Context = .{ .select = s, .args = args };
1322 try s.io.vtable.groupConcurrent(s.io.userdata, &s.group, @ptrCast(&context), .of(Context), Context.start);
1323 _ = @atomicRmw(usize, &s.outstanding, .Add, 1, .monotonic);
1324 }
1325
12861326 /// Blocks until another task of the select finishes.
12871327 ///
12881328 /// Asserts there is at least one more `outstanding` task.