1use crate::{
2 Executor, ExecutorBlockOn, ExecutorBlocking, ExecutorTimeout, InnerJoinHandle, JoinHandle,
3};
4use std::future::Future;
5use std::sync::Arc;
6use tokio::runtime::{Handle, Runtime};
7
8#[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq, Eq)]
10pub struct TokioExecutor;
11
12impl Executor for TokioExecutor {
13 fn runtime_type(&self) -> Option<&'static str> {
14 Some("tokio")
15 }
16
17 fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
18 where
19 F: Future + Send + 'static,
20 F::Output: Send + 'static,
21 {
22 let handle = tokio::task::spawn(future);
23 let inner = InnerJoinHandle::tokio(handle);
24 JoinHandle { inner }
25 }
26}
27
28impl ExecutorBlocking for TokioExecutor {
29 fn spawn_blocking<F, R>(&self, f: F) -> JoinHandle<R>
30 where
31 F: FnOnce() -> R + Send + 'static,
32 R: Send + 'static,
33 {
34 let handle = tokio::task::spawn_blocking(f);
35 let inner = InnerJoinHandle::tokio(handle);
36 JoinHandle { inner }
37 }
38}
39
40impl ExecutorTimeout for TokioExecutor {}
41
42impl ExecutorBlockOn for TokioExecutor {
43 fn block_on<F: Future>(&self, f: F) -> F::Output {
46 let handle = Handle::current();
47 handle.block_on(f)
48 }
49}
50
51#[derive(Clone, Debug)]
53pub struct TokioRuntimeExecutor {
54 handle: Handle,
55 _runtime: Option<Arc<Runtime>>,
56}
57
58impl TokioRuntimeExecutor {
59 pub fn with_single_thread() -> std::io::Result<Self> {
61 let runtime = tokio::runtime::Builder::new_current_thread()
62 .enable_all()
63 .build()?;
64 Ok(Self::with_runtime(runtime))
65 }
66
67 pub fn with_multi_thread() -> std::io::Result<Self> {
69 let runtime = tokio::runtime::Builder::new_multi_thread()
70 .enable_all()
71 .build()?;
72 Ok(Self::with_runtime(runtime))
73 }
74
75 pub fn with_runtime(runtime: Runtime) -> Self {
80 let runtime = Arc::new(runtime);
81 let handle = runtime.handle().clone();
82 Self {
83 _runtime: Some(runtime),
84 handle,
85 }
86 }
87
88 pub fn with_handle(handle: Handle) -> Self {
93 Self {
94 handle,
95 _runtime: None,
96 }
97 }
98
99 pub fn from_current_handle() -> std::io::Result<Self> {
104 let handle = Handle::try_current().map_err(std::io::Error::other)?;
105 Ok(Self::with_handle(handle))
106 }
107}
108
109impl Executor for TokioRuntimeExecutor {
110 fn runtime_type(&self) -> Option<&'static str> {
111 Some("tokio")
112 }
113
114 fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
115 where
116 F: Future + Send + 'static,
117 F::Output: Send + 'static,
118 {
119 let handle = self.handle.spawn(future);
120 let inner = InnerJoinHandle::tokio(handle);
121 JoinHandle { inner }
122 }
123}
124
125impl ExecutorBlocking for TokioRuntimeExecutor {
126 fn spawn_blocking<F, R>(&self, f: F) -> JoinHandle<R>
127 where
128 F: FnOnce() -> R + Send + 'static,
129 R: Send + 'static,
130 {
131 let handle = self.handle.spawn_blocking(f);
132 let inner = InnerJoinHandle::tokio(handle);
133 JoinHandle { inner }
134 }
135}
136
137impl ExecutorTimeout for TokioRuntimeExecutor {}
138
139impl ExecutorBlockOn for TokioRuntimeExecutor {
140 fn block_on<F: Future>(&self, f: F) -> F::Output {
147 match self._runtime.as_ref() {
148 None => self.handle.block_on(f),
149 Some(runtime) => runtime.block_on(f),
150 }
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::{TokioExecutor, TokioRuntimeExecutor};
157 use crate::error::JoinError;
158 use crate::{Executor, ExecutorBlockOn, ExecutorBlocking, ExecutorTimeout, TimeoutError};
159 use futures::channel::mpsc::{Receiver, UnboundedReceiver};
160 use futures_timer::Delay;
161
162 #[tokio::test]
163 async fn explicit_abort_is_reported_as_aborted() {
164 let handle = TokioExecutor.spawn(futures::future::pending::<()>());
165
166 handle.abort();
167
168 assert!(matches!(handle.await, Err(JoinError::Aborted)));
169 }
170
171 #[cfg(panic = "unwind")]
172 #[tokio::test]
173 async fn task_panic_is_reported_as_panicked() {
174 async fn panic_task() -> usize {
175 panic!("expected task panic");
176 }
177
178 let handle = TokioExecutor.spawn(panic_task());
179
180 assert!(matches!(handle.await, Err(JoinError::Panicked)));
181 }
182
183 #[test]
184 fn runtime_shutdown_is_reported_as_cancelled() {
185 let executor = TokioRuntimeExecutor::with_multi_thread().unwrap();
186 let handle = executor.spawn(futures::future::pending::<()>());
187
188 drop(executor);
189
190 assert!(matches!(
191 futures::executor::block_on(handle),
192 Err(JoinError::Cancelled)
193 ));
194 }
195
196 #[test]
197 fn block_on_drives_owned_current_thread_runtime() {
198 let executor = TokioRuntimeExecutor::with_single_thread().unwrap();
199 let handle = executor.spawn(async { 42 });
200
201 assert_eq!(executor.block_on(handle).unwrap(), 42);
202 }
203
204 #[tokio::test]
205 async fn default_abortable_task() {
206 let executor = TokioExecutor;
207
208 async fn task(tx: futures::channel::oneshot::Sender<()>) {
209 futures_timer::Delay::new(std::time::Duration::from_secs(5)).await;
210 let _ = tx.send(());
211 unreachable!();
212 }
213
214 let (tx, rx) = futures::channel::oneshot::channel::<()>();
215
216 let handle = executor.spawn_abortable(task(tx));
217
218 drop(handle);
219 let result = rx.await;
220 assert!(result.is_err());
221 }
222
223 #[tokio::test]
224 async fn task_coroutine() {
225 let executor = TokioExecutor;
226
227 enum Message {
228 Send(String, futures::channel::oneshot::Sender<String>),
229 }
230
231 let mut task = executor.spawn_coroutine(|msg: Message| async move {
232 match msg {
233 Message::Send(msg, sender) => {
234 sender.send(msg).unwrap();
235 }
236 }
237 });
238
239 let (tx, rx) = futures::channel::oneshot::channel::<String>();
240 let msg = Message::Send("Hello".into(), tx);
241
242 task.send(msg).await.unwrap();
243 let resp = rx.await.unwrap();
244 assert_eq!(resp, "Hello");
245 }
246
247 #[tokio::test]
248 async fn task_coroutine_with_context() {
249 let executor = TokioExecutor;
250
251 type Resp = futures::channel::oneshot::Sender<usize>;
252
253 let mut task =
254 executor.spawn_coroutine_with_context(0usize, |counter: &mut usize, resp: Resp| {
255 *counter += 1;
256 let n = *counter;
257 async move {
258 resp.send(n).unwrap();
259 }
260 });
261
262 let (tx1, rx1) = futures::channel::oneshot::channel::<usize>();
263 let (tx2, rx2) = futures::channel::oneshot::channel::<usize>();
264 task.send(tx1).await.unwrap();
265 task.send(tx2).await.unwrap();
266 assert_eq!(rx1.await.unwrap(), 1);
267 assert_eq!(rx2.await.unwrap(), 2);
268 }
269
270 #[tokio::test]
271 async fn task_coroutine_with_receiver() {
272 use futures::stream::StreamExt;
273 let executor = TokioExecutor;
274
275 enum Message {
276 Send(String, futures::channel::oneshot::Sender<String>),
277 }
278
279 let mut task =
280 executor.spawn_coroutine_with_receiver(|mut rx: Receiver<Message>| async move {
281 while let Some(msg) = rx.next().await {
282 match msg {
283 Message::Send(msg, sender) => {
284 sender.send(msg).unwrap();
285 }
286 }
287 }
288 });
289
290 let (tx, rx) = futures::channel::oneshot::channel::<String>();
291 let msg = Message::Send("Hello".into(), tx);
292
293 task.send(msg).await.unwrap();
294 let resp = rx.await.unwrap();
295 assert_eq!(resp, "Hello");
296 }
297
298 #[tokio::test]
299 async fn task_coroutine_with_receiver_and_context() {
300 use futures::stream::StreamExt;
301 let executor = TokioExecutor;
302
303 #[derive(Default)]
304 struct State {
305 message: String,
306 }
307
308 enum Message {
309 Set(String),
310 Get(futures::channel::oneshot::Sender<String>),
311 }
312
313 let mut task = executor.spawn_coroutine_with_receiver_and_context(
314 State::default(),
315 |mut state, mut rx: Receiver<Message>| async move {
316 while let Some(msg) = rx.next().await {
317 match msg {
318 Message::Set(msg) => {
319 state.message = msg;
320 }
321 Message::Get(resp) => {
322 resp.send(state.message.clone()).unwrap();
323 }
324 }
325 }
326 },
327 );
328
329 let msg = Message::Set("Hello".into());
330
331 task.send(msg).await.unwrap();
332 let (tx, rx) = futures::channel::oneshot::channel::<String>();
333 let msg = Message::Get(tx);
334 task.send(msg).await.unwrap();
335 let resp = rx.await.unwrap();
336 assert_eq!(resp, "Hello");
337 }
338
339 #[tokio::test]
340 async fn task_unbounded_coroutine() {
341 let executor = TokioExecutor;
342
343 enum Message {
344 Send(String, futures::channel::oneshot::Sender<String>),
345 }
346
347 let mut task = executor.spawn_unbounded_coroutine(|msg: Message| async move {
348 match msg {
349 Message::Send(msg, sender) => {
350 sender.send(msg).unwrap();
351 }
352 }
353 });
354
355 let (tx, rx) = futures::channel::oneshot::channel::<String>();
356 let msg = Message::Send("Hello".into(), tx);
357
358 task.send(msg).unwrap();
359 let resp = rx.await.unwrap();
360 assert_eq!(resp, "Hello");
361 }
362
363 #[tokio::test]
364 async fn task_unbounded_coroutine_with_context() {
365 let executor = TokioExecutor;
366
367 type Resp = futures::channel::oneshot::Sender<usize>;
368
369 let mut task = executor.spawn_unbounded_coroutine_with_context(
370 0usize,
371 |counter: &mut usize, resp: Resp| {
372 *counter += 1;
373 let n = *counter;
374 async move {
375 resp.send(n).unwrap();
376 }
377 },
378 );
379
380 let (tx1, rx1) = futures::channel::oneshot::channel::<usize>();
381 let (tx2, rx2) = futures::channel::oneshot::channel::<usize>();
382 task.send(tx1).unwrap();
383 task.send(tx2).unwrap();
384 assert_eq!(rx1.await.unwrap(), 1);
385 assert_eq!(rx2.await.unwrap(), 2);
386 }
387
388 #[tokio::test]
389 async fn task_unbounded_coroutine_with_receiver() {
390 use futures::stream::StreamExt;
391 let executor = TokioExecutor;
392
393 enum Message {
394 Send(String, futures::channel::oneshot::Sender<String>),
395 }
396
397 let mut task = executor.spawn_unbounded_coroutine_with_receiver(
398 |mut rx: UnboundedReceiver<Message>| async move {
399 while let Some(msg) = rx.next().await {
400 match msg {
401 Message::Send(msg, sender) => {
402 sender.send(msg).unwrap();
403 }
404 }
405 }
406 },
407 );
408
409 let (tx, rx) = futures::channel::oneshot::channel::<String>();
410 let msg = Message::Send("Hello".into(), tx);
411
412 task.send(msg).unwrap();
413 let resp = rx.await.unwrap();
414 assert_eq!(resp, "Hello");
415 }
416
417 #[tokio::test]
418 async fn task_unbounded_coroutine_with_receiver_and_context() {
419 use futures::stream::StreamExt;
420 let executor = TokioExecutor;
421
422 #[derive(Default)]
423 struct State {
424 message: String,
425 }
426
427 enum Message {
428 Set(String),
429 Get(futures::channel::oneshot::Sender<String>),
430 }
431
432 let mut task = executor.spawn_unbounded_coroutine_with_receiver_and_context(
433 State::default(),
434 |mut state, mut rx: UnboundedReceiver<Message>| async move {
435 while let Some(msg) = rx.next().await {
436 match msg {
437 Message::Set(msg) => {
438 state.message = msg;
439 }
440 Message::Get(resp) => {
441 resp.send(state.message.clone()).unwrap();
442 }
443 }
444 }
445 },
446 );
447
448 let msg = Message::Set("Hello".into());
449
450 task.send(msg).unwrap();
451 let (tx, rx) = futures::channel::oneshot::channel::<String>();
452 let msg = Message::Get(tx);
453 task.send(msg).unwrap();
454 let resp = rx.await.unwrap();
455 assert_eq!(resp, "Hello");
456 }
457
458 #[tokio::test]
459 async fn timeout_task() {
460 let executor = TokioExecutor;
461
462 let task = executor.spawn_timeout(
463 std::time::Duration::from_millis(10),
464 futures::future::pending::<()>(),
465 );
466 let resp = task.await.unwrap();
467 assert!(matches!(resp.unwrap_err(), TimeoutError));
468 }
469
470 #[tokio::test]
471 async fn complete_before_timeout_task() {
472 let executor = TokioExecutor;
473
474 let task = executor.spawn_timeout(
475 std::time::Duration::from_millis(10),
476 futures::future::ready("Hello"),
477 );
478 let resp = task.await.unwrap();
479 assert!(resp.is_ok());
480 let result = resp.unwrap();
481 assert_eq!(result, "Hello");
482 }
483
484 #[tokio::test]
485 async fn delay_task() {
486 let executor = TokioExecutor;
487 let duration = std::time::Duration::from_millis(20);
488 let started = std::time::Instant::now();
489
490 let task = executor.spawn_delay(duration, async { "Hello" });
491 let result = task.await.unwrap();
492
493 assert!(started.elapsed() >= duration);
494 assert_eq!(result, "Hello");
495 }
496
497 #[tokio::test]
498 async fn abortable_delay_task() {
499 let executor = TokioExecutor;
500 let (tx, rx) = futures::channel::oneshot::channel();
501 let task = executor.spawn_abortable_delay(std::time::Duration::from_secs(5), async move {
502 let _ = tx.send(());
503 });
504
505 drop(task);
506
507 assert!(rx.await.is_err());
508 }
509
510 #[tokio::test]
511 async fn race_before_timeout_task() {
512 let executor = TokioExecutor;
513
514 let task = executor.spawn_timeout(std::time::Duration::from_millis(500), async {
515 Delay::new(std::time::Duration::from_millis(10)).await;
516 "Hello"
517 });
518 let resp = task.await.unwrap();
519 assert!(resp.is_ok());
520 let result = resp.unwrap();
521 assert_eq!(result, "Hello");
522 }
523
524 #[tokio::test]
525 async fn abortable_timeout_task() {
526 let executor = TokioExecutor;
527
528 let task = executor.spawn_abortable_timeout(
529 std::time::Duration::from_millis(10),
530 futures::future::pending::<()>(),
531 );
532 let resp = task.await.unwrap();
533 assert!(matches!(resp.unwrap_err(), TimeoutError));
534 }
535
536 #[tokio::test]
537 async fn blocking_task() {
538 let executor = TokioExecutor;
539
540 let task = executor.spawn_blocking(|| {
541 std::thread::sleep(std::time::Duration::from_millis(100));
542 "Hello"
543 });
544 let resp = task.await.unwrap();
545 assert_eq!(resp, "Hello");
546 }
547}