summaryrefslogtreecommitdiff
path: root/exercises/108_labeled_switch.zig
diff options
context:
space:
mode:
authorChris Boesch <chrboesch@noreply.codeberg.org>2024-09-19 10:16:08 +0000
committerChris Boesch <chrboesch@noreply.codeberg.org>2024-09-19 10:16:08 +0000
commit94b5b4bf4bd2cef9adcca401dc75d1b6cd079fb4 (patch)
tree1e97f8c1f0cc1cf96d5deef7e925cddfdc386094 /exercises/108_labeled_switch.zig
parent102ba8c894ebc39e0d61634ad17ca9751984e715 (diff)
parentf0c2c56087bfd4398b896d3a8304a90cddbb3583 (diff)
Merge pull request 'Add a new exercise for a labeled switch' (#161) from nm-remarkable/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/161
Diffstat (limited to 'exercises/108_labeled_switch.zig')
-rw-r--r--exercises/108_labeled_switch.zig77
1 files changed, 77 insertions, 0 deletions
diff --git a/exercises/108_labeled_switch.zig b/exercises/108_labeled_switch.zig
new file mode 100644
index 0000000..0748d9d
--- /dev/null
+++ b/exercises/108_labeled_switch.zig
@@ -0,0 +1,77 @@
+//
+// You've heard of while loops in exercises 011,012,013 and 014
+// You've also heard of switch expressions in exercises 030 and 31.
+// You've also seen how labels can be used in exercise 063.
+//
+// By combining while loops and switch statements with continue and break statements
+// one can create very concise State Machines.
+//
+// One such example would be:
+//
+// pub fn main() void {
+// var op: u8 = 1;
+// while (true) {
+// switch (op) {
+// 1 => { op = 2; continue; },
+// 2 => { op = 3; continue; },
+// 3 => return,
+// 4 => {},
+// }
+// break;
+// }
+// std.debug.print("This statement cannot be reached");
+// }
+//
+// By combining all we've learned so far, we can now proceed with a labeled switch
+//
+// A labeled switch is some extra syntatic sugar, which comes with all sorts of
+// candy (performance benefits). Don't believe me? Directly to source https://github.com/ziglang/zig/pull/21367
+//
+// Here is the previous excerpt implemented as a labeled switch instead:
+//
+// pub fn main() void {
+// foo: switch (@as(u8, 1)) {
+// 1 => continue :foo 2,
+// 2 => continue :foo 3,
+// 3 => return,
+// 4 => {},
+// }
+// std.debug.print("This statement cannot be reached");
+// }
+//
+// The flow of execution on this second case is:
+// 1. The switch starts with value '1';
+// 2. The switch evaluates to case '1' which in turn uses the continue statement
+// to re-evaluate the labeled switch again, now providing the value '2';
+// 3. In the case '2' we repeat the same pattern as case '1'
+// but instead the value to be evaluated is now '3';
+// 4. Finally we get to case '3', where we return from the function as a whole.
+//
+// Since step 4 or a break stament do not exist in this switch, the debug statement is
+// never executed
+//
+const std = @import("std");
+
+const PullRequestState = enum(u8) {
+ Draft,
+ InReview,
+ Approved,
+ Rejected,
+ Merged,
+};
+
+pub fn main() void {
+ // Oh no, your pull request keeps being rejected,
+ // how would you fix it?
+ pr: switch (@as(PullRequestState, PullRequestState.Draft)) {
+ PullRequestState.Draft => continue :pr PullRequestState.InReview,
+ PullRequestState.InReview => continue :pr PullRequestState.Rejected,
+ PullRequestState.Approved => continue :pr PullRequestState.Merged,
+ PullRequestState.Rejected => {
+ std.debug.print("The pull request has been rejected", .{});
+ return;
+ },
+ PullRequestState.Merged => break, // Would you know where to break to?
+ }
+ std.debug.print("The pull request has been merged", .{});
+}