1- use futures:: Future ;
2- use std:: cell:: RefCell ;
31use cpython:: { PyResult , PyObject , Python , PythonObject , ToPyObject } ;
2+ use futures:: executor;
3+ use futures:: { Future , Async } ;
4+ use std:: cell:: RefCell ;
5+ use std:: sync:: Arc ;
46
5- // Workaround rust-lang/rust#28796
67pub trait Callback : Send {
7- fn call ( self : Box < Self > , py : Python ) -> PyResult < PyObject > ;
8+ fn poll ( & mut self , py : Python ) -> PyResult < Option < PyObject > > ;
9+ fn wait ( & mut self , py : Python ) -> PyResult < PyObject > ;
10+ }
11+
12+ struct FutureData < F , T > {
13+ future : Option < executor:: Spawn < F > > ,
14+ then : Option < T > ,
815}
9- impl < F : Send + for < ' a > FnOnce ( Python < ' a > ) -> PyResult < PyObject > > Callback for F {
10- fn call ( self : Box < Self > , py : Python ) -> PyResult < PyObject > {
11- ( * self ) ( py)
16+
17+ struct NoopUnpark ;
18+ impl executor:: Unpark for NoopUnpark {
19+ fn unpark ( & self ) { }
20+ }
21+
22+ impl < F , T , U > Callback for FutureData < F , T >
23+ where F : Future + Send + ' static ,
24+ T : FnOnce ( Python , Result < F :: Item , F :: Error > ) -> PyResult < U > + Send + ' static ,
25+ U : ToPyObject
26+ {
27+ fn poll ( & mut self , py : Python ) -> PyResult < Option < PyObject > > {
28+ let result = {
29+ let future = self . future . as_mut ( ) . expect ( "Future already completed" ) ;
30+ match future. poll_future ( Arc :: new ( NoopUnpark ) ) {
31+ Ok ( Async :: Ready ( v) ) => Ok ( v) ,
32+ Err ( e) => Err ( e) ,
33+ Ok ( Async :: NotReady ) => return Ok ( None ) ,
34+ }
35+ } ;
36+
37+ self . future = None ;
38+ let then = self . then . take ( ) . unwrap ( ) ;
39+ then ( py, result) . map ( |o| Some ( o. into_py_object ( py) . into_object ( ) ) )
40+ }
41+
42+ fn wait ( & mut self , py : Python ) -> PyResult < PyObject > {
43+ let mut future = self . future . take ( ) . expect ( "Future already completed" ) ;
44+ let result = future. wait_future ( ) ;
45+
46+ let then = self . then . take ( ) . unwrap ( ) ;
47+ then ( py, result) . map ( |o| o. into_py_object ( py) . into_object ( ) )
1248 }
1349}
1450
1551py_class ! ( pub class PyFuture |py| {
16- data callback : RefCell <Option <Box <Callback >>>;
52+ data callback : RefCell <Box <Callback >>;
53+
54+ def poll( & self ) -> PyResult <Option <PyObject >> {
55+ self . callback( py) . borrow_mut( ) . poll( py)
56+ }
1757
1858 def wait( & self ) -> PyResult <PyObject > {
19- let callback = self . callback( py) . borrow_mut( ) . take( ) . expect( "Future already completed" ) ;
20- callback. call( py)
59+ self . callback( py) . borrow_mut( ) . wait( py)
2160 }
2261} ) ;
2362
@@ -27,10 +66,10 @@ impl PyFuture {
2766 T : FnOnce ( Python , Result < F :: Item , F :: Error > ) -> PyResult < U > + Send + ' static ,
2867 U : ToPyObject
2968 {
30- PyFuture :: create_instance ( py, RefCell :: new ( Some ( Box :: new ( move | py : Python | {
31- let result = future. wait ( ) ;
32- then ( py , result ) . map ( |o| o . into_py_object ( py ) . into_object ( ) )
33- } ) ) ) )
69+ PyFuture :: create_instance ( py, RefCell :: new ( Box :: new ( FutureData {
70+ future : Some ( executor :: spawn ( future ) ) ,
71+ then : Some ( then ) ,
72+ } ) ) )
3473 }
3574}
3675
0 commit comments