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: u32,
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");
}
}