util.rs

 1use std::sync::atomic::AtomicUsize;
 2use std::sync::atomic::Ordering::SeqCst;
 3#[cfg(any(test, feature = "test-support"))]
 4use std::time::Duration;
 5
 6#[cfg(any(test, feature = "test-support"))]
 7use futures::Future;
 8
 9#[cfg(any(test, feature = "test-support"))]
10use smol::future::FutureExt;
11
12pub use util::*;
13
14/// A helper trait for building complex objects with imperative conditionals in a fluent style.
15pub trait FluentBuilder {
16    /// Imperatively modify self with the given closure.
17    fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
18    where
19        Self: Sized,
20    {
21        f(self)
22    }
23
24    /// Conditionally modify self with the given closure.
25    fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
26    where
27        Self: Sized,
28    {
29        self.map(|this| if condition { then(this) } else { this })
30    }
31
32    /// Conditionally modify self with the given closure.
33    fn when_else(
34        self,
35        condition: bool,
36        then: impl FnOnce(Self) -> Self,
37        else_fn: impl FnOnce(Self) -> Self,
38    ) -> Self
39    where
40        Self: Sized,
41    {
42        self.map(|this| if condition { then(this) } else { else_fn(this) })
43    }
44
45    /// Conditionally unwrap and modify self with the given closure, if the given option is Some.
46    fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
47    where
48        Self: Sized,
49    {
50        self.map(|this| {
51            if let Some(value) = option {
52                then(this, value)
53            } else {
54                this
55            }
56        })
57    }
58    /// Conditionally unwrap and modify self with the given closure, if the given option is None.
59    fn when_none<T>(self, option: &Option<T>, then: impl FnOnce(Self) -> Self) -> Self
60    where
61        Self: Sized,
62    {
63        self.map(|this| {
64            if let Some(_) = option {
65                this
66            } else {
67                then(this)
68            }
69        })
70    }
71}
72
73#[cfg(any(test, feature = "test-support"))]
74pub async fn timeout<F, T>(timeout: Duration, f: F) -> Result<T, ()>
75where
76    F: Future<Output = T>,
77{
78    let timer = async {
79        smol::Timer::after(timeout).await;
80        Err(())
81    };
82    let future = async move { Ok(f.await) };
83    timer.race(future).await
84}
85
86/// Increment the given atomic counter if it is not zero.
87/// Return the new value of the counter.
88pub(crate) fn atomic_incr_if_not_zero(counter: &AtomicUsize) -> usize {
89    let mut loaded = counter.load(SeqCst);
90    loop {
91        if loaded == 0 {
92            return 0;
93        }
94        match counter.compare_exchange_weak(loaded, loaded + 1, SeqCst, SeqCst) {
95            Ok(x) => return x + 1,
96            Err(actual) => loaded = actual,
97        }
98    }
99}