async_executors/iface/
spawn_handle.rs

1#[ allow(unused_imports) ]
2//
3use
4{
5	futures_util :: { future::{ FutureExt, abortable }, task::SpawnExt                    } ,
6	futures_task :: { SpawnError, FutureObj                                               } ,
7	crate        :: { JoinHandle                                                          } ,
8	std          :: { pin::Pin, future::Future, sync::{ Arc, atomic::AtomicBool }, rc::Rc } ,
9	blanket      :: { blanket                                                             } ,
10};
11
12
13/// Lets you spawn and get a [JoinHandle] to await the output of a future.
14///
15/// This trait works much like the [`Spawn`](futures_task::Spawn) trait from the futures library.
16/// It takes a [`FutureObj`] so we can hopefully make it `no_std` compatible when needed. This
17/// also allows it to be object safe.  For convenience, there is [`SpawnHandleExt`] which allows you
18/// to spawn a generic future directly without having to manually make the [`FutureObj`].
19///
20/// [`SpawnHandleExt`] is automatically implemented but must be in scope, so this works:
21///
22/// ```rust
23/// use async_executors::{ SpawnHandle, SpawnHandleExt };
24///
25/// async fn need_exec( exec: impl SpawnHandle<()> )
26/// {
27///    let join_handle = exec.spawn_handle( async {} ).expect( "spawn" );
28///
29///    join_handle.await;
30/// }
31/// ```
32///
33/// and so does this:
34///
35/// ```rust
36/// use async_executors::{ SpawnHandle, SpawnHandleExt };
37///
38/// async fn need_exec( exec: Box< dyn SpawnHandle<()> > )
39/// {
40///    let join_handle = exec.spawn_handle( async {} ).expect( "spawn" );
41///
42///    join_handle.await;
43/// }
44/// ```
45///
46/// One inconvenience of it having to be object safe is that the trait needs to be generic over the
47/// output parameter. This can be annoying if you need an executor that can spawn futures with different
48/// output parameters. Normally you should always be able to know which ones you need. If not
49/// you will have to make the type that stores the executor generic over the output type as well.
50///
51/// So to enable several output types you can use the
52/// [following workaround](https://github.com/najamelan/async_executors/tree/master/examples/spawn_handle_multi.rs).
53/// You can also use the [trait-set](https://crates.io/crates/trait-set) crate to make that [more streamlined](https://github.com/najamelan/async_executors/tree/master/examples/trait_set.rs).
54//
55#[ blanket(derive( Ref, Mut, Box, Arc, Rc )) ]
56//
57pub trait SpawnHandle<Out: 'static + Send>
58{
59	/// Spawn a future and return a [`JoinHandle`] that can be awaited for the output of the future.
60	//
61	fn spawn_handle_obj( &self, future: FutureObj<'static, Out> ) -> Result<JoinHandle<Out>, SpawnError>;
62}
63
64/// Convenience trait for passing in a generic future to [`SpawnHandle`]. Much akin to `Spawn` and `SpawnExt` in the
65/// futures library.
66//
67pub trait SpawnHandleExt<Out: 'static + Send> : SpawnHandle<Out>
68{
69	/// Spawn a future and return a [JoinHandle] that can be awaited for the output of the future.
70	//
71	fn spawn_handle( &self, future: impl Future<Output = Out> + Send + 'static ) -> Result<JoinHandle<Out>, SpawnError>;
72}
73
74
75impl<T, Out> SpawnHandleExt<Out> for T
76
77	where T  : SpawnHandle<Out> + ?Sized ,
78	      Out: 'static + Send            ,
79{
80	fn spawn_handle( &self, future: impl Future<Output = Out> + Send + 'static ) -> Result<JoinHandle<Out>, SpawnError>
81	{
82		self.spawn_handle_obj( FutureObj::new(future.boxed()) )
83	}
84}