1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
//! This is a convenience module for setting a default runtime and allowing code throughout to use [rt::spawn]. //! It means you don't have to pass an executor around everywhere. //! //! For examples, please look in the //! [examples directory of the repository](https://github.com/najamelan/async_runtime/tree/master/examples). //! pub(crate) mod exec03; pub use exec03::*; use crate :: { import::*, RtConfig, RtErr, RtErrKind }; thread_local! ( static EXEC: OnceCell< Exec03 > = OnceCell::INIT; ); /// Set the executor to use by default. Run this before calls to spawn. If you are a library /// author, don't call this unless you create the thread, otherwise it's up to client code to /// decide which executor to use. Just call [spawn]. /// /// This is optional and if you don't set this, the default executor depends on whether the `juliex` /// feature is enabled for the crate. If it is, it is the default executor, otherwise it will be the /// local pool. If it's enabled and you still want the local pool, use this method. /// /// ### Errors /// /// This method will fail with [RtErrKind::DoubleExecutorInit](crate::RtErrKind::DoubleExecutorInit) if you /// call it twice on the same thread or if you have called [spawn] and thus the executor has been initialized /// by default before you call init. /// /// ### Example /// /// ``` /// # #![ feature( async_await ) ] /// # /// # // unfortunately we can't rename the crate itself in Cargo.yml. /// # // /// # use naja_async_runtime as async_runtime; /// # /// use async_runtime::*; /// /// rt::init( RtConfig::Local ).expect( "Set default executor" ); /// /// // ...spawn some tasks... /// // /// rt::spawn( async {} ).expect( "spawn future" ); /// /// // Important, otherwise the local executor does not poll. For the threadpool this is not necessary, /// // as futures will be polled immediately after spawning them. /// // /// rt::run(); /// /// ``` // pub fn init( config: RtConfig ) -> Result< (), RtErr > { EXEC.with( move |exec| -> Result< (), RtErr > { exec .set( Exec03::new( config ) ) .map_err( |_| RtErrKind::DoubleExecutorInit.into() ) }) } /// If no executor is set, initialize with defaults (pool if juliex feature is enabled, local pool otherwise) // fn default_init() { EXEC.with( move |exec| { if exec.get().is_none() { init( RtConfig::default() ).unwrap(); } }); } /// Spawn a future to be run on the default executor (set with [init] or default, depending on `juliex feature`, /// see documentation for rt::init). /// /// ### Errors /// /// - When using `RtConfig::Pool` (currently juliex), this method is infallible. /// - When using `RtConfig::Local` (currently futures 0.3 LocalPool), this method can return a spawn /// error if the executor has been shut down. See the [docs for the futures library](https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.16/futures/task/struct.SpawnError.html). I haven't really found a way to trigger this error. /// You can call [crate::rt::run] and spawn again afterwards. /// /// ### Example /// /// ``` /// # #![ feature( async_await) ] /// # /// # // unfortunately we can't rename the crate itself in Cargo.yml. /// # // /// # use naja_async_runtime as async_runtime; /// # /// use async_runtime::*; /// /// // This will run on the threadpool. For the local pool you must call [rt::init] and [rt::run]. /// // /// rt::spawn( async /// { /// println!( "async execution" ); /// /// }); /// ``` // pub fn spawn( fut: impl Future< Output=() > + 'static + Send ) -> Result< (), RtErr > { EXEC.with( move |exec| -> Result< (), RtErr > { default_init(); exec.get().unwrap().spawn( fut ) }) } /// Spawn a future to be run on the LocalPool (current thread). This will return an error /// if the current executor is the threadpool. /// /// Does exactly the same as [spawn], but does not require the future to be [Send]. If your /// future is [Send], you can just use [spawn]. It will always spawn on the default executor. /// /// ### Errors /// /// - When using `RtConfig::Pool` (currently juliex), this method will return a [RtErrKind::Spawn](crate::RtErrKind::Spawn). Since /// the signature doesn't require [Send] on the future, it can never be sent on a threadpool. /// - When using `RtConfig::Local` (currently futures 0.3 LocalPool), this method can return a spawn /// error if the executor has been shut down. See the [docs for the futures library](https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.16/futures/task/struct.SpawnError.html). I haven't really found a way to trigger this error. /// You can call [rt::run](crate::rt::run) and spawn again afterwards. // pub fn spawn_local( fut: impl Future< Output=() > + 'static ) -> Result< (), RtErr > { EXEC.with( move |exec| -> Result< (), RtErr > { default_init(); exec.get().unwrap().spawn_local( fut ) }) } /// Run all spawned futures to completion. This is a no-op for the threadpool. However you must /// run this after spawning on the local pool or futures won't be polled. /// Do not call it from within a spawned task, or your program will hang or panic. // pub fn run() { EXEC.with( move |exec| { default_init(); exec.get().unwrap().run(); }); } /// Get the configuration for the current default executor. /// Note that if this returns `None` and you call [`spawn`], a default executor /// will be initialized, after which this will no longer return `None`. /// /// If you are a library author you can use this to generate a clean error message /// if you have a hard requirement for a certain executor. // pub fn current_rt() -> Option<RtConfig> { EXEC.with( move |exec| { if exec.get().is_none() { None } else { Some( exec.get().unwrap().config().clone() ) } }) } /// Block the current thread until the given future resolves and return the Output. /// This just forwards to `futures::executor::block_on` under the hood. // pub fn block_on< F: Future >( fut: F ) -> F::Output { futures::executor::block_on( fut ) }