1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
#![no_std] //! //! [![Codecov](https://img.shields.io/codecov/c/github/jonay2000/blocker?logo=codecov&style=for-the-badge)](https://codecov.io/gh/jonay200/blocker) //! [![Docs.rs](https://img.shields.io/badge/docs.rs-blocker-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K)](https://docs.rs/blocker) //! [![Crates.io](https://img.shields.io/crates/v/blocker?logo=rust&style=for-the-badge)](https://crates.io/crates/blocker) //! //! # Blocker! //! //! Blocker blocks. That's what it does, nothing more. Give it an async function and it waits until it's done. Forever. //! Works in `#![no_std]` environments as long as alloc is available. Blocker itself does not use any unsafe code. //! //! Enable the `thread_yield` feature to yield the current thread whenever an async function returns `Poll::pending`. //! //! # License //! //! This code is licensed under the [Apache 2.0 license](./LICENSE) use core::future::Future; use core::task::{Context, Poll}; use futures::task::noop_waker; extern crate alloc; use alloc::boxed::Box; #[cfg(thread_yield)] extern crate std; pub trait Blocker { type Output; fn block(self) -> Self::Output; } /// Blocker is a trait implemented for any type which implements Future. When imported, calling /// [`block`] on any future will halt the program until the future completes. impl<T> Blocker for T where T: Future, { type Output = T::Output; fn block(self) -> Self::Output { block(self) } } /// block is the heart of the blocker crate. When called with any future as parameter it blocks the /// program until the future completes. When futures return [`Pending`](core::task::Poll), the future /// will just be repolled. When the `thread_yield` feature is enabled, a pending future will yield the /// current thread. Note that this only works when std is available. pub fn block<'a, T>(future: impl Future<Output = T>) -> T where T: 'a, { let waker = noop_waker(); let mut ctx = Context::from_waker(&waker); let mut pinned = Box::pin(future); loop { if let Poll::Ready(i) = pinned.as_mut().poll(&mut ctx) { return i; } else { #[cfg(thread_yield)] std::thread::yield_now() } } } #[cfg(test)] mod tests { use crate::*; use alloc::rc::Rc; use core::ops::Deref; extern crate std; use std::sync::Mutex; async fn num() -> i64 { return 10; } #[test] pub fn test_block() { let f1 = num(); let f2 = num(); let f3 = num(); assert_eq!(10, block(f2)); assert_eq!(10, block(f1)); assert_eq!(10, block(f3)); } #[test] pub fn test_block_trait() { let f1 = num(); let f2 = num(); let f3 = num(); assert_eq!(10, f2.block()); assert_eq!(10, f1.block()); assert_eq!(10, f3.block()); } async fn rc(r: Rc<i64>) -> Rc<i64> { return r.clone(); } #[test] pub fn test_rc() { let r = Rc::new(10); let f1 = rc(r.clone()); let rcclone = r.deref(); assert_eq!(&10, block(f1).deref()); assert_eq!(&10, rcclone); } #[cfg_attr(miri, ignore)] async fn rc_mutex(r: Rc<Mutex<i64>>) -> Rc<Mutex<i64>> { let mut guard = r.deref().lock().unwrap(); *guard = 15; drop(guard); return r; } #[test] #[cfg_attr(miri, ignore)] pub fn test_rc_mutex() { let r = Rc::new(Mutex::new(10)); let f1 = rc_mutex(r.clone()); let original = r.deref(); let blocked = block(f1); { let guard = blocked.deref().lock().unwrap(); assert_eq!(15, *guard); } { let guard = original.deref().lock().unwrap(); assert_eq!(15, *guard); } } }