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));
|
let (interpreter_version, lines) = try!(get_config_from_interpreter(interpreter_path));
|
||||||
if MIN_MINOR <= interpreter_version.minor.unwrap_or(0) &&
|
if MIN_MINOR <= interpreter_version.minor.unwrap_or(0) &&
|
||||||
interpreter_version.major == 3 {
|
interpreter_version.major == 3 {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use quote::Tokens;
|
||||||
|
|
||||||
pub enum MethodProto {
|
pub enum MethodProto {
|
||||||
Len{name: &'static str, proto: &'static str},
|
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},
|
Binary{name: &'static str, arg: &'static str, proto: &'static str},
|
||||||
Ternary{name: &'static str, arg1: &'static str, arg2: &'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 {
|
pub fn eq(&self, name: &str) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
MethodProto::Len{name: n, proto: _} => n == name,
|
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::Binary{name: n, arg: _, proto: _} => n == name,
|
||||||
MethodProto::Ternary{name: n, arg1: _, arg2: _, 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} => {
|
MethodProto::Binary{name: _, arg, proto} => {
|
||||||
let p = syn::Ident::from(proto);
|
let p = syn::Ident::from(proto);
|
||||||
let arg_name = syn::Ident::from(arg);
|
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 {
|
static MAPPING: Proto = Proto {
|
||||||
//py_methods: &[],
|
//py_methods: &[],
|
||||||
methods: &[
|
methods: &[
|
||||||
|
@ -81,8 +96,9 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
|
||||||
impl_protocol("pyo3::class::async::PyObjectProtocolImpl",
|
impl_protocol("pyo3::class::async::PyObjectProtocolImpl",
|
||||||
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
||||||
ImplType::Async =>
|
ImplType::Async =>
|
||||||
impl_protocol("pyo3::class::async::PyAsyncProtocolImpl",
|
impl_proto_impl(ty, impl_items, &ASYNC),
|
||||||
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
ImplType::Mapping =>
|
||||||
|
impl_proto_impl(ty, impl_items, &MAPPING),
|
||||||
ImplType::Buffer =>
|
ImplType::Buffer =>
|
||||||
impl_protocol("pyo3::class::buffer::PyBufferProtocolImpl",
|
impl_protocol("pyo3::class::buffer::PyBufferProtocolImpl",
|
||||||
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
||||||
|
@ -101,8 +117,6 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
|
||||||
ImplType::Number =>
|
ImplType::Number =>
|
||||||
impl_protocol("pyo3::class::number::PyNumberProtocolImpl",
|
impl_protocol("pyo3::class::number::PyNumberProtocolImpl",
|
||||||
path.clone(), ty, impl_items, &NUM_METHODS),
|
path.clone(), ty, impl_items, &NUM_METHODS),
|
||||||
ImplType::Mapping =>
|
|
||||||
impl_proto_impl(ty, impl_items, &MAPPING),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("#[proto] can only be used with protocol trait implementations")
|
panic!("#[proto] can only be used with protocol trait implementations")
|
||||||
|
|
|
@ -9,93 +9,187 @@
|
||||||
use ffi;
|
use ffi;
|
||||||
use err::PyResult;
|
use err::PyResult;
|
||||||
use python::{Python, PythonObject};
|
use python::{Python, PythonObject};
|
||||||
use objects::PyObject;
|
|
||||||
use callback::PyObjectCallbackConverter;
|
use callback::PyObjectCallbackConverter;
|
||||||
use class::NO_METHODS;
|
|
||||||
|
|
||||||
|
|
||||||
/// Awaitable interface
|
/// 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> {
|
pub trait PyAsyncAiterProtocol: PyAsyncProtocol {
|
||||||
Ok(py.None())
|
type Success: ::ToPyObject;
|
||||||
}
|
type Result: Into<PyResult<Self::Success>>;
|
||||||
|
}
|
||||||
|
|
||||||
default fn __aiter__(&self, py: Python) -> PyResult<PyObject> {
|
pub trait PyAsyncAnextProtocol: PyAsyncProtocol {
|
||||||
Ok(py.None())
|
type Success: ::ToPyObject;
|
||||||
}
|
type Result: Into<PyResult<Self::Success>>;
|
||||||
|
}
|
||||||
|
|
||||||
default fn __anext__(&self, py: Python) -> PyResult<PyObject> {
|
pub trait PyAsyncAenterProtocol: PyAsyncProtocol {
|
||||||
Ok(py.None())
|
type Success: ::ToPyObject;
|
||||||
}
|
type Result: Into<PyResult<Self::Success>>;
|
||||||
|
}
|
||||||
|
|
||||||
default fn __aenter__(&self, py: Python) -> PyResult<PyObject> {
|
pub trait PyAsyncAexitProtocol: PyAsyncProtocol {
|
||||||
Ok(py.None())
|
type Success: ::ToPyObject;
|
||||||
}
|
type Result: Into<PyResult<Self::Success>>;
|
||||||
|
|
||||||
default fn __aexit__(&self, py: Python) -> PyResult<PyObject> {
|
|
||||||
Ok(py.None())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait PyAsyncProtocolImpl {
|
pub trait PyAsyncProtocolImpl {
|
||||||
fn methods() -> &'static [&'static str];
|
fn tp_as_async() -> Option<ffi::PyAsyncMethods>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> PyAsyncProtocolImpl for T {
|
impl<T> PyAsyncProtocolImpl for T {
|
||||||
default fn methods() -> &'static [&'static str] {
|
#[inline]
|
||||||
NO_METHODS
|
default fn tp_as_async() -> Option<ffi::PyAsyncMethods> {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ffi::PyAsyncMethods {
|
impl<T> PyAsyncProtocolImpl for T where T: PyAsyncProtocol {
|
||||||
|
#[inline]
|
||||||
/// Construct PyAsyncMethods struct for PyTypeObject.tp_as_async
|
fn tp_as_async() -> Option<ffi::PyAsyncMethods> {
|
||||||
pub fn new<T>() -> Option<ffi::PyAsyncMethods>
|
Some(ffi::PyAsyncMethods {
|
||||||
where T: PyAsyncProtocol + PyAsyncProtocolImpl + PythonObject
|
am_await: Self::am_await(),
|
||||||
{
|
am_aiter: Self::am_aiter(),
|
||||||
let methods = T::methods();
|
am_anext: Self::am_anext(),
|
||||||
if methods.is_empty() {
|
})
|
||||||
return None
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut meth: ffi::PyAsyncMethods = ffi::PyAsyncMethods_INIT;
|
|
||||||
|
trait PyAsyncAwaitProtocolImpl {
|
||||||
for name in methods {
|
fn am_await() -> Option<ffi::unaryfunc>;
|
||||||
match name {
|
}
|
||||||
&"__await__" => {
|
|
||||||
meth.am_await = py_unary_func!(
|
impl<T> PyAsyncAwaitProtocolImpl for T
|
||||||
PyAsyncProtocol, T::__await__, PyObjectCallbackConverter);
|
where T: PyAsyncProtocol
|
||||||
},
|
{
|
||||||
&"__aiter__" => {
|
#[inline]
|
||||||
meth.am_aiter = py_unary_func!(
|
default fn am_await() -> Option<ffi::unaryfunc> {
|
||||||
PyAsyncProtocol, T::__aiter__, PyObjectCallbackConverter);
|
None
|
||||||
},
|
}
|
||||||
&"__anext__" => {
|
}
|
||||||
meth.am_anext = py_unary_func!(
|
|
||||||
PyAsyncProtocol, T::__anext__, PyObjectCallbackConverter);
|
impl<T> PyAsyncAwaitProtocolImpl for T
|
||||||
},
|
where T: PyAsyncAwaitProtocol
|
||||||
_ => unreachable!(),
|
{
|
||||||
}
|
#[inline]
|
||||||
}
|
fn am_await() -> Option<ffi::unaryfunc> {
|
||||||
|
py_unary_func_!(PyAsyncAwaitProtocol, T::__await__, PyObjectCallbackConverter)
|
||||||
Some(meth)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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]
|
#[macro_export]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
macro_rules! py_len_func {
|
macro_rules! py_len_func {
|
||||||
|
|
|
@ -16,21 +16,18 @@ use conversion::{ToPyObject, FromPyObject};
|
||||||
/// Mapping interface
|
/// Mapping interface
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait PyMappingProtocol: PythonObject {
|
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
|
fn __len__(&self, py: Python)
|
||||||
where Self: PyMappingGetItemProtocol
|
-> Self::Result where Self: PyMappingLenProtocol { unimplemented!() }
|
||||||
{ unimplemented!() }
|
|
||||||
|
|
||||||
fn __setitem__(&self, py: Python, key: Self::Key, value: Self::Value) -> Self::Result
|
fn __getitem__(&self, py: Python, key: Self::Key)
|
||||||
where Self: PyMappingSetItemProtocol
|
-> Self::Result where Self: PyMappingGetItemProtocol { unimplemented!() }
|
||||||
{ unimplemented!() }
|
|
||||||
|
|
||||||
fn __delitem__(&self, py: Python, key: Self::Key) -> Self::Result
|
fn __setitem__(&self, py: Python, key: Self::Key, value: Self::Value)
|
||||||
where Self: PyMappingDelItemProtocol
|
-> Self::Result where Self: PyMappingSetItemProtocol { unimplemented!() }
|
||||||
{ 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
|
// 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;
|
static mut ASYNC_METHODS: ffi::PyAsyncMethods = ffi::PyAsyncMethods_INIT;
|
||||||
*(unsafe { &mut ASYNC_METHODS }) = meth;
|
*(unsafe { &mut ASYNC_METHODS }) = meth;
|
||||||
type_object.tp_as_async = unsafe { &mut ASYNC_METHODS };
|
type_object.tp_as_async = unsafe { &mut ASYNC_METHODS };
|
||||||
|
|
Loading…
Reference in New Issue