1#![doc = document_features::document_features!()]
29#![cfg_attr(docsrs, feature(doc_auto_cfg))]
30#![deny(unsafe_code)]
36#![warn(
37 clippy::all,
38 clippy::await_holding_lock,
39 clippy::char_lit_as_u8,
40 clippy::checked_conversions,
41 clippy::dbg_macro,
42 clippy::debug_assert_with_mut_call,
43 clippy::doc_markdown,
44 clippy::empty_enum,
45 clippy::enum_glob_use,
46 clippy::exit,
47 clippy::expl_impl_clone_on_copy,
48 clippy::explicit_deref_methods,
49 clippy::explicit_into_iter_loop,
50 clippy::fallible_impl_from,
51 clippy::filter_map_next,
52 clippy::flat_map_option,
53 clippy::float_cmp_const,
54 clippy::fn_params_excessive_bools,
55 clippy::from_iter_instead_of_collect,
56 clippy::if_let_mutex,
57 clippy::implicit_clone,
58 clippy::imprecise_flops,
59 clippy::inefficient_to_string,
60 clippy::invalid_upcast_comparisons,
61 clippy::large_digit_groups,
62 clippy::large_stack_arrays,
63 clippy::large_types_passed_by_value,
64 clippy::let_unit_value,
65 clippy::linkedlist,
66 clippy::lossy_float_literal,
67 clippy::macro_use_imports,
68 clippy::manual_ok_or,
69 clippy::map_err_ignore,
70 clippy::map_flatten,
71 clippy::map_unwrap_or,
72 clippy::match_on_vec_items,
73 clippy::match_same_arms,
74 clippy::match_wild_err_arm,
75 clippy::match_wildcard_for_single_variants,
76 clippy::mem_forget,
77 clippy::mismatched_target_os,
78 clippy::missing_enforced_import_renames,
79 clippy::mut_mut,
80 clippy::mutex_integer,
81 clippy::needless_borrow,
82 clippy::needless_continue,
83 clippy::needless_for_each,
84 clippy::option_option,
85 clippy::path_buf_push_overwrite,
86 clippy::ptr_as_ptr,
87 clippy::rc_mutex,
88 clippy::ref_option_ref,
89 clippy::rest_pat_in_fully_bound_structs,
90 clippy::same_functions_in_if_condition,
91 clippy::semicolon_if_nothing_returned,
92 clippy::single_match_else,
93 clippy::string_add_assign,
94 clippy::string_add,
95 clippy::string_lit_as_bytes,
96 clippy::string_to_string,
97 clippy::todo,
98 clippy::trait_duplication_in_bounds,
99 clippy::unimplemented,
100 clippy::unnested_or_patterns,
101 clippy::unused_self,
102 clippy::useless_transmute,
103 clippy::verbose_file_reads,
104 clippy::zero_sized_map_values,
105 future_incompatible,
106 nonstandard_style,
107 rust_2018_idioms
108)]
109#![deny(missing_docs, rustdoc::missing_crate_level_docs)]
112
113mod promise;
114
115pub use promise::{Promise, Sender, TaskType};
116
117#[cfg(feature = "smol")]
118static EXECUTOR: smol::Executor<'static> = smol::Executor::new();
119#[cfg(feature = "smol")]
120thread_local! {
121 static LOCAL_EXECUTOR: smol::LocalExecutor<'static> = smol::LocalExecutor::new();
122}
123
124#[cfg(feature = "smol")]
129pub fn tick() -> bool {
130 crate::EXECUTOR.try_tick()
131}
132
133#[cfg(feature = "smol")]
138pub fn tick_local() -> bool {
139 crate::LOCAL_EXECUTOR.with(|exec| exec.try_tick())
140}
141
142#[cfg(test)]
143mod test {
144 use crate::Promise;
145
146 #[test]
147 fn it_spawns_threads() {
148 let promise = Promise::spawn_thread("test", || {
149 std::thread::sleep(std::time::Duration::from_secs(1));
150 0
151 });
152
153 assert_eq!(0, promise.block_and_take());
154 }
155
156 #[test]
157 #[cfg(feature = "smol")]
158 fn it_runs_async_threaded() {
159 let promise = Promise::spawn_async(async move { 0 });
160
161 assert_eq!(0, promise.block_and_take());
162 }
163
164 #[tokio::test(flavor = "multi_thread")]
165 #[cfg(feature = "tokio")]
166 async fn it_runs_async_threaded() {
167 let promise = Promise::spawn_async(async move { 0 });
168
169 assert_eq!(0, promise.block_and_take());
170 }
171
172 #[test]
173 #[cfg(feature = "async-std")]
174 fn it_runs_async_threaded() {
175 let promise = Promise::spawn_async(async move { 0 });
176
177 assert_eq!(0, promise.block_and_take());
178 }
179
180 #[test]
181 #[cfg(feature = "smol")]
182 fn it_runs_locally() {
183 let promise = Promise::spawn_local(async move { 0 });
184
185 assert_eq!(0, promise.block_and_take());
186 }
187
188 #[test]
189 #[cfg(feature = "smol")]
190 fn it_runs_background() {
191 let promise = Promise::spawn_async(async move {
192 let mut e = 0;
193 for i in -10000..0 {
194 e += i;
195 }
196 e
197 });
198 #[cfg(not(feature = "smol_tick_poll"))]
199 crate::tick();
200
201 std::thread::sleep(std::time::Duration::from_secs(1));
202 assert!(promise.ready().is_some(), "was not finished");
203 }
204
205 #[tokio::test(flavor = "multi_thread")]
206 #[cfg(feature = "tokio")]
207 async fn it_runs_background() {
208 let promise = Promise::spawn_async(async move {
209 let mut e = 0;
210 for i in -10000..0 {
211 e += i;
212 }
213 e
214 });
215
216 std::thread::sleep(std::time::Duration::from_secs(1));
217 assert!(promise.ready().is_some(), "was not finished");
218 }
219
220 #[test]
221 #[cfg(feature = "async-std")]
222 fn it_runs_background() {
223 let promise = Promise::spawn_async(async move {
224 let mut e = 0;
225 for i in -10000..0 {
226 e += i;
227 }
228 e
229 });
230
231 std::thread::sleep(std::time::Duration::from_secs(1));
232 assert!(promise.ready().is_some(), "was not finished");
233 }
234
235 #[test]
236 #[cfg(feature = "smol")]
237 fn it_can_block() {
238 let promise = Promise::spawn_local(async move {
239 std::thread::sleep(std::time::Duration::from_secs(1));
240 });
241 #[cfg(not(feature = "smol_tick_poll"))]
242 crate::tick_local();
243
244 assert!(promise.ready().is_some(), "was not finished");
245 }
246
247 #[test]
248 #[cfg(feature = "smol")]
249 fn it_can_run_async_functions() {
250 let promise = Promise::spawn_async(async move { something_async().await });
251 #[cfg(not(feature = "smol_tick_poll"))]
252 crate::tick();
253
254 assert!(promise.block_and_take(), "example.com is ipv4");
255 }
256 #[tokio::test(flavor = "multi_thread")]
257 #[cfg(feature = "tokio")]
258 async fn it_can_run_async_functions() {
259 let promise = Promise::spawn_async(async move { something_async().await });
260
261 assert!(promise.block_and_take(), "example.com is ipv4");
262 }
263
264 #[test]
265 #[cfg(feature = "async-std")]
266 fn it_can_run_async_functions() {
267 let promise = Promise::spawn_async(async move { something_async().await });
268
269 assert!(promise.block_and_take(), "example.com is ipv4");
270 }
271
272 #[test]
273 #[cfg(feature = "smol")]
274 fn it_can_run_async_functions_locally() {
275 let promise = Promise::spawn_local(async move { something_async().await });
276 #[cfg(not(feature = "smol_tick_poll"))]
277 crate::tick_local();
278
279 assert!(promise.block_and_take(), "example.com is ipv4");
280 }
281
282 #[cfg(any(feature = "smol", feature = "tokio", feature = "async-std"))]
283 async fn something_async() -> bool {
284 async_net::resolve("example.com:80").await.unwrap()[0].is_ipv4()
285 }
286}