refactor PyAsyncProtocol
This commit is contained in:
parent
7a75d3e652
commit
9759cf7177
2
build.rs
2
build.rs
|
@ -268,7 +268,7 @@ fn find_interpreter_and_get_config() -> Result<(PythonVersion, String, Vec<Strin
|
|||
}
|
||||
|
||||
{
|
||||
let interpreter_path = "python";
|
||||
let interpreter_path = "python3";
|
||||
let (interpreter_version, lines) = try!(get_config_from_interpreter(interpreter_path));
|
||||
if MIN_MINOR <= interpreter_version.minor.unwrap_or(0) &&
|
||||
interpreter_version.major == 3 {
|
||||
|
|
|
@ -6,7 +6,7 @@ use quote::Tokens;
|
|||
|
||||
pub enum MethodProto {
|
||||
Len{name: &'static str, proto: &'static str},
|
||||
//Unary(&'static str),
|
||||
Unary{name: &'static str, proto: &'static str},
|
||||
Binary{name: &'static str, arg: &'static str, proto: &'static str},
|
||||
Ternary{name: &'static str, arg1: &'static str, arg2: &'static str, proto: &'static str},
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ impl MethodProto {
|
|||
pub fn eq(&self, name: &str) -> bool {
|
||||
match *self {
|
||||
MethodProto::Len{name: n, proto: _} => n == name,
|
||||
//MethodProto::Unary(n) => n == name,
|
||||
MethodProto::Unary{name: n, proto: _} => n == name,
|
||||
MethodProto::Binary{name: n, arg: _, proto: _} => n == name,
|
||||
MethodProto::Ternary{name: n, arg1: _, arg2: _, proto: _} => n == name,
|
||||
}
|
||||
|
@ -38,6 +38,17 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
|
|||
}
|
||||
}
|
||||
},
|
||||
MethodProto::Unary{name: _, proto} => {
|
||||
let p = syn::Ident::from(proto);
|
||||
let succ = get_res_success(ty);
|
||||
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type Success = #succ;
|
||||
type Result = #ty;
|
||||
}
|
||||
}
|
||||
},
|
||||
MethodProto::Binary{name: _, arg, proto} => {
|
||||
let p = syn::Ident::from(proto);
|
||||
let arg_name = syn::Ident::from(arg);
|
||||
|
|
|
@ -37,6 +37,21 @@ static NUM_METHODS: Methods = Methods {
|
|||
],
|
||||
};
|
||||
|
||||
static ASYNC: Proto = Proto {
|
||||
//py_methods: &[],
|
||||
methods: &[
|
||||
MethodProto::Unary{
|
||||
name: "__await__",
|
||||
proto: "class::mapping::PyAsyncAwaitProtocol"},
|
||||
MethodProto::Unary{
|
||||
name: "__aiter__",
|
||||
proto: "class::mapping::PyAsyncAiterProtocol"},
|
||||
MethodProto::Unary{
|
||||
name: "__anext__",
|
||||
proto: "class::mapping::PyAsyncAnextProtocol"},
|
||||
],
|
||||
};
|
||||
|
||||
static MAPPING: Proto = Proto {
|
||||
//py_methods: &[],
|
||||
methods: &[
|
||||
|
@ -81,8 +96,9 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
|
|||
impl_protocol("pyo3::class::async::PyObjectProtocolImpl",
|
||||
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
||||
ImplType::Async =>
|
||||
impl_protocol("pyo3::class::async::PyAsyncProtocolImpl",
|
||||
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
||||
impl_proto_impl(ty, impl_items, &ASYNC),
|
||||
ImplType::Mapping =>
|
||||
impl_proto_impl(ty, impl_items, &MAPPING),
|
||||
ImplType::Buffer =>
|
||||
impl_protocol("pyo3::class::buffer::PyBufferProtocolImpl",
|
||||
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
||||
|
@ -101,8 +117,6 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
|
|||
ImplType::Number =>
|
||||
impl_protocol("pyo3::class::number::PyNumberProtocolImpl",
|
||||
path.clone(), ty, impl_items, &NUM_METHODS),
|
||||
ImplType::Mapping =>
|
||||
impl_proto_impl(ty, impl_items, &MAPPING),
|
||||
}
|
||||
} else {
|
||||
panic!("#[proto] can only be used with protocol trait implementations")
|
||||
|
|
|
@ -9,93 +9,187 @@
|
|||
use ffi;
|
||||
use err::PyResult;
|
||||
use python::{Python, PythonObject};
|
||||
use objects::PyObject;
|
||||
use callback::PyObjectCallbackConverter;
|
||||
use class::NO_METHODS;
|
||||
|
||||
|
||||
/// Awaitable interface
|
||||
pub trait PyAsyncProtocol {
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyAsyncProtocol: PythonObject {
|
||||
|
||||
fn __await__(&self, py: Python) -> PyResult<PyObject>;
|
||||
fn __await__(&self, py: Python)
|
||||
-> Self::Result where Self: PyAsyncAwaitProtocol { unimplemented!() }
|
||||
|
||||
fn __aiter__(&self, py: Python) -> PyResult<PyObject>;
|
||||
fn __aiter__(&self, py: Python)
|
||||
-> Self::Result where Self: PyAsyncAiterProtocol { unimplemented!() }
|
||||
|
||||
fn __anext__(&self, py: Python) -> PyResult<PyObject>;
|
||||
fn __anext__(&self, py: Python)
|
||||
-> Self::Result where Self: PyAsyncAnextProtocol { unimplemented!() }
|
||||
|
||||
fn __aenter__(&self, py: Python) -> PyResult<PyObject>;
|
||||
fn __aenter__(&self, py: Python)
|
||||
-> Self::Result where Self: PyAsyncAenterProtocol { unimplemented!() }
|
||||
|
||||
fn __aexit__(&self, py: Python) -> PyResult<PyObject>;
|
||||
fn __aexit__(&self, py: Python)
|
||||
-> Self::Result where Self: PyAsyncAexitProtocol { unimplemented!() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
impl<P> PyAsyncProtocol for P {
|
||||
pub trait PyAsyncAwaitProtocol: PyAsyncProtocol {
|
||||
type Success: ::ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
default fn __await__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Ok(py.None())
|
||||
}
|
||||
pub trait PyAsyncAiterProtocol: PyAsyncProtocol {
|
||||
type Success: ::ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
default fn __aiter__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Ok(py.None())
|
||||
}
|
||||
pub trait PyAsyncAnextProtocol: PyAsyncProtocol {
|
||||
type Success: ::ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
default fn __anext__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Ok(py.None())
|
||||
}
|
||||
pub trait PyAsyncAenterProtocol: PyAsyncProtocol {
|
||||
type Success: ::ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
default fn __aenter__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Ok(py.None())
|
||||
}
|
||||
|
||||
default fn __aexit__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Ok(py.None())
|
||||
}
|
||||
pub trait PyAsyncAexitProtocol: PyAsyncProtocol {
|
||||
type Success: ::ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyAsyncProtocolImpl {
|
||||
fn methods() -> &'static [&'static str];
|
||||
fn tp_as_async() -> Option<ffi::PyAsyncMethods>;
|
||||
}
|
||||
|
||||
impl<T> PyAsyncProtocolImpl for T {
|
||||
default fn methods() -> &'static [&'static str] {
|
||||
NO_METHODS
|
||||
#[inline]
|
||||
default fn tp_as_async() -> Option<ffi::PyAsyncMethods> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl ffi::PyAsyncMethods {
|
||||
|
||||
/// Construct PyAsyncMethods struct for PyTypeObject.tp_as_async
|
||||
pub fn new<T>() -> Option<ffi::PyAsyncMethods>
|
||||
where T: PyAsyncProtocol + PyAsyncProtocolImpl + PythonObject
|
||||
{
|
||||
let methods = T::methods();
|
||||
if methods.is_empty() {
|
||||
return None
|
||||
}
|
||||
|
||||
let mut meth: ffi::PyAsyncMethods = ffi::PyAsyncMethods_INIT;
|
||||
|
||||
for name in methods {
|
||||
match name {
|
||||
&"__await__" => {
|
||||
meth.am_await = py_unary_func!(
|
||||
PyAsyncProtocol, T::__await__, PyObjectCallbackConverter);
|
||||
},
|
||||
&"__aiter__" => {
|
||||
meth.am_aiter = py_unary_func!(
|
||||
PyAsyncProtocol, T::__aiter__, PyObjectCallbackConverter);
|
||||
},
|
||||
&"__anext__" => {
|
||||
meth.am_anext = py_unary_func!(
|
||||
PyAsyncProtocol, T::__anext__, PyObjectCallbackConverter);
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
Some(meth)
|
||||
impl<T> PyAsyncProtocolImpl for T where T: PyAsyncProtocol {
|
||||
#[inline]
|
||||
fn tp_as_async() -> Option<ffi::PyAsyncMethods> {
|
||||
Some(ffi::PyAsyncMethods {
|
||||
am_await: Self::am_await(),
|
||||
am_aiter: Self::am_aiter(),
|
||||
am_anext: Self::am_anext(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait PyAsyncAwaitProtocolImpl {
|
||||
fn am_await() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAwaitProtocolImpl for T
|
||||
where T: PyAsyncProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn am_await() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAwaitProtocolImpl for T
|
||||
where T: PyAsyncAwaitProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn am_await() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func_!(PyAsyncAwaitProtocol, T::__await__, PyObjectCallbackConverter)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyAsyncAiterProtocolImpl {
|
||||
fn am_aiter() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAiterProtocolImpl for T
|
||||
where T: PyAsyncProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn am_aiter() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAiterProtocolImpl for T
|
||||
where T: PyAsyncAiterProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn am_aiter() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func_!(PyAsyncAiterProtocol, T::__aiter__, PyObjectCallbackConverter)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyAsyncAnextProtocolImpl {
|
||||
fn am_anext() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAnextProtocolImpl for T
|
||||
where T: PyAsyncProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn am_anext() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAnextProtocolImpl for T
|
||||
where T: PyAsyncAnextProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn am_anext() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func_!(PyAsyncAnextProtocol, T::__anext__, PyObjectCallbackConverter)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyAsyncAenterProtocolImpl {
|
||||
fn am_aenter() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAenterProtocolImpl for T
|
||||
where T: PyAsyncProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn am_aenter() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAenterProtocolImpl for T
|
||||
where T: PyAsyncAenterProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn am_aenter() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func_!(PyAsyncAenterProtocol, T::__aenter__, PyObjectCallbackConverter)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyAsyncAexitProtocolImpl {
|
||||
fn am_aexit() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAexitProtocolImpl for T
|
||||
where T: PyAsyncProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn am_aexit() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAexitProtocolImpl for T
|
||||
where T: PyAsyncAexitProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn am_aexit() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func_!(PyAsyncAexitProtocol, T::__aexit__, PyObjectCallbackConverter)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,26 @@ macro_rules! py_unary_func {
|
|||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_unary_func_ {
|
||||
($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject)
|
||||
-> *mut $crate::ffi::PyObject
|
||||
where T: $trait
|
||||
{
|
||||
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
|
||||
$crate::callback::handle_callback(LOCATION, $conv, |py| {
|
||||
let slf = $crate::PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<T>();
|
||||
let ret = slf.$f(py).into();
|
||||
$crate::PyDrop::release_ref(slf, py);
|
||||
ret
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_len_func {
|
||||
|
|
|
@ -16,21 +16,18 @@ use conversion::{ToPyObject, FromPyObject};
|
|||
/// Mapping interface
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyMappingProtocol: PythonObject {
|
||||
fn __len__(&self, py: Python) -> Self::Result
|
||||
where Self: PyMappingLenProtocol
|
||||
{ unimplemented!() }
|
||||
|
||||
fn __getitem__(&self, py: Python, key: Self::Key) -> Self::Result
|
||||
where Self: PyMappingGetItemProtocol
|
||||
{ unimplemented!() }
|
||||
fn __len__(&self, py: Python)
|
||||
-> Self::Result where Self: PyMappingLenProtocol { unimplemented!() }
|
||||
|
||||
fn __setitem__(&self, py: Python, key: Self::Key, value: Self::Value) -> Self::Result
|
||||
where Self: PyMappingSetItemProtocol
|
||||
{ unimplemented!() }
|
||||
fn __getitem__(&self, py: Python, key: Self::Key)
|
||||
-> Self::Result where Self: PyMappingGetItemProtocol { unimplemented!() }
|
||||
|
||||
fn __delitem__(&self, py: Python, key: Self::Key) -> Self::Result
|
||||
where Self: PyMappingDelItemProtocol
|
||||
{ unimplemented!() }
|
||||
fn __setitem__(&self, py: Python, key: Self::Key, value: Self::Value)
|
||||
-> Self::Result where Self: PyMappingSetItemProtocol { unimplemented!() }
|
||||
|
||||
fn __delitem__(&self, py: Python, key: Self::Key)
|
||||
-> Self::Result where Self: PyMappingDelItemProtocol { unimplemented!() }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ pub fn initialize_type<T>(py: Python, module_name: Option<&str>,
|
|||
}
|
||||
|
||||
// async methods
|
||||
if let Some(meth) = ffi::PyAsyncMethods::new::<T>() {
|
||||
if let Some(meth) = <T as class::async::PyAsyncProtocolImpl>::tp_as_async() {
|
||||
static mut ASYNC_METHODS: ffi::PyAsyncMethods = ffi::PyAsyncMethods_INIT;
|
||||
*(unsafe { &mut ASYNC_METHODS }) = meth;
|
||||
type_object.tp_as_async = unsafe { &mut ASYNC_METHODS };
|
||||
|
|
Loading…
Reference in a new issue