loop_guard/
lib.rs

1/// Utility for preventing infinite loops
2///
3/// Use as a guard rail inside a loop block
4pub struct LoopGuard {
5    max_ticks: i32,
6    count: i32,
7    message: String,
8}
9
10impl LoopGuard {
11    /// # Create a new LoopGuard
12    /// Make sure to create the LoopGuard instance **outside** the loop block
13    ///
14    /// ## Arguments
15    /// * `max_ticks` - The limit of how many times a loop should run
16    ///
17    /// ```should_panic
18    /// use loop_guard::LoopGuard;
19    ///
20    /// let mut guard = LoopGuard::new(10);
21    ///
22    /// loop {
23    ///     guard.protect() // This will panic after 10 loops
24    /// }
25    /// ```
26    pub fn new(max: i32) -> LoopGuard {
27        LoopGuard {
28            max_ticks: max,
29            count: 0,
30            message: String::from("Max number of ticks reached"),
31        }
32    }
33
34    /// Set a custom panic message for a LoopGuard instance
35    pub fn set_panic_message(mut self, message: &str) -> Self {
36        self.message = String::from(message);
37        self
38    }
39
40    /// From within a `while` or `loop` block, panic if the loop iteration
41    /// surpasses the LoopGuard's `max_ticks` value.
42    pub fn protect(&mut self) {
43        self.count += 1;
44        if self.count > self.max_ticks {
45            panic!("{}", self.message);
46        }
47    }
48}
49
50#[test]
51#[should_panic(expected = "Max number of ticks reached")]
52fn infinite_loop_with_guard() {
53    // Arrange
54    let mut guard = LoopGuard::new(1000);
55
56    // Act
57    loop {
58        // Infinite loop - should obviously panic
59        guard.protect();
60    }
61}
62
63#[test]
64#[should_panic(expected = "Infinite Loop 2: Electric Boogaloo")]
65fn infinite_loop_with_guard_with_custom_message() {
66    // Arrange
67    let mut guard = LoopGuard::new(10).set_panic_message("Infinite Loop 2: Electric Boogaloo");
68
69    // Act
70    loop {
71        guard.protect();
72    }
73}
74
75#[test]
76#[should_panic(expected = "Max number of ticks reached")]
77fn for_loop_surpasses_max_ticks() {
78    // Arrange
79    let mut guard = LoopGuard::new(10);
80
81    // Act
82    for _i in 0..11 {
83        guard.protect();
84    }
85}
86
87#[test]
88fn for_loop_does_not_surpass_max_ticks() {
89    // Arrange
90    let mut guard = LoopGuard::new(10);
91
92    // Act - Does not panic, since loop is within 10 ticks
93    for _i in 0..10 {
94        guard.protect();
95    }
96}