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}