const SelectFrames = struct { frames: []@Frame(runInternal), next_get_result: usize, next_put_result: usize, result_frames: []@Frame(awaitResultInternal); result_values: []Result; pub fn init(self: *@This(), in_frames: []anyframe->Result) !void { const wrapped_frames = try allocator.alloc(@Frame(runInternal), in_frames.len); errdefer allocator.free(wrapped_frames); const result_frames = try allocator.alloc(@Frame(awaitResultInternal), in_frames.len); errdefer allocator.free(result_frames); const results = try allocator.alloc(Result, in_frames.len); errdefer allocator.free(results); self = .{ .frames = wrapped_frames, .next_get_result = 0, .next_put_result = 0, .result_frames = result_frames, .dispose_frames = results, }; for (result_frames) |*frame| { frame.* = async awaitResultInternal(self); } for (wrapped_frames) |*frame, i| { frame.* = async runInternal(self, in_frames[i]); } } /// Blocks until any result is available, and returns it. pub fn next(self: *PollFrames) Result { const index = atomic_increment(&self.next_get_result); await self.result_frames[index]; return self.result_values[index]; } fn runInternal(self: *PollFrames, frame: anyframe->Result) void { const result = await frame; const index = atomic_increment(&self.next_put_result); result_values[index] = result; resume result_frames[index]; } fn awaitResultInternal(self: *PollFrames) Result { suspend; // resumed by finished function } }