cpython-async: expose Rust Future to Python

Summary:
Add a `PyFuture<F>` type that can be used as return type in binding function.
It converts Rust Future to a Python object with an `await` method so Python
can access the value stored in the future.

Unlike `TStream`, it's currently only designed to support Rust->Python one
way conversion so it looks simpler.

Reviewed By: kulshrax

Differential Revision: D23799644

fbshipit-source-id: da4a322527ad9bb4c2dbaa1c302147b784d1ee41
This commit is contained in:
Jun Wu 2020-09-21 13:26:13 -07:00 committed by Facebook GitHub Bot
parent 41b200c8d8
commit 7f1c05dd74
2 changed files with 53 additions and 0 deletions

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
use cpython_ext::cpython::*;
use cpython_ext::ResultPyErrExt;
use futures::future::BoxFuture;
use futures::future::Future;
use futures::future::FutureExt;
use std::cell::RefCell;
// Type to make Python able to reason about a Rust future.
//
// Unlike TStream, it does not support typed lossless Python -> Rust conversion.
py_class!(pub class future |py| {
data inner: RefCell<Option<BoxFuture<'static, PyResult<PyObject>>>>;
/// Resolve the future and return the resolved object.
def wait(&self) -> PyResult<PyObject> {
let mut inner = None;
std::mem::swap(&mut inner, &mut self.inner(py).borrow_mut());
match inner {
Some(future) => async_runtime::block_on_future(future),
None => Err(PyErr::new::<exc::ValueError, _>(py, "future was already waited")),
}
}
});
impl future {
/// Convert Rust Future to Python object.
pub fn new<T, E, F>(py: Python, f: F) -> PyResult<Self>
where
T: ToPyObject,
E: Into<anyhow::Error>,
F: Future<Output = Result<T, E>> + Send + 'static,
{
let future = f.map(|v| {
let gil = Python::acquire_gil();
let py = gil.python();
v.map_pyerr(py).map(|v| v.into_py_object(py).into_object())
});
Self::create_instance(py, RefCell::new(Some(Box::pin(future))))
}
}

View File

@ -11,9 +11,14 @@
//!
//! The `TStream` type provides easy, and lossless conversion between
//! Rust `Stream` and Python objects.
//!
//! The `PyFuture` type provides a way to export Rust `Future` to
//! Python.
mod future;
mod stream;
pub use future::future as PyFuture;
pub use stream::TStream;
// Used by py_stream_class!.