summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.zig46
-rw-r--r--exercises/084_interfaces.zig (renamed from exercises/095_interfaces.zig)0
-rw-r--r--exercises/085_async.zig (renamed from exercises/084_async.zig)0
-rw-r--r--exercises/086_async2.zig (renamed from exercises/085_async2.zig)0
-rw-r--r--exercises/087_async3.zig (renamed from exercises/086_async3.zig)0
-rw-r--r--exercises/088_async4.zig (renamed from exercises/087_async4.zig)0
-rw-r--r--exercises/089_async5.zig (renamed from exercises/088_async5.zig)0
-rw-r--r--exercises/090_async6.zig (renamed from exercises/089_async6.zig)0
-rw-r--r--exercises/091_async7.zig (renamed from exercises/090_async7.zig)0
-rw-r--r--exercises/092_async8.zig (renamed from exercises/091_async8.zig)0
-rw-r--r--exercises/093_async9.zig (renamed from exercises/092_async9.zig)0
-rw-r--r--exercises/094_async10.zig (renamed from exercises/093_async10.zig)0
-rw-r--r--exercises/095_quiz_async.zig186
-rw-r--r--patches/patches/084_interfaces.patch11
-rw-r--r--patches/patches/085_async.patch11
-rw-r--r--patches/patches/086_async2.patch14
-rw-r--r--patches/patches/087_async3.patch18
-rw-r--r--patches/patches/088_async4.patch11
-rw-r--r--patches/patches/089_async5.patch11
-rw-r--r--patches/patches/090_async6.patch11
-rw-r--r--patches/patches/091_async7.patch13
-rw-r--r--patches/patches/092_async8.patch11
-rw-r--r--patches/patches/093_async9.patch11
-rw-r--r--patches/patches/094_async10.patch13
-rw-r--r--patches/patches/095_quiz_async.patch52
25 files changed, 399 insertions, 20 deletions
diff --git a/build.zig b/build.zig
index b9aaac3..beb0d72 100644
--- a/build.zig
+++ b/build.zig
@@ -1109,20 +1109,29 @@ const exercises = [_]Exercise{
.main_file = "083_anonymous_lists.zig",
.output = "I say hello!",
},
+ .{
+ .main_file = "084_interfaces.zig",
+ .output =
+ \\Daily Insect Report:
+ \\Ant is alive.
+ \\Bee visited 17 flowers.
+ \\Grasshopper hopped 32 meters.
+ , // pay attention to the comma
+ },
// Skipped because of https://github.com/ratfactor/ziglings/issues/163
// direct link: https://github.com/ziglang/zig/issues/6025
.{
- .main_file = "084_async.zig",
+ .main_file = "085_async.zig",
.output = "Current time: <timestamp>s since epoch",
.timestamp = true,
},
.{
- .main_file = "085_async2.zig",
+ .main_file = "086_async2.zig",
.output = "Computing... the answer is: 42",
},
.{
- .main_file = "086_async3.zig",
+ .main_file = "087_async3.zig",
.output =
\\1 + 2 = 3
\\6 * 7 = 42
@@ -1130,7 +1139,7 @@ const exercises = [_]Exercise{
, // pay attention to the comma
},
.{
- .main_file = "087_async4.zig",
+ .main_file = "088_async4.zig",
.output =
\\Task 1 done.
\\Task 2 done.
@@ -1139,7 +1148,7 @@ const exercises = [_]Exercise{
, // pay attention to the comma
},
.{
- .main_file = "088_async5.zig",
+ .main_file = "089_async5.zig",
.output =
\\Starting long computation...
\\Canceling slow task...
@@ -1148,19 +1157,19 @@ const exercises = [_]Exercise{
, // pay attention to the comma
},
.{
- .main_file = "089_async6.zig",
+ .main_file = "090_async6.zig",
.output = "Hare: I'm fast!",
},
.{
- .main_file = "090_async7.zig",
+ .main_file = "091_async7.zig",
.output = "Counter: 400",
},
.{
- .main_file = "091_async8.zig",
+ .main_file = "092_async8.zig",
.output = "Sum of 1..10 = 55",
},
.{
- .main_file = "092_async9.zig",
+ .main_file = "093_async9.zig",
.output =
\\Main thread continues...
\\Computing on a separate thread!
@@ -1169,7 +1178,7 @@ const exercises = [_]Exercise{
, // pay attention to the comma
},
.{
- .main_file = "093_async10.zig",
+ .main_file = "094_async10.zig",
.output =
\\Starting critical section...
\\Critical section completed safely.
@@ -1177,17 +1186,14 @@ const exercises = [_]Exercise{
, // pay attention to the comma
},
.{
- .main_file = "094_async_quiz.zig",
- .output = "",
- .skip = true,
- },
- .{
- .main_file = "095_interfaces.zig",
+ .main_file = "095_quiz_async.zig",
.output =
- \\Daily Insect Report:
- \\Ant is alive.
- \\Bee visited 17 flowers.
- \\Grasshopper hopped 32 meters.
+ \\=== Doctor Zoraptera's Garden Report ===
+ \\Temperature : 23C
+ \\Humidity : 63%
+ \\Wind : 13 km/h
+ \\Readings : 9
+ \\Bee-friendly conditions! Expect high pollination.
, // pay attention to the comma
},
.{
diff --git a/exercises/095_interfaces.zig b/exercises/084_interfaces.zig
index 7775dd5..7775dd5 100644
--- a/exercises/095_interfaces.zig
+++ b/exercises/084_interfaces.zig
diff --git a/exercises/084_async.zig b/exercises/085_async.zig
index 48bda2b..48bda2b 100644
--- a/exercises/084_async.zig
+++ b/exercises/085_async.zig
diff --git a/exercises/085_async2.zig b/exercises/086_async2.zig
index 1f1c4c8..1f1c4c8 100644
--- a/exercises/085_async2.zig
+++ b/exercises/086_async2.zig
diff --git a/exercises/086_async3.zig b/exercises/087_async3.zig
index 07221e9..07221e9 100644
--- a/exercises/086_async3.zig
+++ b/exercises/087_async3.zig
diff --git a/exercises/087_async4.zig b/exercises/088_async4.zig
index 50829fc..50829fc 100644
--- a/exercises/087_async4.zig
+++ b/exercises/088_async4.zig
diff --git a/exercises/088_async5.zig b/exercises/089_async5.zig
index 4fb8d76..4fb8d76 100644
--- a/exercises/088_async5.zig
+++ b/exercises/089_async5.zig
diff --git a/exercises/089_async6.zig b/exercises/090_async6.zig
index eab03c9..eab03c9 100644
--- a/exercises/089_async6.zig
+++ b/exercises/090_async6.zig
diff --git a/exercises/090_async7.zig b/exercises/091_async7.zig
index bfe6ffd..bfe6ffd 100644
--- a/exercises/090_async7.zig
+++ b/exercises/091_async7.zig
diff --git a/exercises/091_async8.zig b/exercises/092_async8.zig
index 10921c3..10921c3 100644
--- a/exercises/091_async8.zig
+++ b/exercises/092_async8.zig
diff --git a/exercises/092_async9.zig b/exercises/093_async9.zig
index ad30dcf..ad30dcf 100644
--- a/exercises/092_async9.zig
+++ b/exercises/093_async9.zig
diff --git a/exercises/093_async10.zig b/exercises/094_async10.zig
index 6ed229d..6ed229d 100644
--- a/exercises/093_async10.zig
+++ b/exercises/094_async10.zig
diff --git a/exercises/095_quiz_async.zig b/exercises/095_quiz_async.zig
new file mode 100644
index 0000000..fb78e7b
--- /dev/null
+++ b/exercises/095_quiz_async.zig
@@ -0,0 +1,186 @@
+//
+// Quiz Time — Async I/O!
+//
+// Doctor Zoraptera's insect simulation is going well, but she
+// realized that her virtual garden needs weather data! Insects
+// behave differently depending on temperature, humidity, and
+// wind conditions.
+//
+// She has set up three weather sensors around the garden that
+// measure conditions in parallel and report their readings
+// through a shared data channel. A collector task gathers the
+// readings, and after all sensors have reported, a garden
+// report is printed.
+//
+// But Doctor Z rushed through the code (she was being chased
+// by a grasshopper) and left several bugs. Can you fix them?
+//
+// Here's what the program should do:
+// 1. Three sensor tasks run concurrently, each sending
+// exactly 3 readings through a Queue
+// 2. A collector task receives readings, protected by a Mutex
+// 3. After all sensors finish, the queue is closed
+// 4. The final report is written in a cancel-protected section
+//
+// *************************************************************
+// * A NOTE ABOUT THIS EXERCISE *
+// * *
+// * This quiz uses concepts from exercises 084-093. *
+// * There are 6 bugs to fix — look for the ???s! *
+// * *
+// *************************************************************
+//
+const std = @import("std");
+const print = std.debug.print;
+
+const SensorType = enum { thermometer, hygrometer, anemometer };
+
+const Reading = struct {
+ sensor_type: SensorType,
+ value: i32,
+};
+
+const GardenWeather = struct {
+ temperature: i32 = 0,
+ humidity: i32 = 0,
+ wind: i32 = 0,
+ readings_count: u32 = 0,
+ mutex: std.Io.Mutex = .init,
+
+ fn addReading(self: *GardenWeather, io: std.Io, reading: Reading) void {
+ // Bug 1: The collector needs to lock before modifying
+ // shared state. What Mutex method acquires the lock?
+ self.mutex.lock(io) catch return;
+ self.mutex.???(io) catch return;
+
+ switch (reading.sensor_type) {
+ .thermometer => self.temperature = reading.value,
+ .hygrometer => self.humidity = reading.value,
+ .anemometer => self.wind = reading.value,
+ }
+ self.readings_count += 1;
+ }
+};
+
+pub fn main(init: std.process.Init) !void {
+ const io = init.io;
+
+ var weather = GardenWeather{};
+
+ var reading_buf: [8]Reading = undefined;
+ var queue: std.Io.Queue(Reading) = .init(&reading_buf);
+
+ // Sensor group: runs all three sensors to completion.
+ var sensors: std.Io.Group = .init;
+
+ // Start three sensor tasks. They need GUARANTEED concurrency
+ // since they each simulate real-time measurement.
+ //
+ // Bug 2: io.async doesn't guarantee a separate thread.
+ // Which Io method guarantees true concurrency?
+ // (Don't forget: it can fail, so you need 'try'!)
+ try sensors.???(io, sensor, .{ io, &queue, .thermometer, 20 });
+ try sensors.???(io, sensor, .{ io, &queue, .hygrometer, 60 });
+ try sensors.???(io, sensor, .{ io, &queue, .anemometer, 10 });
+
+ // Collector group: processes readings from the queue.
+ var collectors: std.Io.Group = .init;
+ collectors.async(io, collector, .{ io, &queue, &weather });
+
+ // Bug 3: Wait for ALL sensors to finish sending their readings.
+ // What Group method blocks until all tasks complete?
+ try sensors.await(io);
+ // try sensors.???(io);
+
+ // All sensors done — close the queue so the collector knows
+ // there's no more data coming.
+ queue.close(io);
+
+ // Wait for the collector to drain the queue.
+ try collectors.await(io);
+
+ // Now write the garden report. This is critical — it must
+ // NOT be interrupted, even if something tries to cancel us!
+ //
+ // Bug 4: Protect this section from cancellation.
+ // What Io method swaps the cancel protection state?
+ const old_protection = io.???(.blocked);
+ defer _ = io.???(old_protection);
+
+ printGardenReport(&weather);
+}
+
+fn sensor(
+ io: std.Io,
+ queue: *std.Io.Queue(Reading),
+ sensor_type: SensorType,
+ base_value: i32,
+) void {
+ // Each sensor takes exactly 3 measurements.
+ for (1..4) |i| {
+ io.sleep(std.Io.Duration.fromMilliseconds(100), .awake) catch return;
+
+ const reading = Reading{
+ .sensor_type = sensor_type,
+ .value = base_value + @as(i32, @intCast(i)),
+ };
+
+ // Bug 5: Send the reading into the queue.
+ // What Queue method sends a single element?
+ queue.???(io, reading) catch return;
+ }
+}
+
+fn collector(
+ io: std.Io,
+ queue: *std.Io.Queue(Reading),
+ weather: *GardenWeather,
+) void {
+ while (true) {
+ const reading = queue.getOne(io) catch |err| switch (err) {
+ error.Closed => break,
+ error.Canceled => return,
+ };
+ weather.addReading(io, reading);
+ }
+}
+
+fn printGardenReport(weather: *GardenWeather) void {
+ print("=== Doctor Zoraptera's Garden Report ===\n", .{});
+ print("Temperature : {}C\n", .{weather.temperature});
+ print("Humidity : {}%\n", .{weather.humidity});
+ print("Wind : {} km/h\n", .{weather.wind});
+ print("Readings : {}\n", .{weather.readings_count});
+
+ if (weather.temperature > 20 and weather.wind < 15) {
+ print("Bee-friendly conditions! Expect high pollination.\n", .{});
+ } else {
+ print("Grasshoppers will be grumpy today.\n", .{});
+ }
+}
+
+// Further reading for the curious:
+//
+// This quiz covered the main async I/O primitives:
+// io.async() - launch a task (may run inline)
+// io.concurrent() - launch with guaranteed parallelism
+// Group.concurrent() - concurrent tasks in a group
+// Future.await/cancel - collect or cancel a single task
+// Group.async/await/cancel - manage fire-and-forget tasks
+// Select.async/await - race tasks, act on first completion
+// Queue - bounded channel between tasks
+// Mutex - protect shared state
+// CancelProtection - shield critical sections
+//
+// There are more synchronization primitives we didn't cover:
+// Condition - wait for a condition to become true
+// RwLock - multiple readers OR one writer
+// Semaphore - limit concurrent access to a resource
+// Futex - low-level wait/wake on a memory address
+// Batch - submit multiple I/O operations at once
+//
+// The key insight: all of these work through the Io VTable,
+// so your code is portable across backends (Threaded, Uring,
+// Kqueue, Dispatch) without any changes!
+//
+// Doctor Zoraptera approves.
diff --git a/patches/patches/084_interfaces.patch b/patches/patches/084_interfaces.patch
new file mode 100644
index 0000000..a1d0628
--- /dev/null
+++ b/patches/patches/084_interfaces.patch
@@ -0,0 +1,11 @@
+--- exercises/084_interfaces.zig 2025-08-15 15:17:57.839348063 +0200
++++ answers/084_interfaces.zig 2026-04-03 14:27:32.670756488 +0200
+@@ -106,7 +106,7 @@
+ for (my_insects) |insect| {
+ // Almost done! We want to print() each insect with a
+ // single method call here.
+- ???
++ insect.print();
+ }
+ }
+
diff --git a/patches/patches/085_async.patch b/patches/patches/085_async.patch
new file mode 100644
index 0000000..ca8b102
--- /dev/null
+++ b/patches/patches/085_async.patch
@@ -0,0 +1,11 @@
+--- exercises/085_async.zig 2026-04-01 20:40:08.904999609 +0200
++++ answers/085_async.zig 2026-04-01 20:40:05.641933231 +0200
+@@ -37,7 +37,7 @@
+ const std = @import("std");
+
+ pub fn main(init: std.process.Init) !void {
+- const io = init.???;
++ const io = init.io;
+
+ // Get the current wall-clock time using the Io interface.
+ // Hint: Timestamp.now() takes an Io and a Clock type (.real = wall clock).
diff --git a/patches/patches/086_async2.patch b/patches/patches/086_async2.patch
new file mode 100644
index 0000000..7506a69
--- /dev/null
+++ b/patches/patches/086_async2.patch
@@ -0,0 +1,14 @@
+--- exercises/086_async2.zig 2026-04-01 19:22:50.017227542 +0200
++++ answers/086_async2.zig 2026-04-01 19:21:57.569158481 +0200
+@@ -38,9 +38,9 @@
+
+ // Now collect the result. What method on Future gives us
+ // the value, blocking if it isn't ready yet?
+- const answer = future.???(io);
++ const answer = future.await(io);
+
+- std.debug.print("The answer is: {}\n", .{answer});
++ std.debug.print("the answer is: {}\n", .{answer});
+ }
+
+ fn computeAnswer(a: u32, b: u32) u32 {
diff --git a/patches/patches/087_async3.patch b/patches/patches/087_async3.patch
new file mode 100644
index 0000000..8365e7a
--- /dev/null
+++ b/patches/patches/087_async3.patch
@@ -0,0 +1,18 @@
+--- exercises/087_async3.zig 2026-04-01 22:51:05.540094851 +0200
++++ answers/087_async3.zig 2026-04-01 22:50:44.579669189 +0200
+@@ -29,12 +29,12 @@
+ const io = init.io;
+
+ // Launch both tasks asynchronously.
+- var future_a = io.async(slowAdd, .{ 10, 20 });
+- var future_b = ???(slowMul, .{ 6, 7 });
++ var future_a = io.async(slowAdd, .{ 1, 2 });
++ var future_b = io.async(slowMul, .{ 6, 7 });
+
+ // Await both results.
+ const sum = future_a.await(io);
+- const product = future_b.???(io);
++ const product = future_b.await(io);
+
+ print("{} + {} = {}\n", .{ 1, 2, sum });
+ print("{} * {} = {}\n", .{ 6, 7, product });
diff --git a/patches/patches/088_async4.patch b/patches/patches/088_async4.patch
new file mode 100644
index 0000000..1faf30e
--- /dev/null
+++ b/patches/patches/088_async4.patch
@@ -0,0 +1,11 @@
+--- exercises/088_async4.zig 2026-04-01 23:17:31.066443941 +0200
++++ answers/088_async4.zig 2026-04-01 23:17:39.251612131 +0200
+@@ -38,7 +38,7 @@
+
+ // Wait for all tasks to finish.
+ // What Group method blocks until all tasks complete?
+- try group.???
++ try group.await(io);
+
+ print("All tasks finished!\n", .{});
+ }
diff --git a/patches/patches/089_async5.patch b/patches/patches/089_async5.patch
new file mode 100644
index 0000000..d2baa96
--- /dev/null
+++ b/patches/patches/089_async5.patch
@@ -0,0 +1,11 @@
+--- exercises/089_async5.zig 2026-04-01 23:40:40.505855238 +0200
++++ answers/089_async5.zig 2026-04-01 23:40:10.176236971 +0200
+@@ -40,7 +40,7 @@
+
+ // We don't want to wait 10 seconds!
+ // Which Future method requests cancellation AND returns the result?
+- const result = ???;
++ const result = future.cancel(io);
+
+ print("Task returned: {}\n", .{result});
+ }
diff --git a/patches/patches/090_async6.patch b/patches/patches/090_async6.patch
new file mode 100644
index 0000000..5ac777b
--- /dev/null
+++ b/patches/patches/090_async6.patch
@@ -0,0 +1,11 @@
+--- exercises/090_async6.zig 2026-04-02 10:25:34.016616118 +0200
++++ answers/090_async6.zig 2026-04-02 10:27:48.827144051 +0200
+@@ -47,7 +47,7 @@
+
+ // Wait for the first finisher.
+ // What Select method returns the first completed result?
+- const winner = ???;
++ const winner = try sel.await();
+
+ switch (winner) {
+ .hare => |msg| print("Hare: {s}\n", .{msg}),
diff --git a/patches/patches/091_async7.patch b/patches/patches/091_async7.patch
new file mode 100644
index 0000000..b4bab9b
--- /dev/null
+++ b/patches/patches/091_async7.patch
@@ -0,0 +1,13 @@
+--- exercises/091_async7.zig 2026-04-02 10:50:08.142508099 +0200
++++ answers/091_async7.zig 2026-04-02 10:49:59.629341593 +0200
+@@ -49,8 +49,8 @@
+ for (0..times) |_| {
+ // Acquire the lock before modifying shared state.
+ // What Mutex method blocks until the lock is acquired?
+- state.mutex.??? catch return;
+- defer state.mutex.unlock(); // <-- what's missing here?
++ state.mutex.lock(io) catch return;
++ defer state.mutex.unlock(io);
+
+ state.counter += 1;
+ }
diff --git a/patches/patches/092_async8.patch b/patches/patches/092_async8.patch
new file mode 100644
index 0000000..0ec9116
--- /dev/null
+++ b/patches/patches/092_async8.patch
@@ -0,0 +1,11 @@
+--- exercises/092_async8.zig 2026-04-02 10:49:27.925721496 +0200
++++ answers/092_async8.zig 2026-04-02 10:49:31.694795212 +0200
+@@ -43,7 +43,7 @@
+ // Send numbers 1 through 10 into the queue.
+ for (1..11) |i| {
+ // What Queue method sends a single element, blocking if full?
+- queue.???(io, @intCast(i)) catch return;
++ queue.putOne(io, @intCast(i)) catch return;
+ }
+ // Signal that we're done sending.
+ queue.close(io);
diff --git a/patches/patches/093_async9.patch b/patches/patches/093_async9.patch
new file mode 100644
index 0000000..f759921
--- /dev/null
+++ b/patches/patches/093_async9.patch
@@ -0,0 +1,11 @@
+--- exercises/093_async9.zig 2026-04-03 13:44:50.526780809 +0200
++++ answers/093_async9.zig 2026-04-03 13:44:54.957870294 +0200
+@@ -36,7 +36,7 @@
+ // Launch with a guaranteed separate thread.
+ // Which Io method guarantees true concurrency?
+ // (Hint: unlike io.async, this one can fail!)
+- var future = try io.???(compute, .{io});
++ var future = try io.concurrent(compute, .{io});
+
+ print("Main thread continues...\n", .{});
+
diff --git a/patches/patches/094_async10.patch b/patches/patches/094_async10.patch
new file mode 100644
index 0000000..ae0d26d
--- /dev/null
+++ b/patches/patches/094_async10.patch
@@ -0,0 +1,13 @@
+--- exercises/094_async10.zig 2026-04-03 14:25:16.600025924 +0200
++++ answers/094_async10.zig 2026-04-03 14:24:56.192615893 +0200
+@@ -50,8 +50,8 @@
+
+ // Protect this section from cancellation.
+ // What method swaps the cancel protection state?
+- const old = io.???(. blocked);
+- defer _ = io.???(old);
++ const old = io.swapCancelProtection(.blocked);
++ defer _ = io.swapCancelProtection(old);
+
+ // This sleep will NOT return error.Canceled even though
+ // we get canceled during it — protection is active!
diff --git a/patches/patches/095_quiz_async.patch b/patches/patches/095_quiz_async.patch
new file mode 100644
index 0000000..dbaae07
--- /dev/null
+++ b/patches/patches/095_quiz_async.patch
@@ -0,0 +1,52 @@
+--- exercises/095_quiz_async.zig 2026-04-03 18:04:53.577391455 +0200
++++ answers/095_quiz_async.zig 2026-04-03 18:05:42.570392172 +0200
+@@ -51,7 +51,7 @@
+ // Bug 1: The collector needs to lock before modifying
+ // shared state. What Mutex method acquires the lock?
+ self.mutex.lock(io) catch return;
+- self.mutex.???(io) catch return;
++ defer self.mutex.unlock(io);
+
+ switch (reading.sensor_type) {
+ .thermometer => self.temperature = reading.value,
+@@ -79,9 +79,9 @@
+ // Bug 2: io.async doesn't guarantee a separate thread.
+ // Which Io method guarantees true concurrency?
+ // (Don't forget: it can fail, so you need 'try'!)
+- try sensors.???(io, sensor, .{ io, &queue, .thermometer, 20 });
+- try sensors.???(io, sensor, .{ io, &queue, .hygrometer, 60 });
+- try sensors.???(io, sensor, .{ io, &queue, .anemometer, 10 });
++ try sensors.concurrent(io, sensor, .{ io, &queue, .thermometer, 20 });
++ try sensors.concurrent(io, sensor, .{ io, &queue, .hygrometer, 60 });
++ try sensors.concurrent(io, sensor, .{ io, &queue, .anemometer, 10 });
+
+ // Collector group: processes readings from the queue.
+ var collectors: std.Io.Group = .init;
+@@ -90,7 +90,6 @@
+ // Bug 3: Wait for ALL sensors to finish sending their readings.
+ // What Group method blocks until all tasks complete?
+ try sensors.await(io);
+- // try sensors.???(io);
+
+ // All sensors done — close the queue so the collector knows
+ // there's no more data coming.
+@@ -104,8 +103,8 @@
+ //
+ // Bug 4: Protect this section from cancellation.
+ // What Io method swaps the cancel protection state?
+- const old_protection = io.???(.blocked);
+- defer _ = io.???(old_protection);
++ const old_protection = io.swapCancelProtection(.blocked);
++ defer _ = io.swapCancelProtection(old_protection);
+
+ printGardenReport(&weather);
+ }
+@@ -127,7 +126,7 @@
+
+ // Bug 5: Send the reading into the queue.
+ // What Queue method sends a single element?
+- queue.???(io, reading) catch return;
++ queue.putOne(io, reading) catch return;
+ }
+ }
+