Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Enable default features to avoid unexpected panic #132

Merged
merged 1 commit into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion backon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ targets = [
]

[features]
default = ["tokio-sleep", "gloo-timers-sleep"]
gloo-timers-sleep = ["dep:gloo-timers", "gloo-timers?/futures"]
tokio-sleep = ["dep:tokio", "tokio?/time"]

[dependencies]
fastrand = "2.0.0"
fastrand = "2"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1", optional = true }
Expand Down
11 changes: 7 additions & 4 deletions backon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
//!
//! Retry in BackON requires an implementation for sleeping. BackON will accept a [`Sleeper`] to pause for a specified duration.
//!
//! BackON offers the following features for users to choose from:
//! BackON employs the following default sleep implementations:
//!
//! - `tokio-sleep`: Use [`TokioSleeper`] within a Tokio context.
//! - `gloo-timers-sleep`: Use [`GlooTimersSleep`] to pause in a wasm32 environment.
//! - `tokio-sleep`: Utilizes [`TokioSleeper`] within a Tokio context in non-wasm32 environments.
//! - `gloo-timers-sleep`: Utilizes [`GlooTimersSleep`] to pause in wasm32 environments.
//!
//! Users MUST provide a custom implementation if they prefer not to use the default options.
//! Users CAN provide a custom implementation if they prefer not to use the default options.
//!
//! If neither feature is enabled nor a custom implementation is provided, BackON will fallback to an empty sleeper. This will cause a panic in the `debug` profile and do nothing in the `release` profile.
//!
//! # Retry
//!
Expand Down Expand Up @@ -123,6 +125,7 @@ mod sleep;
pub use sleep::DefaultSleeper;
#[cfg(all(target_arch = "wasm32", feature = "gloo-timers-sleep"))]
pub use sleep::GlooTimersSleep;
pub(crate) use sleep::NoopSleeper;
pub use sleep::Sleeper;
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio-sleep"))]
pub use sleep::TokioSleeper;
Expand Down
5 changes: 5 additions & 0 deletions backon/src/retry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,11 @@ where
type Output = Result<T, E>;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
#[cfg(debug_assertions)]
if std::any::TypeId::of::<SF>() == std::any::TypeId::of::<crate::NoopSleeper>() {
panic!("BackON: No sleeper has been configured. Please enable the features or provide a custom implementation.")
}

// Safety: This is safe because we don't move the `Retry` struct itself,
// only its internal state.
//
Expand Down
5 changes: 5 additions & 0 deletions backon/src/retry_with_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,11 @@ where
type Output = (Ctx, Result<T, E>);

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
#[cfg(debug_assertions)]
if std::any::TypeId::of::<SF>() == std::any::TypeId::of::<crate::NoopSleeper>() {
panic!("BackON: No sleeper has been configured. Please enable the features or provide a custom implementation.")
}

// Safety: This is safe because we don't move the `Retry` struct itself,
// only its internal state.
//
Expand Down
26 changes: 14 additions & 12 deletions backon/src/sleep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,42 @@ use std::{
};

/// A sleeper is used to generate a future that completes after a specified duration.
pub trait Sleeper {
pub trait Sleeper: 'static {
/// The future returned by the `sleep` method.
type Sleep: Future<Output = ()>;

/// Create a future that completes after a set period.
fn sleep(&self, dur: Duration) -> Self::Sleep;
}

/// The default implementation of `Sleeper`.
/// The default implementation of `Sleeper` is a no-op when no features are enabled.
///
/// - Under `tokio-sleep` feature, it uses `tokio::time::sleep`.
/// - Under `gloo-timers-sleep` feature, it uses `gloo_timers::sleep::sleep`.
/// It will panic on `debug` profile and do nothing on `release` profile.
#[cfg(all(not(feature = "tokio-sleep"), not(feature = "gloo-timers-sleep")))]
pub type DefaultSleeper = ();
/// The default implementation of `Sleeper` based on enabled feature flag.
pub type DefaultSleeper = NoopSleeper;
/// The default implementation of `Sleeper` while feature `tokio-sleep` enabled.
///
/// Under `tokio-sleep` feature, it uses `tokio::time::sleep`.
/// it uses `tokio::time::sleep`.
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio-sleep"))]
pub type DefaultSleeper = TokioSleeper;
/// The default implementation of `Sleeper` based on enabled feature flag.
/// The default implementation of `Sleeper` while feature `gloo-timers-sleep` enabled.
///
/// Under `gloo-timers-sleep` feature, it uses `gloo_timers::sleep::sleep`.
/// It uses `gloo_timers::sleep::sleep`.
#[cfg(all(target_arch = "wasm32", feature = "gloo-timers-sleep"))]
pub type DefaultSleeper = GlooTimersSleep;

impl Sleeper for () {
/// The no-op implementation of `Sleeper` that does nothing.
pub struct NoopSleeper;

impl Sleeper for NoopSleeper {
type Sleep = Ready<()>;

fn sleep(&self, _: Duration) -> Self::Sleep {
panic!("no sleeper has been configured, consider enabling features or provide a custom implementation")
std::future::ready(())
}
}

impl<F: Fn(Duration) -> Fut, Fut: Future<Output = ()>> Sleeper for F {
impl<F: Fn(Duration) -> Fut + 'static, Fut: Future<Output = ()>> Sleeper for F {
type Sleep = Fut;

fn sleep(&self, dur: Duration) -> Self::Sleep {
Expand Down