async_std/
utils.rs

1/// Calls a function and aborts if it panics.
2///
3/// This is useful in unsafe code where we can't recover from panics.
4#[cfg(feature = "default")]
5#[inline]
6pub fn abort_on_panic<T>(f: impl FnOnce() -> T) -> T {
7    struct Bomb;
8
9    impl Drop for Bomb {
10        fn drop(&mut self) {
11            std::process::abort();
12        }
13    }
14
15    let bomb = Bomb;
16    let t = f();
17    std::mem::forget(bomb);
18    t
19}
20
21/// Generates a random number in `0..n`.
22#[cfg(feature = "unstable")]
23pub fn random(n: u32) -> u32 {
24    use std::cell::Cell;
25    use std::num::Wrapping;
26
27    thread_local! {
28        static RNG: Cell<Wrapping<u32>> = {
29            // Take the address of a local value as seed.
30            let mut x = 0i32;
31            let r = &mut x;
32            let addr = r as *mut i32 as usize;
33            Cell::new(Wrapping(addr as u32))
34        }
35    }
36
37    RNG.with(|rng| {
38        // This is the 32-bit variant of Xorshift.
39        //
40        // Source: https://en.wikipedia.org/wiki/Xorshift
41        let mut x = rng.get();
42        x ^= x << 13;
43        x ^= x >> 17;
44        x ^= x << 5;
45        rng.set(x);
46
47        // This is a fast alternative to `x % n`.
48        //
49        // Author: Daniel Lemire
50        // Source: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
51        ((u64::from(x.0)).wrapping_mul(u64::from(n)) >> 32) as u32
52    })
53}
54
55/// Add additional context to errors
56#[cfg(feature = "std")]
57pub(crate) trait Context {
58    fn context(self, message: impl Fn() -> String) -> Self;
59}
60
61#[cfg(all(
62    not(target_os = "unknown"),
63    any(feature = "default", feature = "unstable")
64))]
65mod timer {
66    pub type Timer = async_io::Timer;
67}
68
69#[cfg(any(feature = "unstable", feature = "default"))]
70pub(crate) fn timer_after(dur: std::time::Duration) -> timer::Timer {
71    Timer::after(dur)
72}
73
74#[cfg(any(all(target_arch = "wasm32", feature = "default"),))]
75mod timer {
76    use std::pin::Pin;
77    use std::task::Poll;
78
79    use gloo_timers::future::TimeoutFuture;
80
81    #[derive(Debug)]
82    pub(crate) struct Timer(TimeoutFuture);
83
84    impl Timer {
85        pub(crate) fn after(dur: std::time::Duration) -> Self {
86            // Round up to the nearest millisecond.
87            let mut timeout_ms = dur.as_millis() as u32;
88            if std::time::Duration::from_millis(timeout_ms as u64) < dur {
89                timeout_ms += 1;
90            }
91
92            Timer(TimeoutFuture::new(timeout_ms))
93        }
94    }
95
96    impl std::future::Future for Timer {
97        type Output = ();
98
99        fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
100            match Pin::new(&mut self.0).poll(cx) {
101                Poll::Pending => Poll::Pending,
102                Poll::Ready(_) => Poll::Ready(()),
103            }
104        }
105    }
106}
107
108#[cfg(any(feature = "unstable", feature = "default"))]
109pub(crate) use timer::*;
110
111/// Defers evaluation of a block of code until the end of the scope.
112#[cfg(feature = "default")]
113#[doc(hidden)]
114macro_rules! defer {
115    ($($body:tt)*) => {
116        let _guard = {
117            pub struct Guard<F: FnOnce()>(Option<F>);
118
119            impl<F: FnOnce()> Drop for Guard<F> {
120                fn drop(&mut self) {
121                    (self.0).take().map(|f| f());
122                }
123            }
124
125            Guard(Some(|| {
126                let _ = { $($body)* };
127            }))
128        };
129    };
130}
131
132/// Declares unstable items.
133#[doc(hidden)]
134macro_rules! cfg_unstable {
135    ($($item:item)*) => {
136        $(
137            #[cfg(feature = "unstable")]
138            #[cfg_attr(feature = "docs", doc(cfg(unstable)))]
139            $item
140        )*
141    }
142}
143
144/// Declares unstable and default items.
145#[doc(hidden)]
146macro_rules! cfg_unstable_default {
147    ($($item:item)*) => {
148        $(
149            #[cfg(all(feature = "default", feature = "unstable"))]
150            #[cfg_attr(feature = "docs", doc(cfg(unstable)))]
151            $item
152        )*
153    }
154}
155
156/// Declares Unix-specific items.
157#[doc(hidden)]
158#[allow(unused_macros)]
159macro_rules! cfg_unix {
160    ($($item:item)*) => {
161        $(
162            #[cfg(any(unix, feature = "docs"))]
163            $item
164        )*
165    }
166}
167
168/// Declares Windows-specific items.
169#[doc(hidden)]
170#[allow(unused_macros)]
171macro_rules! cfg_windows {
172    ($($item:item)*) => {
173        $(
174            #[cfg(any(windows, feature = "docs"))]
175            $item
176        )*
177    }
178}
179
180/// Declares items when the "docs" feature is enabled.
181#[doc(hidden)]
182#[allow(unused_macros)]
183macro_rules! cfg_docs {
184    ($($item:item)*) => {
185        $(
186            #[cfg(feature = "docs")]
187            $item
188        )*
189    }
190}
191
192/// Declares items when the "docs" feature is disabled.
193#[doc(hidden)]
194#[allow(unused_macros)]
195macro_rules! cfg_not_docs {
196    ($($item:item)*) => {
197        $(
198            #[cfg(not(feature = "docs"))]
199            $item
200        )*
201    }
202}
203
204/// Declares std items.
205#[allow(unused_macros)]
206#[doc(hidden)]
207macro_rules! cfg_std {
208    ($($item:item)*) => {
209        $(
210            #[cfg(feature = "std")]
211            $item
212        )*
213    }
214}
215
216/// Declares no-std items.
217#[allow(unused_macros)]
218#[doc(hidden)]
219macro_rules! cfg_alloc {
220    ($($item:item)*) => {
221        $(
222            #[cfg(feature = "alloc")]
223            $item
224        )*
225    }
226}
227
228/// Declares default items.
229#[allow(unused_macros)]
230#[doc(hidden)]
231macro_rules! cfg_default {
232    ($($item:item)*) => {
233        $(
234            #[cfg(feature = "default")]
235            $item
236        )*
237    }
238}
239
240/// Declares items that use I/O safety.
241#[allow(unused_macros)]
242#[doc(hidden)]
243macro_rules! cfg_io_safety {
244    ($($item:item)*) => {
245        $(
246            #[cfg(feature = "io_safety")]
247            $item
248        )*
249    }
250}