Open
Description
I thought I had already proposed this but I could not find it. This depends on the , which is related to #3164 but I will open an explicit proposal for it.cancel
proposal being accepted
There is one thing missing with zig's async
/ await
features which is the ability to respond to the first completed function. Here's a use case:
fn httpRequestWithTimeout(url: []const, timeout_duration: u64) !Response {
var request_tok = CancelToken{};
var request = async httpRequest(url, &request_tok);
defer request_tok.cancel(&request);
var timeout_tok = CancelToken{};
var timeout = async sleep(timeout_duration, &timeout_tok);
defer timeout_tok.cancel(&timeout);
select {
request => |result| {
request_tok.awaited = true;
return result;
},
timeout => {
timeout_tok.awaited = true;
return error.TimedOut;
},
}
}
Here's a more complicated example, which shows how select also supports arrays of frames:
fn httpRequestWithMirrors(mirrors: []const []const u8) !Request {
const frames = try allocator.alloc(@Frame(httpRequest), mirrors.len);
defer allocator.free(frames);
const cancel_tokens = try allocator.alloc(CancelToken, mirrors.len);
defer allocator.free(cancel_tokens);
for (frames) |*frame, i| {
cancel_tokens[i] = CancelToken{};
frame.* = async httpRequest(mirrors[i], &cancel_token[i]);
}
defer for (cancel_tokens) |*tok, i| tok.cancel(&frames[i]);
var in_flight_count: usize = mirrors.len;
while (true) {
select {
frames => |result, i| {
cancel_tokens[i].awaited = true;
if (result) |payload| {
return payload;
} else |err| {
in_flight_count -= 1;
if (in_flight_count == 0)
return err;
}
},
}
}
}
Here's another use case:
Lines 68 to 86 in 9b788b7
As an alternative syntax, we could replace select
with await
. Since only labeled blocks can return values, await {
is unambiguously the "select" form of await
.