blob: 95214ed4d687a60c96cde9cec8d819455bd27e2d [file] [log] [blame]
Stjepan Glavina1479e862019-08-12 20:18:51 +02001//! A function that runs a future to completion on a dedicated thread.
2
Stjepan Glavina1479e862019-08-12 20:18:51 +02003use std::future::Future;
4use std::sync::Arc;
5use std::thread;
6
7use crossbeam::channel;
8use futures::executor;
9
Stjepan Glavinafcfa4ab2019-11-25 18:39:17 +010010type JoinHandle<T> = async_task::JoinHandle<T, ()>;
11
Stjepan Glavina1479e862019-08-12 20:18:51 +020012/// Spawns a future on a new dedicated thread.
13///
14/// The returned handle can be used to await the output of the future.
Stjepan Glavinafcfa4ab2019-11-25 18:39:17 +010015fn spawn_on_thread<F, R>(future: F) -> JoinHandle<R>
Stjepan Glavina1479e862019-08-12 20:18:51 +020016where
17 F: Future<Output = R> + Send + 'static,
18 R: Send + 'static,
19{
20 // Create a channel that holds the task when it is scheduled for running.
21 let (sender, receiver) = channel::unbounded();
22 let sender = Arc::new(sender);
23 let s = Arc::downgrade(&sender);
24
25 // Wrap the future into one that disconnects the channel on completion.
26 let future = async move {
27 // When the inner future completes, the sender gets dropped and disconnects the channel.
28 let _sender = sender;
29 future.await
30 };
31
32 // Create a task that is scheduled by sending itself into the channel.
33 let schedule = move |t| s.upgrade().unwrap().send(t).unwrap();
34 let (task, handle) = async_task::spawn(future, schedule, ());
35
36 // Schedule the task by sending it into the channel.
37 task.schedule();
38
39 // Spawn a thread running the task to completion.
40 thread::spawn(move || {
41 // Keep taking the task from the channel and running it until completion.
42 for task in receiver {
43 task.run();
44 }
45 });
46
47 handle
48}
49
50fn main() {
51 // Spawn a future on a dedicated thread.
52 executor::block_on(spawn_on_thread(async {
53 println!("Hello, world!");
54 }));
55}