1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::error::Error;
use std::fmt::{Display,Formatter};
use std::fmt::Error as FmtError;
use std::thread::sleep_ms;
#[derive(Debug)]
pub struct RetryError {
message: &'static str
}
impl Display for RetryError {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
write!(formatter, "{}", self.message)
}
}
impl Error for RetryError {
fn description(&self) -> &str {
self.message
}
}
pub fn retry<F, G, R>(
tries: usize,
wait: u32,
mut value_fn: F,
mut condition_fn: G
) -> Result<R, RetryError> where F: FnMut() -> R, G: FnMut(&R) -> bool {
if tries == 0 {
return Err(RetryError { message: "tries must be non-zero" });
}
for _ in 0..tries {
let value = value_fn();
if condition_fn(&value) {
return Ok(value);
}
sleep_ms(wait);
}
Err(RetryError { message: "reached last try without condition match" })
}
#[cfg(test)]
mod tests {
use super::retry;
#[test]
fn succeeds_on_first_try() {
let value = retry(1, 0, || 1, |value| *value == 1).ok().unwrap();
assert_eq!(value, 1);
}
#[test]
fn requires_non_zero_tries() {
let error = retry(0, 0, || 1, |value| *value == 1).err().unwrap();
assert_eq!(error.message, "tries must be non-zero");
}
#[test]
fn succeeds_on_subsequent_try() {
let mut collection = vec![1, 2].into_iter();
let value = retry(2, 0, || collection.next().unwrap(), |value| *value == 2).ok().unwrap();
assert_eq!(value, 2);
}
#[test]
fn fails_after_last_try() {
let mut collection = vec![1].into_iter();
let error = retry(1, 0, || collection.next().unwrap(), |value| *value == 2).err().unwrap();
assert_eq!(error.message, "reached last try without condition match");
}
}