1
- use std:: { any:: Any , future:: Future , panic:: AssertUnwindSafe , pin:: Pin } ;
1
+ use std:: { any:: Any , cell :: RefCell , future:: Future , panic:: AssertUnwindSafe , pin:: Pin } ;
2
2
3
3
use async_std:: task;
4
4
use futures:: prelude:: * ;
5
- use once_cell:: unsync:: OnceCell ;
6
- use pyo3:: { prelude:: * , PyNativeType } ;
5
+ use pyo3:: prelude:: * ;
7
6
8
- use crate :: {
9
- generic:: { self , JoinError , Runtime , SpawnLocalExt } ,
10
- into_future_with_loop,
11
- } ;
7
+ use crate :: generic:: { self , JoinError , Runtime , SpawnLocalExt } ;
12
8
13
9
/// <span class="module-item stab portability" style="display: inline; border-radius: 3px; padding: 2px; font-size: 80%; line-height: 1.2;"><code>attributes</code></span>
14
10
/// re-exports for macros
@@ -37,7 +33,7 @@ impl JoinError for AsyncStdJoinErr {
37
33
}
38
34
39
35
async_std:: task_local! {
40
- static EVENT_LOOP : OnceCell < PyObject > = OnceCell :: new( )
36
+ static EVENT_LOOP : RefCell < Option < PyObject >> = RefCell :: new( None ) ;
41
37
}
42
38
43
39
struct AsyncStdRuntime ;
@@ -50,11 +46,19 @@ impl Runtime for AsyncStdRuntime {
50
46
where
51
47
F : Future < Output = R > + Send + ' static ,
52
48
{
53
- EVENT_LOOP . with ( |c| c. set ( event_loop) . unwrap ( ) ) ;
54
- Box :: pin ( fut)
49
+ let old = EVENT_LOOP . with ( |c| c. replace ( Some ( event_loop) ) ) ;
50
+ Box :: pin ( async move {
51
+ let result = fut. await ;
52
+ EVENT_LOOP . with ( |c| c. replace ( old) ) ;
53
+ result
54
+ } )
55
55
}
56
56
fn get_task_event_loop ( py : Python ) -> Option < & PyAny > {
57
- match EVENT_LOOP . try_with ( |c| c. get ( ) . map ( |event_loop| event_loop. clone ( ) . into_ref ( py) ) ) {
57
+ match EVENT_LOOP . try_with ( |c| {
58
+ c. borrow ( )
59
+ . as_ref ( )
60
+ . map ( |event_loop| event_loop. clone ( ) . into_ref ( py) )
61
+ } ) {
58
62
Ok ( event_loop) => event_loop,
59
63
Err ( _) => None ,
60
64
}
@@ -78,8 +82,12 @@ impl SpawnLocalExt for AsyncStdRuntime {
78
82
where
79
83
F : Future < Output = R > + ' static ,
80
84
{
81
- EVENT_LOOP . with ( |c| c. set ( event_loop) . unwrap ( ) ) ;
82
- Box :: pin ( fut)
85
+ let old = EVENT_LOOP . with ( |c| c. replace ( Some ( event_loop) ) ) ;
86
+ Box :: pin ( async move {
87
+ let result = fut. await ;
88
+ EVENT_LOOP . with ( |c| c. replace ( old) ) ;
89
+ result
90
+ } )
83
91
}
84
92
85
93
fn spawn_local < F > ( fut : F ) -> Self :: JoinHandle
@@ -110,21 +118,20 @@ where
110
118
}
111
119
112
120
/// Get the current event loop from either Python or Rust async task local context
121
+ ///
122
+ /// This function first checks if the runtime has a task-local reference to the Python event loop.
123
+ /// If not, it calls [`get_running_loop`](`crate::get_running_loop`) to get the event loop
124
+ /// associated with the current OS thread.
113
125
pub fn get_current_loop ( py : Python ) -> PyResult < & PyAny > {
114
126
generic:: get_current_loop :: < AsyncStdRuntime > ( py)
115
127
}
116
128
117
- /// Get the task local event loop for the current async_std task
118
- pub fn task_event_loop ( py : Python ) -> Option < & PyAny > {
119
- AsyncStdRuntime :: get_task_event_loop ( py)
120
- }
121
-
122
129
/// Run the event loop until the given Future completes
123
130
///
124
131
/// The event loop runs until the given future is complete.
125
132
///
126
133
/// After this function returns, the event loop can be resumed with either [`run_until_complete`] or
127
- /// [`crate::run_forever`]
134
+ /// [`run_forever`](` crate::run_forever`)
128
135
///
129
136
/// # Arguments
130
137
/// * `py` - The current PyO3 GIL guard
@@ -227,6 +234,39 @@ where
227
234
generic:: into_coroutine :: < AsyncStdRuntime , _ > ( py, fut)
228
235
}
229
236
237
+ /// Convert a Rust Future into a Python awaitable
238
+ ///
239
+ /// # Arguments
240
+ /// * `event_loop` - The Python event loop that the awaitable should be attached to
241
+ /// * `fut` - The Rust future to be converted
242
+ ///
243
+ /// # Examples
244
+ ///
245
+ /// ```
246
+ /// use std::time::Duration;
247
+ ///
248
+ /// use pyo3::prelude::*;
249
+ ///
250
+ /// /// Awaitable sleep function
251
+ /// #[pyfunction]
252
+ /// fn sleep_for<'p>(py: Python<'p>, secs: &'p PyAny) -> PyResult<&'p PyAny> {
253
+ /// let secs = secs.extract()?;
254
+ /// pyo3_asyncio::async_std::future_into_py_with_loop(
255
+ /// pyo3_asyncio::async_std::get_current_loop(py)?,
256
+ /// async move {
257
+ /// async_std::task::sleep(Duration::from_secs(secs)).await;
258
+ /// Python::with_gil(|py| Ok(py.None()))
259
+ /// }
260
+ /// )
261
+ /// }
262
+ /// ```
263
+ pub fn future_into_py_with_loop < F > ( event_loop : & PyAny , fut : F ) -> PyResult < & PyAny >
264
+ where
265
+ F : Future < Output = PyResult < PyObject > > + Send + ' static ,
266
+ {
267
+ generic:: future_into_py_with_loop :: < AsyncStdRuntime , F > ( event_loop, fut)
268
+ }
269
+
230
270
/// Convert a Rust Future into a Python awaitable
231
271
///
232
272
/// # Arguments
@@ -260,7 +300,7 @@ where
260
300
/// Convert a `!Send` Rust Future into a Python awaitable
261
301
///
262
302
/// # Arguments
263
- /// * `py ` - The current PyO3 GIL guard
303
+ /// * `event_loop ` - The Python event loop that the awaitable should be attached to
264
304
/// * `fut` - The Rust future to be converted
265
305
///
266
306
/// # Examples
@@ -273,7 +313,7 @@ where
273
313
/// /// Awaitable non-send sleep function
274
314
/// #[pyfunction]
275
315
/// fn sleep_for(py: Python, secs: u64) -> PyResult<&PyAny> {
276
- /// // Rc is non-send so it cannot be passed into pyo3_asyncio::async_std::into_coroutine
316
+ /// // Rc is non-send so it cannot be passed into pyo3_asyncio::async_std::future_into_py
277
317
/// let secs = Rc::new(secs);
278
318
/// Ok(pyo3_asyncio::async_std::local_future_into_py_with_loop(
279
319
/// pyo3_asyncio::async_std::get_current_loop(py)?,
@@ -321,7 +361,7 @@ where
321
361
/// /// Awaitable non-send sleep function
322
362
/// #[pyfunction]
323
363
/// fn sleep_for(py: Python, secs: u64) -> PyResult<&PyAny> {
324
- /// // Rc is non-send so it cannot be passed into pyo3_asyncio::async_std::into_coroutine
364
+ /// // Rc is non-send so it cannot be passed into pyo3_asyncio::async_std::future_into_py
325
365
/// let secs = Rc::new(secs);
326
366
/// pyo3_asyncio::async_std::local_future_into_py(py, async move {
327
367
/// async_std::task::sleep(Duration::from_secs(*secs)).await;
@@ -399,5 +439,5 @@ where
399
439
/// }
400
440
/// ```
401
441
pub fn into_future ( awaitable : & PyAny ) -> PyResult < impl Future < Output = PyResult < PyObject > > + Send > {
402
- into_future_with_loop ( get_current_loop ( awaitable . py ( ) ) ? , awaitable)
442
+ generic :: into_future :: < AsyncStdRuntime > ( awaitable)
403
443
}
0 commit comments