diff --git a/src/delay.rs b/src/delay.rs index fbf4c82..03b786d 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -14,16 +14,24 @@ use rand::{ /// Each retry increases the delay since the last exponentially. #[derive(Debug)] pub struct Exponential { - base: u64, current: u64, + factor: f64, } impl Exponential { /// Create a new `Exponential` using the given millisecond duration as the initial delay. pub fn from_millis(base: u64) -> Self { Exponential { - base, current: base, + factor: base as f64, + } + } + + /// Create a new `Exponential` using the given millisecond duration as the initial delay and a variable multiplication factor. + pub fn from_millis_with_factor(base: u64, factor: f64) -> Self { + Exponential { + current: base, + factor, } } } @@ -34,11 +42,12 @@ impl Iterator for Exponential { fn next(&mut self) -> Option { let duration = Duration::from_millis(self.current); - if let Some(next) = self.current.checked_mul(self.base) { - self.current = next; + let next = (self.current as f64) * self.factor; + self.current = if next > (U64_MAX as f64) { + U64_MAX } else { - self.current = U64_MAX; - } + next as u64 + }; Some(duration) } @@ -50,6 +59,24 @@ impl From for Exponential { } } +#[test] +fn exponential_with_factor() { + let mut iter = Exponential::from_millis_with_factor(1000, 2.0); + assert_eq!(iter.next(), Some(Duration::from_millis(1000))); + assert_eq!(iter.next(), Some(Duration::from_millis(2000))); + assert_eq!(iter.next(), Some(Duration::from_millis(4000))); + assert_eq!(iter.next(), Some(Duration::from_millis(8000))); + assert_eq!(iter.next(), Some(Duration::from_millis(16000))); + assert_eq!(iter.next(), Some(Duration::from_millis(32000))); +} + +#[test] +fn exponential_overflow() { + let mut iter = Exponential::from_millis(U64_MAX); + assert_eq!(iter.next(), Some(Duration::from_millis(U64_MAX))); + assert_eq!(iter.next(), Some(Duration::from_millis(U64_MAX))); +} + /// Each retry uses a delay which is the sum of the two previous delays. /// /// Depending on the problem at hand, a fibonacci delay strategy might diff --git a/src/lib.rs b/src/lib.rs index d7cddb3..d5f313a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -203,6 +203,7 @@ impl Display for Error where E: StdError, { + #[allow(deprecated)] fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> { write!(formatter, "{}", self.description()) } @@ -212,6 +213,7 @@ impl StdError for Error where E: StdError, { + #[allow(deprecated)] fn description(&self) -> &str { match *self { Error::Operation { ref error, .. } => error.description(), @@ -339,6 +341,23 @@ mod tests { assert_eq!(value, 2); } + #[test] + fn succeeds_with_exponential_delay_with_factor() { + let mut collection = vec![1, 2].into_iter(); + + let value = retry( + Exponential::from_millis_with_factor(1000, 2.0), + || match collection.next() { + Some(n) if n == 2 => Ok(n), + Some(_) => Err("not 2"), + None => Err("not 2"), + }, + ) + .unwrap(); + + assert_eq!(value, 2); + } + #[test] fn succeeds_with_ranged_delay() { let mut collection = vec![1, 2].into_iter();