mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: run rustfmt with custom defined fmt configuration (#1848)
* chore: update rustfmt * chore: apply rustfmt format
This commit is contained in:
@ -2,66 +2,66 @@ use futures_core::future::BoxFuture;
|
||||
use futures_core::ready;
|
||||
use pin_project::pin_project;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
fmt::Debug,
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
pub fn to_fut<T, O>(f: T) -> Fut<O>
|
||||
where
|
||||
T: Future<Output = O> + Send + Sync + 'static,
|
||||
T: Future<Output = O> + Send + Sync + 'static,
|
||||
{
|
||||
Fut { fut: Box::pin(f) }
|
||||
Fut { fut: Box::pin(f) }
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct Fut<T> {
|
||||
#[pin]
|
||||
pub fut: Pin<Box<dyn Future<Output = T> + Sync + Send>>,
|
||||
#[pin]
|
||||
pub fut: Pin<Box<dyn Future<Output = T> + Sync + Send>>,
|
||||
}
|
||||
|
||||
impl<T> Future for Fut<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
T: Send + Sync,
|
||||
{
|
||||
type Output = T;
|
||||
type Output = T;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.as_mut().project();
|
||||
Poll::Ready(ready!(this.fut.poll(cx)))
|
||||
}
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.as_mut().project();
|
||||
Poll::Ready(ready!(this.fut.poll(cx)))
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct FutureResult<T, E> {
|
||||
#[pin]
|
||||
pub fut: Pin<Box<dyn Future<Output = Result<T, E>> + Sync + Send>>,
|
||||
#[pin]
|
||||
pub fut: Pin<Box<dyn Future<Output = Result<T, E>> + Sync + Send>>,
|
||||
}
|
||||
|
||||
impl<T, E> FutureResult<T, E> {
|
||||
pub fn new<F>(f: F) -> Self
|
||||
where
|
||||
F: Future<Output = Result<T, E>> + Send + Sync + 'static,
|
||||
{
|
||||
Self {
|
||||
fut: Box::pin(async { f.await }),
|
||||
}
|
||||
pub fn new<F>(f: F) -> Self
|
||||
where
|
||||
F: Future<Output = Result<T, E>> + Send + Sync + 'static,
|
||||
{
|
||||
Self {
|
||||
fut: Box::pin(async { f.await }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Future for FutureResult<T, E>
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Debug,
|
||||
T: Send + Sync,
|
||||
E: Debug,
|
||||
{
|
||||
type Output = Result<T, E>;
|
||||
type Output = Result<T, E>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.as_mut().project();
|
||||
let result = ready!(this.fut.poll(cx));
|
||||
Poll::Ready(result)
|
||||
}
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.as_mut().project();
|
||||
let result = ready!(this.fut.poll(cx));
|
||||
Poll::Ready(result)
|
||||
}
|
||||
}
|
||||
|
||||
pub type BoxResultFuture<'a, T, E> = BoxFuture<'a, Result<T, E>>;
|
||||
|
@ -4,82 +4,89 @@ use std::sync::Arc;
|
||||
|
||||
#[async_trait]
|
||||
pub trait RefCountValue {
|
||||
async fn did_remove(&self) {}
|
||||
async fn did_remove(&self) {}
|
||||
}
|
||||
|
||||
struct RefCountHandler<T> {
|
||||
ref_count: usize,
|
||||
inner: T,
|
||||
ref_count: usize,
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T> RefCountHandler<T> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self { ref_count: 1, inner }
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self {
|
||||
ref_count: 1,
|
||||
inner,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increase_ref_count(&mut self) {
|
||||
self.ref_count += 1;
|
||||
}
|
||||
pub fn increase_ref_count(&mut self) {
|
||||
self.ref_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RefCountHashMap<T>(HashMap<String, RefCountHandler<T>>);
|
||||
|
||||
impl<T> std::default::Default for RefCountHashMap<T> {
|
||||
fn default() -> Self {
|
||||
Self(HashMap::new())
|
||||
}
|
||||
fn default() -> Self {
|
||||
Self(HashMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RefCountHashMap<T>
|
||||
where
|
||||
T: Clone + Send + Sync + RefCountValue + 'static,
|
||||
T: Clone + Send + Sync + RefCountValue + 'static,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &str) -> Option<T> {
|
||||
self.0.get(key).map(|handler| handler.inner.clone())
|
||||
}
|
||||
|
||||
pub fn values(&self) -> Vec<T> {
|
||||
self
|
||||
.0
|
||||
.values()
|
||||
.map(|value| value.inner.clone())
|
||||
.collect::<Vec<T>>()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: String, value: T) {
|
||||
if let Some(handler) = self.0.get_mut(&key) {
|
||||
handler.increase_ref_count();
|
||||
} else {
|
||||
let handler = RefCountHandler::new(value);
|
||||
self.0.insert(key, handler);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn remove(&mut self, key: &str) {
|
||||
let mut should_remove = false;
|
||||
if let Some(value) = self.0.get_mut(key) {
|
||||
if value.ref_count > 0 {
|
||||
value.ref_count -= 1;
|
||||
}
|
||||
should_remove = value.ref_count == 0;
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &str) -> Option<T> {
|
||||
self.0.get(key).map(|handler| handler.inner.clone())
|
||||
}
|
||||
|
||||
pub fn values(&self) -> Vec<T> {
|
||||
self.0.values().map(|value| value.inner.clone()).collect::<Vec<T>>()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: String, value: T) {
|
||||
if let Some(handler) = self.0.get_mut(&key) {
|
||||
handler.increase_ref_count();
|
||||
} else {
|
||||
let handler = RefCountHandler::new(value);
|
||||
self.0.insert(key, handler);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn remove(&mut self, key: &str) {
|
||||
let mut should_remove = false;
|
||||
if let Some(value) = self.0.get_mut(key) {
|
||||
if value.ref_count > 0 {
|
||||
value.ref_count -= 1;
|
||||
}
|
||||
should_remove = value.ref_count == 0;
|
||||
}
|
||||
|
||||
if should_remove {
|
||||
if let Some(handler) = self.0.remove(key) {
|
||||
tokio::spawn(async move {
|
||||
handler.inner.did_remove().await;
|
||||
});
|
||||
}
|
||||
}
|
||||
if should_remove {
|
||||
if let Some(handler) = self.0.remove(key) {
|
||||
tokio::spawn(async move {
|
||||
handler.inner.did_remove().await;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> RefCountValue for Arc<T>
|
||||
where
|
||||
T: RefCountValue + Sync + Send,
|
||||
T: RefCountValue + Sync + Send,
|
||||
{
|
||||
async fn did_remove(&self) {
|
||||
(**self).did_remove().await
|
||||
}
|
||||
async fn did_remove(&self) {
|
||||
(**self).did_remove().await
|
||||
}
|
||||
}
|
||||
|
@ -3,73 +3,76 @@
|
||||
use crate::retry::FixedInterval;
|
||||
use pin_project::pin_project;
|
||||
use std::{
|
||||
future::Future,
|
||||
iter::{IntoIterator, Iterator},
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
future::Future,
|
||||
iter::{IntoIterator, Iterator},
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use tokio::time::{sleep_until, Duration, Instant, Sleep};
|
||||
|
||||
#[pin_project(project = RetryStateProj)]
|
||||
enum RetryState<A>
|
||||
where
|
||||
A: Action,
|
||||
A: Action,
|
||||
{
|
||||
Running(#[pin] A::Future),
|
||||
Sleeping(#[pin] Sleep),
|
||||
Running(#[pin] A::Future),
|
||||
Sleeping(#[pin] Sleep),
|
||||
}
|
||||
|
||||
impl<A: Action> RetryState<A> {
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> RetryFuturePoll<A> {
|
||||
match self.project() {
|
||||
RetryStateProj::Running(future) => RetryFuturePoll::Running(future.poll(cx)),
|
||||
RetryStateProj::Sleeping(future) => RetryFuturePoll::Sleeping(future.poll(cx)),
|
||||
}
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> RetryFuturePoll<A> {
|
||||
match self.project() {
|
||||
RetryStateProj::Running(future) => RetryFuturePoll::Running(future.poll(cx)),
|
||||
RetryStateProj::Sleeping(future) => RetryFuturePoll::Sleeping(future.poll(cx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum RetryFuturePoll<A>
|
||||
where
|
||||
A: Action,
|
||||
A: Action,
|
||||
{
|
||||
Running(Poll<Result<A::Item, A::Error>>),
|
||||
Sleeping(Poll<()>),
|
||||
Running(Poll<Result<A::Item, A::Error>>),
|
||||
Sleeping(Poll<()>),
|
||||
}
|
||||
|
||||
/// Future that drives multiple attempts at an action via a retry strategy.
|
||||
#[pin_project]
|
||||
pub struct Retry<I, A>
|
||||
where
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
{
|
||||
#[pin]
|
||||
retry_if: RetryIf<I, A, fn(&A::Error) -> bool>,
|
||||
#[pin]
|
||||
retry_if: RetryIf<I, A, fn(&A::Error) -> bool>,
|
||||
}
|
||||
|
||||
impl<I, A> Retry<I, A>
|
||||
where
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
{
|
||||
pub fn new<T: IntoIterator<IntoIter = I, Item = Duration>>(strategy: T, action: A) -> Retry<I, A> {
|
||||
Retry {
|
||||
retry_if: RetryIf::spawn(strategy, action, (|_| true) as fn(&A::Error) -> bool),
|
||||
}
|
||||
pub fn new<T: IntoIterator<IntoIter = I, Item = Duration>>(
|
||||
strategy: T,
|
||||
action: A,
|
||||
) -> Retry<I, A> {
|
||||
Retry {
|
||||
retry_if: RetryIf::spawn(strategy, action, (|_| true) as fn(&A::Error) -> bool),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, A> Future for Retry<I, A>
|
||||
where
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
{
|
||||
type Output = Result<A::Item, A::Error>;
|
||||
type Output = Result<A::Item, A::Error>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
this.retry_if.poll(cx)
|
||||
}
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
this.retry_if.poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
/// Future that drives multiple attempts at an action via a retry strategy.
|
||||
@ -78,101 +81,109 @@ where
|
||||
#[pin_project]
|
||||
pub struct RetryIf<I, A, C>
|
||||
where
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
C: Condition<A::Error>,
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
C: Condition<A::Error>,
|
||||
{
|
||||
strategy: I,
|
||||
#[pin]
|
||||
state: RetryState<A>,
|
||||
action: A,
|
||||
condition: C,
|
||||
strategy: I,
|
||||
#[pin]
|
||||
state: RetryState<A>,
|
||||
action: A,
|
||||
condition: C,
|
||||
}
|
||||
|
||||
impl<I, A, C> RetryIf<I, A, C>
|
||||
where
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
C: Condition<A::Error>,
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
C: Condition<A::Error>,
|
||||
{
|
||||
pub fn spawn<T: IntoIterator<IntoIter = I, Item = Duration>>(
|
||||
strategy: T,
|
||||
mut action: A,
|
||||
condition: C,
|
||||
) -> RetryIf<I, A, C> {
|
||||
RetryIf {
|
||||
strategy: strategy.into_iter(),
|
||||
state: RetryState::Running(action.run()),
|
||||
action,
|
||||
condition,
|
||||
}
|
||||
pub fn spawn<T: IntoIterator<IntoIter = I, Item = Duration>>(
|
||||
strategy: T,
|
||||
mut action: A,
|
||||
condition: C,
|
||||
) -> RetryIf<I, A, C> {
|
||||
RetryIf {
|
||||
strategy: strategy.into_iter(),
|
||||
state: RetryState::Running(action.run()),
|
||||
action,
|
||||
condition,
|
||||
}
|
||||
}
|
||||
|
||||
fn attempt(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<A::Item, A::Error>> {
|
||||
let future = {
|
||||
let this = self.as_mut().project();
|
||||
this.action.run()
|
||||
};
|
||||
self.as_mut().project().state.set(RetryState::Running(future));
|
||||
self.poll(cx)
|
||||
}
|
||||
fn attempt(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<A::Item, A::Error>> {
|
||||
let future = {
|
||||
let this = self.as_mut().project();
|
||||
this.action.run()
|
||||
};
|
||||
self
|
||||
.as_mut()
|
||||
.project()
|
||||
.state
|
||||
.set(RetryState::Running(future));
|
||||
self.poll(cx)
|
||||
}
|
||||
|
||||
fn retry(
|
||||
mut self: Pin<&mut Self>,
|
||||
err: A::Error,
|
||||
cx: &mut Context,
|
||||
) -> Result<Poll<Result<A::Item, A::Error>>, A::Error> {
|
||||
match self.as_mut().project().strategy.next() {
|
||||
None => Err(err),
|
||||
Some(duration) => {
|
||||
let deadline = Instant::now() + duration;
|
||||
let future = sleep_until(deadline);
|
||||
self.as_mut().project().state.set(RetryState::Sleeping(future));
|
||||
Ok(self.poll(cx))
|
||||
}
|
||||
}
|
||||
fn retry(
|
||||
mut self: Pin<&mut Self>,
|
||||
err: A::Error,
|
||||
cx: &mut Context,
|
||||
) -> Result<Poll<Result<A::Item, A::Error>>, A::Error> {
|
||||
match self.as_mut().project().strategy.next() {
|
||||
None => Err(err),
|
||||
Some(duration) => {
|
||||
let deadline = Instant::now() + duration;
|
||||
let future = sleep_until(deadline);
|
||||
self
|
||||
.as_mut()
|
||||
.project()
|
||||
.state
|
||||
.set(RetryState::Sleeping(future));
|
||||
Ok(self.poll(cx))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, A, C> Future for RetryIf<I, A, C>
|
||||
where
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
C: Condition<A::Error>,
|
||||
I: Iterator<Item = Duration>,
|
||||
A: Action,
|
||||
C: Condition<A::Error>,
|
||||
{
|
||||
type Output = Result<A::Item, A::Error>;
|
||||
type Output = Result<A::Item, A::Error>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
match self.as_mut().project().state.poll(cx) {
|
||||
RetryFuturePoll::Running(poll_result) => match poll_result {
|
||||
Poll::Ready(Ok(ok)) => Poll::Ready(Ok(ok)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Err(err)) => {
|
||||
if self.as_mut().project().condition.should_retry(&err) {
|
||||
match self.retry(err, cx) {
|
||||
Ok(poll) => poll,
|
||||
Err(err) => Poll::Ready(Err(err)),
|
||||
}
|
||||
} else {
|
||||
Poll::Ready(Err(err))
|
||||
}
|
||||
}
|
||||
},
|
||||
RetryFuturePoll::Sleeping(poll_result) => match poll_result {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(_) => self.attempt(cx),
|
||||
},
|
||||
}
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
match self.as_mut().project().state.poll(cx) {
|
||||
RetryFuturePoll::Running(poll_result) => match poll_result {
|
||||
Poll::Ready(Ok(ok)) => Poll::Ready(Ok(ok)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Err(err)) => {
|
||||
if self.as_mut().project().condition.should_retry(&err) {
|
||||
match self.retry(err, cx) {
|
||||
Ok(poll) => poll,
|
||||
Err(err) => Poll::Ready(Err(err)),
|
||||
}
|
||||
} else {
|
||||
Poll::Ready(Err(err))
|
||||
}
|
||||
},
|
||||
},
|
||||
RetryFuturePoll::Sleeping(poll_result) => match poll_result {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(_) => self.attempt(cx),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An action can be run multiple times and produces a future.
|
||||
pub trait Action: Send + Sync {
|
||||
type Future: Future<Output = Result<Self::Item, Self::Error>>;
|
||||
type Item;
|
||||
type Error;
|
||||
type Future: Future<Output = Result<Self::Item, Self::Error>>;
|
||||
type Item;
|
||||
type Error;
|
||||
|
||||
fn run(&mut self) -> Self::Future;
|
||||
fn run(&mut self) -> Self::Future;
|
||||
}
|
||||
// impl<R, E, T: Future<Output = Result<R, E>>, F: FnMut() -> T + Send + Sync>
|
||||
// Action for F { type Future = T;
|
||||
@ -183,25 +194,25 @@ pub trait Action: Send + Sync {
|
||||
// }
|
||||
|
||||
pub trait Condition<E> {
|
||||
fn should_retry(&mut self, error: &E) -> bool;
|
||||
fn should_retry(&mut self, error: &E) -> bool;
|
||||
}
|
||||
|
||||
impl<E, F: FnMut(&E) -> bool> Condition<E> for F {
|
||||
fn should_retry(&mut self, error: &E) -> bool {
|
||||
self(error)
|
||||
}
|
||||
fn should_retry(&mut self, error: &E) -> bool {
|
||||
self(error)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_retry<A: Action + 'static>(
|
||||
retry_count: usize,
|
||||
retry_per_millis: u64,
|
||||
action: A,
|
||||
retry_count: usize,
|
||||
retry_per_millis: u64,
|
||||
action: A,
|
||||
) -> impl Future<Output = Result<A::Item, A::Error>>
|
||||
where
|
||||
A::Item: Send + Sync,
|
||||
A::Error: Send + Sync,
|
||||
<A as Action>::Future: Send + Sync,
|
||||
A::Item: Send + Sync,
|
||||
A::Error: Send + Sync,
|
||||
<A as Action>::Future: Send + Sync,
|
||||
{
|
||||
let strategy = FixedInterval::from_millis(retry_per_millis).take(retry_count);
|
||||
Retry::new(strategy, action)
|
||||
let strategy = FixedInterval::from_millis(retry_per_millis).take(retry_count);
|
||||
Retry::new(strategy, action)
|
||||
}
|
||||
|
@ -4,124 +4,124 @@ use std::{iter::Iterator, time::Duration};
|
||||
/// The power corresponds to the number of past attempts.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExponentialBackoff {
|
||||
current: u64,
|
||||
base: u64,
|
||||
factor: u64,
|
||||
max_delay: Option<Duration>,
|
||||
current: u64,
|
||||
base: u64,
|
||||
factor: u64,
|
||||
max_delay: Option<Duration>,
|
||||
}
|
||||
|
||||
impl ExponentialBackoff {
|
||||
/// Constructs a new exponential back-off strategy,
|
||||
/// given a base duration in milliseconds.
|
||||
///
|
||||
/// The resulting duration is calculated by taking the base to the `n`-th
|
||||
/// power, where `n` denotes the number of past attempts.
|
||||
pub fn from_millis(base: u64) -> ExponentialBackoff {
|
||||
ExponentialBackoff {
|
||||
current: base,
|
||||
base,
|
||||
factor: 1u64,
|
||||
max_delay: None,
|
||||
}
|
||||
/// Constructs a new exponential back-off strategy,
|
||||
/// given a base duration in milliseconds.
|
||||
///
|
||||
/// The resulting duration is calculated by taking the base to the `n`-th
|
||||
/// power, where `n` denotes the number of past attempts.
|
||||
pub fn from_millis(base: u64) -> ExponentialBackoff {
|
||||
ExponentialBackoff {
|
||||
current: base,
|
||||
base,
|
||||
factor: 1u64,
|
||||
max_delay: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A multiplicative factor that will be applied to the retry delay.
|
||||
///
|
||||
/// For example, using a factor of `1000` will make each delay in units of
|
||||
/// seconds.
|
||||
///
|
||||
/// Default factor is `1`.
|
||||
pub fn factor(mut self, factor: u64) -> ExponentialBackoff {
|
||||
self.factor = factor;
|
||||
self
|
||||
}
|
||||
/// A multiplicative factor that will be applied to the retry delay.
|
||||
///
|
||||
/// For example, using a factor of `1000` will make each delay in units of
|
||||
/// seconds.
|
||||
///
|
||||
/// Default factor is `1`.
|
||||
pub fn factor(mut self, factor: u64) -> ExponentialBackoff {
|
||||
self.factor = factor;
|
||||
self
|
||||
}
|
||||
|
||||
/// Apply a maximum delay. No retry delay will be longer than this
|
||||
/// `Duration`.
|
||||
pub fn max_delay(mut self, duration: Duration) -> ExponentialBackoff {
|
||||
self.max_delay = Some(duration);
|
||||
self
|
||||
}
|
||||
/// Apply a maximum delay. No retry delay will be longer than this
|
||||
/// `Duration`.
|
||||
pub fn max_delay(mut self, duration: Duration) -> ExponentialBackoff {
|
||||
self.max_delay = Some(duration);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ExponentialBackoff {
|
||||
type Item = Duration;
|
||||
type Item = Duration;
|
||||
|
||||
fn next(&mut self) -> Option<Duration> {
|
||||
// set delay duration by applying factor
|
||||
let duration = if let Some(duration) = self.current.checked_mul(self.factor) {
|
||||
Duration::from_millis(duration)
|
||||
} else {
|
||||
Duration::from_millis(u64::MAX)
|
||||
};
|
||||
fn next(&mut self) -> Option<Duration> {
|
||||
// set delay duration by applying factor
|
||||
let duration = if let Some(duration) = self.current.checked_mul(self.factor) {
|
||||
Duration::from_millis(duration)
|
||||
} else {
|
||||
Duration::from_millis(u64::MAX)
|
||||
};
|
||||
|
||||
// check if we reached max delay
|
||||
if let Some(ref max_delay) = self.max_delay {
|
||||
if duration > *max_delay {
|
||||
return Some(*max_delay);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(next) = self.current.checked_mul(self.base) {
|
||||
self.current = next;
|
||||
} else {
|
||||
self.current = u64::MAX;
|
||||
}
|
||||
|
||||
Some(duration)
|
||||
// check if we reached max delay
|
||||
if let Some(ref max_delay) = self.max_delay {
|
||||
if duration > *max_delay {
|
||||
return Some(*max_delay);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(next) = self.current.checked_mul(self.base) {
|
||||
self.current = next;
|
||||
} else {
|
||||
self.current = u64::MAX;
|
||||
}
|
||||
|
||||
Some(duration)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_some_exponential_base_10() {
|
||||
let mut s = ExponentialBackoff::from_millis(10);
|
||||
let mut s = ExponentialBackoff::from_millis(10);
|
||||
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(10)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(100)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(1000)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(10)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(100)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(1000)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_some_exponential_base_2() {
|
||||
let mut s = ExponentialBackoff::from_millis(2);
|
||||
let mut s = ExponentialBackoff::from_millis(2);
|
||||
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(2)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(4)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(8)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(2)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(4)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(8)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn saturates_at_maximum_value() {
|
||||
let mut s = ExponentialBackoff::from_millis(u64::MAX - 1);
|
||||
let mut s = ExponentialBackoff::from_millis(u64::MAX - 1);
|
||||
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(u64::MAX - 1)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(u64::MAX)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(u64::MAX)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(u64::MAX - 1)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(u64::MAX)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(u64::MAX)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_use_factor_to_get_seconds() {
|
||||
let factor = 1000;
|
||||
let mut s = ExponentialBackoff::from_millis(2).factor(factor);
|
||||
let factor = 1000;
|
||||
let mut s = ExponentialBackoff::from_millis(2).factor(factor);
|
||||
|
||||
assert_eq!(s.next(), Some(Duration::from_secs(2)));
|
||||
assert_eq!(s.next(), Some(Duration::from_secs(4)));
|
||||
assert_eq!(s.next(), Some(Duration::from_secs(8)));
|
||||
assert_eq!(s.next(), Some(Duration::from_secs(2)));
|
||||
assert_eq!(s.next(), Some(Duration::from_secs(4)));
|
||||
assert_eq!(s.next(), Some(Duration::from_secs(8)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stops_increasing_at_max_delay() {
|
||||
let mut s = ExponentialBackoff::from_millis(2).max_delay(Duration::from_millis(4));
|
||||
let mut s = ExponentialBackoff::from_millis(2).max_delay(Duration::from_millis(4));
|
||||
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(2)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(4)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(4)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(2)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(4)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(4)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_max_when_max_less_than_base() {
|
||||
let mut s = ExponentialBackoff::from_millis(20).max_delay(Duration::from_millis(10));
|
||||
let mut s = ExponentialBackoff::from_millis(20).max_delay(Duration::from_millis(10));
|
||||
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(10)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(10)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(10)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(10)));
|
||||
}
|
||||
|
@ -3,37 +3,37 @@ use std::{iter::Iterator, time::Duration};
|
||||
/// A retry strategy driven by a fixed interval.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FixedInterval {
|
||||
duration: Duration,
|
||||
duration: Duration,
|
||||
}
|
||||
|
||||
impl FixedInterval {
|
||||
/// Constructs a new fixed interval strategy.
|
||||
pub fn new(duration: Duration) -> FixedInterval {
|
||||
FixedInterval { duration }
|
||||
}
|
||||
/// Constructs a new fixed interval strategy.
|
||||
pub fn new(duration: Duration) -> FixedInterval {
|
||||
FixedInterval { duration }
|
||||
}
|
||||
|
||||
/// Constructs a new fixed interval strategy,
|
||||
/// given a duration in milliseconds.
|
||||
pub fn from_millis(millis: u64) -> FixedInterval {
|
||||
FixedInterval {
|
||||
duration: Duration::from_millis(millis),
|
||||
}
|
||||
/// Constructs a new fixed interval strategy,
|
||||
/// given a duration in milliseconds.
|
||||
pub fn from_millis(millis: u64) -> FixedInterval {
|
||||
FixedInterval {
|
||||
duration: Duration::from_millis(millis),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for FixedInterval {
|
||||
type Item = Duration;
|
||||
type Item = Duration;
|
||||
|
||||
fn next(&mut self) -> Option<Duration> {
|
||||
Some(self.duration)
|
||||
}
|
||||
fn next(&mut self) -> Option<Duration> {
|
||||
Some(self.duration)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_some_fixed() {
|
||||
let mut s = FixedInterval::new(Duration::from_millis(123));
|
||||
let mut s = FixedInterval::new(Duration::from_millis(123));
|
||||
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(123)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(123)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(123)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(123)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(123)));
|
||||
assert_eq!(s.next(), Some(Duration::from_millis(123)));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::time::Duration;
|
||||
|
||||
pub fn jitter(duration: Duration) -> Duration {
|
||||
duration.mul_f64(rand::random::<f64>())
|
||||
duration.mul_f64(rand::random::<f64>())
|
||||
}
|
||||
|
@ -1,33 +1,38 @@
|
||||
pub fn move_vec_element<T, F>(vec: &mut Vec<T>, filter: F, _from_index: usize, to_index: usize) -> Result<bool, String>
|
||||
pub fn move_vec_element<T, F>(
|
||||
vec: &mut Vec<T>,
|
||||
filter: F,
|
||||
_from_index: usize,
|
||||
to_index: usize,
|
||||
) -> Result<bool, String>
|
||||
where
|
||||
F: FnMut(&T) -> bool,
|
||||
F: FnMut(&T) -> bool,
|
||||
{
|
||||
match vec.iter().position(filter) {
|
||||
None => Ok(false),
|
||||
Some(index) => {
|
||||
if vec.len() > to_index {
|
||||
let removed_element = vec.remove(index);
|
||||
vec.insert(to_index, removed_element);
|
||||
Ok(true)
|
||||
} else {
|
||||
let msg = format!(
|
||||
"Move element to invalid index: {}, current len: {}",
|
||||
to_index,
|
||||
vec.len()
|
||||
);
|
||||
Err(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
match vec.iter().position(filter) {
|
||||
None => Ok(false),
|
||||
Some(index) => {
|
||||
if vec.len() > to_index {
|
||||
let removed_element = vec.remove(index);
|
||||
vec.insert(to_index, removed_element);
|
||||
Ok(true)
|
||||
} else {
|
||||
let msg = format!(
|
||||
"Move element to invalid index: {}, current len: {}",
|
||||
to_index,
|
||||
vec.len()
|
||||
);
|
||||
Err(msg)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn timestamp() -> i64 {
|
||||
chrono::Utc::now().timestamp()
|
||||
chrono::Utc::now().timestamp()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn md5<T: AsRef<[u8]>>(data: T) -> String {
|
||||
let md5 = format!("{:x}", md5::compute(data));
|
||||
md5
|
||||
let md5 = format!("{:x}", md5::compute(data));
|
||||
md5
|
||||
}
|
||||
|
Reference in New Issue
Block a user