Merge pull request #1093 from kngwyu/iterator-example
Improve lifetime insertions for #[pyproto]
This commit is contained in:
commit
b17d4fffe2
|
@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||||
[#1058](https://github.com/PyO3/pyo3/pull/1058). [#1059](https://github.com/PyO3/pyo3/pull/1059)
|
[#1058](https://github.com/PyO3/pyo3/pull/1058). [#1059](https://github.com/PyO3/pyo3/pull/1059)
|
||||||
- Allows `&Self` as a `#[pymethods]` argument again. [#1071](https://github.com/PyO3/pyo3/pull/1071)
|
- Allows `&Self` as a `#[pymethods]` argument again. [#1071](https://github.com/PyO3/pyo3/pull/1071)
|
||||||
- Fix best-effort build against PyPy 3.6. #[1092](https://github.com/PyO3/pyo3/pull/1092)
|
- Fix best-effort build against PyPy 3.6. #[1092](https://github.com/PyO3/pyo3/pull/1092)
|
||||||
|
- Improve lifetime elision in `#[pyproto]`. [#1093](https://github.com/PyO3/pyo3/pull/1093)
|
||||||
|
|
||||||
## [0.11.1] - 2020-06-30
|
## [0.11.1] - 2020-06-30
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -923,8 +923,8 @@ struct MyIterator {
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PyIterProtocol for MyIterator {
|
impl PyIterProtocol for MyIterator {
|
||||||
fn __iter__(slf: PyRef<Self>) -> Py<MyIterator> {
|
fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
|
||||||
slf.into()
|
slf
|
||||||
}
|
}
|
||||||
fn __next__(mut slf: PyRefMut<Self>) -> Option<PyObject> {
|
fn __next__(mut slf: PyRefMut<Self>) -> Option<PyObject> {
|
||||||
slf.iter.next()
|
slf.iter.next()
|
||||||
|
@ -948,8 +948,8 @@ struct Iter {
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PyIterProtocol for Iter {
|
impl PyIterProtocol for Iter {
|
||||||
fn __iter__(slf: PyRefMut<Self>) -> Py<Iter> {
|
fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
|
||||||
slf.into()
|
slf
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __next__(mut slf: PyRefMut<Self>) -> Option<usize> {
|
fn __next__(mut slf: PyRefMut<Self>) -> Option<usize> {
|
||||||
|
@ -964,7 +964,7 @@ struct Container {
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PyIterProtocol for Container {
|
impl PyIterProtocol for Container {
|
||||||
fn __iter__(slf: PyRefMut<Self>) -> PyResult<Py<Iter>> {
|
fn __iter__(slf: PyRef<Self>) -> PyResult<Py<Iter>> {
|
||||||
let iter = Iter {
|
let iter = Iter {
|
||||||
inner: slf.iter.clone().into_iter(),
|
inner: slf.iter.clone().into_iter(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
use crate::func::MethodProto;
|
use crate::proto_method::MethodProto;
|
||||||
|
|
||||||
/// Predicates for `#[pyproto]`.
|
/// Predicates for `#[pyproto]`.
|
||||||
pub struct Proto {
|
pub struct Proto {
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
#![recursion_limit = "1024"]
|
#![recursion_limit = "1024"]
|
||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod func;
|
|
||||||
mod konst;
|
mod konst;
|
||||||
mod method;
|
mod method;
|
||||||
mod module;
|
mod module;
|
||||||
|
mod proto_method;
|
||||||
mod pyclass;
|
mod pyclass;
|
||||||
mod pyfunction;
|
mod pyfunction;
|
||||||
mod pyimpl;
|
mod pyimpl;
|
||||||
|
|
|
@ -6,7 +6,6 @@ use syn::Token;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// Add lifetime support for args with Rptr
|
// Add lifetime support for args with Rptr
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MethodProto {
|
pub enum MethodProto {
|
||||||
Free {
|
Free {
|
||||||
|
@ -77,7 +76,11 @@ pub(crate) fn impl_method_proto(
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let ret_ty = match &sig.output {
|
let ret_ty = match &sig.output {
|
||||||
syn::ReturnType::Default => quote! { () },
|
syn::ReturnType::Default => quote! { () },
|
||||||
syn::ReturnType::Type(_, ty) => ty.to_token_stream(),
|
syn::ReturnType::Type(_, ty) => {
|
||||||
|
let mut ty = ty.clone();
|
||||||
|
insert_lifetime(&mut ty);
|
||||||
|
ty.to_token_stream()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match *meth {
|
match *meth {
|
||||||
|
@ -106,22 +109,7 @@ pub(crate) fn impl_method_proto(
|
||||||
let p: syn::Path = syn::parse_str(proto).unwrap();
|
let p: syn::Path = syn::parse_str(proto).unwrap();
|
||||||
|
|
||||||
let slf_name = syn::Ident::new(arg, Span::call_site());
|
let slf_name = syn::Ident::new(arg, Span::call_site());
|
||||||
let mut slf_ty = get_arg_ty(sig, 0);
|
let slf_ty = get_arg_ty(sig, 0);
|
||||||
|
|
||||||
// update the type if no lifetime was given:
|
|
||||||
// PyRef<Self> --> PyRef<'p, Self>
|
|
||||||
if let syn::Type::Path(ref mut path) = slf_ty {
|
|
||||||
if let syn::PathArguments::AngleBracketed(ref mut args) =
|
|
||||||
path.path.segments[0].arguments
|
|
||||||
{
|
|
||||||
if let syn::GenericArgument::Lifetime(_) = args.args[0] {
|
|
||||||
} else {
|
|
||||||
let lt = syn::parse_quote! {'p};
|
|
||||||
args.args.insert(0, lt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let tmp: syn::ItemFn = syn::parse_quote! {
|
let tmp: syn::ItemFn = syn::parse_quote! {
|
||||||
fn test(&self) -> <#cls as #p<'p>>::Result {}
|
fn test(&self) -> <#cls as #p<'p>>::Result {}
|
||||||
};
|
};
|
||||||
|
@ -336,40 +324,64 @@ pub(crate) fn impl_method_proto(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: better arg ty detection
|
/// Some hacks for arguments: get `T` from `Option<T>` and insert lifetime
|
||||||
fn get_arg_ty(sig: &syn::Signature, idx: usize) -> syn::Type {
|
fn get_arg_ty(sig: &syn::Signature, idx: usize) -> syn::Type {
|
||||||
let mut ty = match sig.inputs[idx] {
|
fn get_option_ty(path: &syn::Path) -> Option<syn::Type> {
|
||||||
syn::FnArg::Typed(ref cap) => {
|
let seg = path.segments.last()?;
|
||||||
match *cap.ty {
|
if seg.ident == "Option" {
|
||||||
syn::Type::Path(ref ty) => {
|
if let syn::PathArguments::AngleBracketed(ref data) = seg.arguments {
|
||||||
// use only last path segment for Option<>
|
if let Some(syn::GenericArgument::Type(ref ty)) = data.args.last() {
|
||||||
let seg = ty.path.segments.last().unwrap().clone();
|
return Some(ty.to_owned());
|
||||||
if seg.ident == "Option" {
|
|
||||||
if let syn::PathArguments::AngleBracketed(ref data) = seg.arguments {
|
|
||||||
if let Some(pair) = data.args.last() {
|
|
||||||
match pair {
|
|
||||||
syn::GenericArgument::Type(ref ty) => return ty.clone(),
|
|
||||||
_ => panic!("Option only accepted for concrete types"),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*cap.ty.clone()
|
|
||||||
}
|
}
|
||||||
_ => *cap.ty.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("fn arg type is not supported"),
|
None
|
||||||
};
|
|
||||||
|
|
||||||
// Add a lifetime if there is none
|
|
||||||
if let syn::Type::Reference(ref mut r) = ty {
|
|
||||||
r.lifetime.get_or_insert(syn::parse_quote! {'p});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut ty = match &sig.inputs[idx] {
|
||||||
|
syn::FnArg::Typed(ref cap) => match &*cap.ty {
|
||||||
|
// For `Option<T>`, we use `T` as an associated type for the protocol.
|
||||||
|
syn::Type::Path(ref ty) => get_option_ty(&ty.path).unwrap_or_else(|| *cap.ty.clone()),
|
||||||
|
_ => *cap.ty.clone(),
|
||||||
|
},
|
||||||
|
ty => panic!("Unsupported argument type: {:?}", ty),
|
||||||
|
};
|
||||||
|
insert_lifetime(&mut ty);
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert lifetime `'p` to `PyRef<Self>` or references (e.g., `&PyType`).
|
||||||
|
fn insert_lifetime(ty: &mut syn::Type) {
|
||||||
|
fn insert_lifetime_for_path(path: &mut syn::TypePath) {
|
||||||
|
if let Some(seg) = path.path.segments.last_mut() {
|
||||||
|
if let syn::PathArguments::AngleBracketed(ref mut args) = seg.arguments {
|
||||||
|
let mut has_lifetime = false;
|
||||||
|
for arg in &mut args.args {
|
||||||
|
match arg {
|
||||||
|
// Insert `'p` recursively for `Option<PyRef<Self>>` or so.
|
||||||
|
syn::GenericArgument::Type(ref mut ty) => insert_lifetime(ty),
|
||||||
|
syn::GenericArgument::Lifetime(_) => has_lifetime = true,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Insert lifetime to PyRef (i.e., PyRef<Self> -> PyRef<'p, Self>)
|
||||||
|
if !has_lifetime && (seg.ident == "PyRef" || seg.ident == "PyRefMut") {
|
||||||
|
args.args.insert(0, syn::parse_quote! {'p});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match ty {
|
||||||
|
syn::Type::Reference(ref mut r) => {
|
||||||
|
r.lifetime.get_or_insert(syn::parse_quote! {'p});
|
||||||
|
insert_lifetime(&mut *r.elem);
|
||||||
|
}
|
||||||
|
syn::Type::Path(ref mut path) => insert_lifetime_for_path(path),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn extract_decl(spec: syn::Item) -> syn::Signature {
|
fn extract_decl(spec: syn::Item) -> syn::Signature {
|
||||||
match spec {
|
match spec {
|
||||||
syn::Item::Fn(f) => f.sig,
|
syn::Item::Fn(f) => f.sig,
|
|
@ -1,8 +1,8 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
use crate::defs;
|
use crate::defs;
|
||||||
use crate::func::impl_method_proto;
|
|
||||||
use crate::method::{FnSpec, FnType};
|
use crate::method::{FnSpec, FnType};
|
||||||
|
use crate::proto_method::impl_method_proto;
|
||||||
use crate::pymethod;
|
use crate::pymethod;
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
|
@ -51,12 +51,12 @@ struct Iterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl<'p> PyIterProtocol for Iterator {
|
impl PyIterProtocol for Iterator {
|
||||||
fn __iter__(slf: PyRef<'p, Self>) -> Py<Iterator> {
|
fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
|
||||||
slf.into()
|
slf
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __next__(mut slf: PyRefMut<'p, Self>) -> Option<i32> {
|
fn __next__(mut slf: PyRefMut<Self>) -> Option<i32> {
|
||||||
slf.iter.next()
|
slf.iter.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ fn iterator() {
|
||||||
struct StringMethods {}
|
struct StringMethods {}
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl<'p> PyObjectProtocol<'p> for StringMethods {
|
impl PyObjectProtocol for StringMethods {
|
||||||
fn __str__(&self) -> &'static str {
|
fn __str__(&self) -> &'static str {
|
||||||
"str"
|
"str"
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,7 @@ struct SetItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PyMappingProtocol<'a> for SetItem {
|
impl PyMappingProtocol for SetItem {
|
||||||
fn __setitem__(&mut self, key: i32, val: i32) {
|
fn __setitem__(&mut self, key: i32, val: i32) {
|
||||||
self.key = key;
|
self.key = key;
|
||||||
self.val = val;
|
self.val = val;
|
||||||
|
@ -362,16 +362,16 @@ struct ContextManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl<'p> PyContextProtocol<'p> for ContextManager {
|
impl PyContextProtocol for ContextManager {
|
||||||
fn __enter__(&mut self) -> i32 {
|
fn __enter__(&mut self) -> i32 {
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __exit__(
|
fn __exit__(
|
||||||
&mut self,
|
&mut self,
|
||||||
ty: Option<&'p PyType>,
|
ty: Option<&PyType>,
|
||||||
_value: Option<&'p PyAny>,
|
_value: Option<&PyAny>,
|
||||||
_traceback: Option<&'p PyAny>,
|
_traceback: Option<&PyAny>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
self.exit_called = true;
|
self.exit_called = true;
|
||||||
|
@ -564,14 +564,14 @@ impl OnceFuture {
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PyAsyncProtocol for OnceFuture {
|
impl PyAsyncProtocol for OnceFuture {
|
||||||
fn __await__(slf: PyRef<'p, Self>) -> PyRef<'p, Self> {
|
fn __await__(slf: PyRef<Self>) -> PyRef<Self> {
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PyIterProtocol for OnceFuture {
|
impl PyIterProtocol for OnceFuture {
|
||||||
fn __iter__(slf: PyRef<'p, Self>) -> PyRef<'p, Self> {
|
fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
fn __next__(mut slf: PyRefMut<Self>) -> Option<PyObject> {
|
fn __next__(mut slf: PyRefMut<Self>) -> Option<PyObject> {
|
||||||
|
@ -632,14 +632,14 @@ impl DescrCounter {
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PyDescrProtocol for DescrCounter {
|
impl PyDescrProtocol for DescrCounter {
|
||||||
fn __get__(
|
fn __get__(
|
||||||
mut slf: PyRefMut<'p, Self>,
|
mut slf: PyRefMut<Self>,
|
||||||
_instance: &PyAny,
|
_instance: &PyAny,
|
||||||
_owner: Option<&'p PyType>,
|
_owner: Option<&PyType>,
|
||||||
) -> PyRefMut<'p, Self> {
|
) -> PyRefMut<Self> {
|
||||||
slf.count += 1;
|
slf.count += 1;
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
fn __set__(_slf: PyRef<'p, Self>, _instance: &PyAny, mut new_value: PyRefMut<'p, Self>) {
|
fn __set__(_slf: PyRef<Self>, _instance: &PyAny, mut new_value: PyRefMut<Self>) {
|
||||||
new_value.count = _slf.count;
|
new_value.count = _slf.count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue