blob: 7cf5a1410838df6bd1fc4c09f67f749371629267 [file] [log] [blame]
Stjepan Glavina1479e862019-08-12 20:18:51 +02001//! A single-threaded executor where join handles catch panics inside tasks.
2
Stjepan Glavina1479e862019-08-12 20:18:51 +02003use std::future::Future;
4use std::panic::AssertUnwindSafe;
5use std::thread;
6
7use crossbeam::channel::{unbounded, Sender};
8use futures::executor;
9use futures::future::FutureExt;
10use lazy_static::lazy_static;
11
12/// Spawns a future on the executor.
13fn spawn<F, R>(future: F) -> async_task::JoinHandle<thread::Result<R>, ()>
14where
15 F: Future<Output = R> + Send + 'static,
16 R: Send + 'static,
17{
18 lazy_static! {
19 // A channel that holds scheduled tasks.
20 static ref QUEUE: Sender<async_task::Task<()>> = {
21 let (sender, receiver) = unbounded::<async_task::Task<()>>();
22
23 // Start the executor thread.
24 thread::spawn(|| {
25 for task in receiver {
26 // No need for `catch_unwind()` here because panics are already caught.
27 task.run();
28 }
29 });
30
31 sender
32 };
33 }
34
35 // Create a future that catches panics within itself.
36 let future = AssertUnwindSafe(future).catch_unwind();
37
38 // Create a task that is scheduled by sending itself into the channel.
39 let schedule = |t| QUEUE.send(t).unwrap();
40 let (task, handle) = async_task::spawn(future, schedule, ());
41
42 // Schedule the task by sending it into the channel.
43 task.schedule();
44
45 handle
46}
47
48fn main() {
49 // Spawn a future that completes succesfully.
50 let handle = spawn(async {
51 println!("Hello, world!");
52 });
53
54 // Block on the future and report its result.
55 match executor::block_on(handle) {
56 None => println!("The task was cancelled."),
57 Some(Ok(val)) => println!("The task completed with {:?}", val),
58 Some(Err(_)) => println!("The task has panicked"),
59 }
60
61 // Spawn a future that panics.
62 let handle = spawn(async {
63 panic!("Ooops!");
64 });
65
66 // Block on the future and report its result.
67 match executor::block_on(handle) {
68 None => println!("The task was cancelled."),
69 Some(Ok(val)) => println!("The task completed with {:?}", val),
70 Some(Err(_)) => println!("The task has panicked"),
71 }
72}