Queue
A std.Io.Queue can be used to pass data between async functions.
The example here is an implementation of Fizz buzz using three async functions connected by queues.
const std = @import("std");
const Io = std.Io;
const Closed = Io.QueueClosedError.Closed;
const print = std.debug.print;
// gen generates numbers up to a maximum and sends
// them to a queue.
fn gen(
io: Io,
queue: *Io.Queue(u64),
max: u64,
) !void {
defer queue.close(io);
for (1..max) |n|
try queue.putOne(io, n);
}
// flt filters those numbers, replacing them with
// fizz/buzz/fizz buzz according to the rules of the
// game before sending them on to the next queue.
fn flt(
io: Io,
input: *Io.Queue(u64),
output: *Io.Queue(Number),
) !void {
defer output.close(io);
while (true) {
const n = input.getOne(io) catch |err|
return if (err == Closed) {} else err;
var result = Number{ .int = n };
if (n % 5 == 0 and n % 3 == 0) {
result = .{ .str = "fizz buzz" };
} else if (n % 5 == 0) {
result = .{ .str = "buzz" };
} else if (n % 3 == 0) {
result = .{ .str = "fizz" };
}
try output.putOne(io, result);
}
}
// The elements of the second queue are either a number
// or a string, so we use a tagged union.
const Number = union(enum) {
int: u64,
str: []const u8,
};
// prt prints the final result.
fn prt(
io: Io,
queue: *Io.Queue(Number),
) !void {
while (true) {
const n = queue.getOne(io) catch |err|
return if (err == Closed) {} else err;
switch (n) {
.int => |i| print("{d}\n", .{i}),
.str => |s| print("{s}\n", .{s}),
}
}
}
// run sets up the two queues, runs the three async
// functions, and waits for them to finish.
fn run(io: Io) !void {
var q1: Io.Queue(u64) = .init(&.{});
var q2: Io.Queue(Number) = .init(&.{});
// We’re using Io.concurrent here instead of
// Io.async because Io.concurrent guarantees that
// the functions run async. Io.async may fall back
// to running its argument directly, but here that
// would cause a deadlock.
var f1 = try io.concurrent(gen, .{ io, &q1, 20 });
defer f1.cancel(io) catch {};
var f2 = try io.concurrent(flt, .{ io, &q1, &q2 });
defer f2.cancel(io) catch {};
var f3 = try io.concurrent(prt, .{ io, &q2 });
defer f3.cancel(io) catch {};
try f1.await(io);
try f2.await(io);
try f3.await(io);
}
pub fn main(init: std.process.Init) !void {
try run(init.io);
}$ zig run queue.zig
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizz buzz
16
17
fizz
19
Next example: File System.