use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; #[cfg(any(test, feature = "test-support"))] use std::time::Duration; #[cfg(any(test, feature = "test-support"))] use futures::Future; #[cfg(any(test, feature = "test-support"))] use smol::future::FutureExt; pub use util::*; /// A helper trait for building complex objects with imperative conditionals in a fluent style. pub trait FluentBuilder { /// Imperatively modify self with the given closure. fn map(self, f: impl FnOnce(Self) -> U) -> U where Self: Sized, { f(self) } /// Conditionally modify self with the given closure. fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self where Self: Sized, { self.map(|this| if condition { then(this) } else { this }) } /// Conditionally modify self with the given closure. fn when_else( self, condition: bool, then: impl FnOnce(Self) -> Self, else_fn: impl FnOnce(Self) -> Self, ) -> Self where Self: Sized, { self.map(|this| if condition { then(this) } else { else_fn(this) }) } /// Conditionally unwrap and modify self with the given closure, if the given option is Some. fn when_some(self, option: Option, then: impl FnOnce(Self, T) -> Self) -> Self where Self: Sized, { self.map(|this| { if let Some(value) = option { then(this, value) } else { this } }) } /// Conditionally unwrap and modify self with the given closure, if the given option is None. fn when_none(self, option: &Option, then: impl FnOnce(Self) -> Self) -> Self where Self: Sized, { self.map(|this| { if let Some(_) = option { this } else { then(this) } }) } } #[cfg(any(test, feature = "test-support"))] pub async fn timeout(timeout: Duration, f: F) -> Result where F: Future, { let timer = async { smol::Timer::after(timeout).await; Err(()) }; let future = async move { Ok(f.await) }; timer.race(future).await } /// Increment the given atomic counter if it is not zero. /// Return the new value of the counter. pub(crate) fn atomic_incr_if_not_zero(counter: &AtomicUsize) -> usize { let mut loaded = counter.load(SeqCst); loop { if loaded == 0 { return 0; } match counter.compare_exchange_weak(loaded, loaded + 1, SeqCst, SeqCst) { Ok(x) => return x + 1, Err(actual) => loaded = actual, } } }