diff --git a/pyo3-derive-backend/src/method.rs b/pyo3-derive-backend/src/method.rs index bc0bca0c..3bea10af 100644 --- a/pyo3-derive-backend/src/method.rs +++ b/pyo3-derive-backend/src/method.rs @@ -27,35 +27,7 @@ pub enum FnType { FnCall, FnClass, FnStatic, - PySelf(PySelfType), -} - -/// For fn(slf: &PyRef) support -#[derive(Clone, Copy, PartialEq, Debug)] -pub enum PySelfType { - Py, - PyRef, - PyRefMut, -} - -impl PySelfType { - fn from_args<'a>(args: &[FnArg<'a>]) -> Option { - let arg = args.iter().next()?; - let path = match arg.ty { - syn::Type::Path(p) => p, - _ => return None, - }; - let last_seg = match path.path.segments.last()? { - syn::punctuated::Pair::Punctuated(t, _) => t, - syn::punctuated::Pair::End(t) => t, - }; - match &*last_seg.ident.to_string() { - "Py" => Some(PySelfType::Py), - "PyRef" => Some(PySelfType::PyRef), - "PyRefMut" => Some(PySelfType::PyRefMut), - _ => None, - } - } + PySelf(syn::Type), } #[derive(Clone, PartialEq, Debug)] @@ -148,14 +120,10 @@ impl<'a> FnSpec<'a> { let ty = get_return_info(&sig.decl.output); if fn_type == FnType::Fn && !has_self { - if let Some(pyslf) = PySelfType::from_args(&arguments) { - fn_type = FnType::PySelf(pyslf); - arguments.remove(0); - } else { - panic!( - "Static method needs an attribute #[staticmethod] or PyRef/PyRefMut as the 1st arg" - ); + if arguments.len() == 0 { + panic!("Static method needs an attribute #[staticmethod]"); } + fn_type = FnType::PySelf(arguments.remove(0).ty.to_owned()); } Ok(FnSpec { diff --git a/pyo3-derive-backend/src/pymethod.rs b/pyo3-derive-backend/src/pymethod.rs index 5a7b6558..4cbeaf76 100644 --- a/pyo3-derive-backend/src/pymethod.rs +++ b/pyo3-derive-backend/src/pymethod.rs @@ -1,6 +1,6 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::method::{FnArg, FnSpec, FnType, PySelfType}; +use crate::method::{FnArg, FnSpec, FnType}; use crate::utils; use proc_macro2::{Span, TokenStream}; use quote::quote; @@ -18,11 +18,11 @@ pub fn gen_py_method( match spec.tp { FnType::Fn => impl_py_method_def(name, doc, &spec, &impl_wrap(cls, name, &spec, true)), - FnType::PySelf(pyslf) => impl_py_method_def( + FnType::PySelf(ref self_ty) => impl_py_method_def( name, doc, &spec, - &impl_wrap_pyslf(cls, name, &spec, pyslf, true), + &impl_wrap_pyslf(cls, name, &spec, self_ty, true), ), FnType::FnNew => impl_py_method_def_new(name, doc, &impl_wrap_new(cls, name, &spec)), FnType::FnInit => impl_py_method_def_init(name, doc, &impl_wrap_init(cls, name, &spec)), @@ -55,7 +55,7 @@ pub fn impl_wrap( ) -> TokenStream { let body = impl_call(cls, name, &spec); let slf = quote! { - let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf); + let _slf: &mut #cls = pyo3::FromPyPointer::from_borrowed_ptr(_py, _slf); }; impl_wrap_common(cls, name, spec, noargs, slf, body) } @@ -64,23 +64,15 @@ pub fn impl_wrap_pyslf( cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>, - slftype: PySelfType, + self_ty: &syn::Type, noargs: bool, ) -> TokenStream { let names = get_arg_names(spec); let body = quote! { #cls::#name(_slf, #(#names),*) }; - let slf = match slftype { - PySelfType::Py => quote! { - let _slf = pyo3::Py::<#cls>::from_borrowed_ptr(_slf); - }, - PySelfType::PyRef => quote! { - let _slf = pyo3::PyRef::<#cls>::from_borrowed_ptr(_py, _slf); - }, - PySelfType::PyRefMut => quote! { - let _slf = pyo3::PyRefMut::<#cls>::from_borrowed_ptr(_py, _slf); - }, + let slf = quote! { + let _slf: #self_ty = pyo3::FromPyPointer::from_borrowed_ptr(_py, _slf); }; impl_wrap_common(cls, name, spec, noargs, slf, body) } diff --git a/src/conversion.rs b/src/conversion.rs index 72b7442e..50df2b2b 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -1,15 +1,13 @@ // Copyright (c) 2017-present PyO3 Project and Contributors //! Conversions between various states of rust and python types and their wrappers. - -use crate::err::{PyDowncastError, PyResult}; -use crate::ffi; +use crate::err::{self, PyDowncastError, PyResult}; use crate::object::PyObject; use crate::type_object::PyTypeInfo; use crate::types::PyAny; use crate::types::PyTuple; -use crate::Py; -use crate::Python; +use crate::{ffi, gil, Py, Python}; +use std::ptr::NonNull; /// This trait represents that, **we can do zero-cost conversion from the object to FFI pointer**. /// @@ -432,6 +430,65 @@ impl FromPy<()> for Py { } } +pub unsafe trait FromPyPointer<'p>: Sized { + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option; + unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> Self { + match Self::from_owned_ptr_or_opt(py, ptr) { + Some(s) => s, + None => err::panic_after_error(), + } + } + unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> Self { + Self::from_owned_ptr_or_panic(py, ptr) + } + unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult { + match Self::from_owned_ptr_or_opt(py, ptr) { + Some(s) => Ok(s), + None => Err(err::PyErr::fetch(py)), + } + } + unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option; + unsafe fn from_borrowed_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> Self { + match Self::from_borrowed_ptr_or_opt(py, ptr) { + Some(s) => s, + None => err::panic_after_error(), + } + } + unsafe fn from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> Self { + Self::from_borrowed_ptr_or_panic(py, ptr) + } + unsafe fn from_borrowed_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult { + match Self::from_borrowed_ptr_or_opt(py, ptr) { + Some(s) => Ok(s), + None => Err(err::PyErr::fetch(py)), + } + } +} + +unsafe impl<'p, T> FromPyPointer<'p> for &'p T +where + T: PyTypeInfo, +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| py.unchecked_downcast(gil::register_owned(py, p))) + } + unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| py.unchecked_downcast(gil::register_borrowed(py, p))) + } +} + +unsafe impl<'p, T> FromPyPointer<'p> for &'p mut T +where + T: PyTypeInfo, +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| py.unchecked_mut_downcast(gil::register_owned(py, p))) + } + unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| py.unchecked_mut_downcast(gil::register_borrowed(py, p))) + } +} + #[cfg(test)] mod test { use crate::types::PyList; diff --git a/src/instance.rs b/src/instance.rs index 7b0336cc..2f91b4b1 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -8,10 +8,10 @@ use crate::objectprotocol::ObjectProtocol; use crate::type_object::PyTypeCreate; use crate::type_object::{PyTypeInfo, PyTypeObject}; use crate::types::PyAny; -use crate::AsPyPointer; -use crate::IntoPyPointer; -use crate::Python; -use crate::{FromPyObject, IntoPyObject, PyTryFrom, ToPyObject}; +use crate::{ + AsPyPointer, FromPyObject, FromPyPointer, IntoPyObject, IntoPyPointer, PyTryFrom, Python, + ToPyObject, +}; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; @@ -72,23 +72,16 @@ impl<'a, T: PyTypeInfo> PyRef<'a, T> { pub(crate) fn from_ref(r: &'a T) -> Self { PyRef(r, PhantomData) } - pub unsafe fn from_owned_ptr(py: Python<'a>, ptr: *mut ffi::PyObject) -> Self { - Self::from_ref(py.from_owned_ptr(ptr)) - } - pub unsafe fn from_borrowed_ptr(py: Python<'a>, ptr: *mut ffi::PyObject) -> Self { - Self::from_ref(py.from_borrowed_ptr(ptr)) - } } -impl<'a, T> PyRef<'a, T> +impl<'p, T> PyRef<'p, T> where T: PyTypeInfo + PyTypeObject + PyTypeCreate, { - pub fn new(py: Python, value: T) -> PyResult> { + pub fn new(py: Python<'p>, value: T) -> PyResult> { let obj = T::create(py)?; obj.init(value); - let ref_ = unsafe { py.from_owned_ptr(obj.into_ptr()) }; - Ok(PyRef::from_ref(ref_)) + unsafe { Self::from_owned_ptr_or_err(py, obj.into_ptr()) } } } @@ -120,6 +113,18 @@ where } } +unsafe impl<'p, T> FromPyPointer<'p> for PyRef<'p, T> +where + T: PyTypeInfo, +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + FromPyPointer::from_owned_ptr_or_opt(py, ptr).map(Self::from_ref) + } + unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + FromPyPointer::from_borrowed_ptr_or_opt(py, ptr).map(Self::from_ref) + } +} + /// Mutable version of [`PyRef`](struct.PyRef.html). /// # Example /// ``` @@ -150,23 +155,16 @@ impl<'a, T: PyTypeInfo> PyRefMut<'a, T> { pub(crate) fn from_mut(t: &'a mut T) -> Self { PyRefMut(t, PhantomData) } - pub unsafe fn from_owned_ptr(py: Python<'a>, ptr: *mut ffi::PyObject) -> Self { - Self::from_mut(py.mut_from_owned_ptr(ptr)) - } - pub unsafe fn from_borrowed_ptr(py: Python<'a>, ptr: *mut ffi::PyObject) -> Self { - Self::from_mut(py.mut_from_borrowed_ptr(ptr)) - } } -impl<'a, T> PyRefMut<'a, T> +impl<'p, T> PyRefMut<'p, T> where T: PyTypeInfo + PyTypeObject + PyTypeCreate, { - pub fn new(py: Python, value: T) -> PyResult> { + pub fn new(py: Python<'p>, value: T) -> PyResult> { let obj = T::create(py)?; obj.init(value); - let ref_ = unsafe { py.mut_from_owned_ptr(obj.into_ptr()) }; - Ok(PyRefMut::from_mut(ref_)) + unsafe { Self::from_owned_ptr_or_err(py, obj.into_ptr()) } } } @@ -206,6 +204,18 @@ where } } +unsafe impl<'p, T> FromPyPointer<'p> for PyRefMut<'p, T> +where + T: PyTypeInfo, +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + FromPyPointer::from_owned_ptr_or_opt(py, ptr).map(Self::from_mut) + } + unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + FromPyPointer::from_borrowed_ptr_or_opt(py, ptr).map(Self::from_mut) + } +} + /// Trait implements object reference extraction from python managed pointer. pub trait AsPyRef: Sized { /// Return reference to object. diff --git a/src/lib.rs b/src/lib.rs index 6be9a6cb..75f56bd0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,8 +119,8 @@ pub use crate::class::*; pub use crate::conversion::{ - AsPyPointer, FromPy, FromPyObject, IntoPy, IntoPyObject, IntoPyPointer, PyTryFrom, PyTryInto, - ToBorrowedObject, ToPyObject, + AsPyPointer, FromPy, FromPyObject, FromPyPointer, IntoPy, IntoPyObject, IntoPyPointer, + PyTryFrom, PyTryInto, ToBorrowedObject, ToPyObject, }; pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult}; pub use crate::gil::{init_once, GILGuard, GILPool}; diff --git a/src/python.rs b/src/python.rs index 176f98e5..5e08092d 100644 --- a/src/python.rs +++ b/src/python.rs @@ -10,7 +10,7 @@ use crate::object::PyObject; use crate::type_object::{PyTypeInfo, PyTypeObject}; use crate::types::{PyAny, PyDict, PyModule, PyType}; use crate::AsPyPointer; -use crate::{IntoPyPointer, PyTryFrom}; +use crate::{FromPyPointer, IntoPyPointer, PyTryFrom}; use std::ffi::CString; use std::marker::PhantomData; use std::os::raw::c_int; @@ -193,7 +193,7 @@ impl<'p> Python<'p> { } impl<'p> Python<'p> { - unsafe fn unchecked_downcast(self, ob: &PyAny) -> &'p T { + pub(crate) unsafe fn unchecked_downcast(self, ob: &PyAny) -> &'p T { if T::OFFSET == 0 { &*(ob as *const _ as *const T) } else { @@ -203,7 +203,7 @@ impl<'p> Python<'p> { } #[allow(clippy::cast_ref_to_mut)] // FIXME - unsafe fn unchecked_mut_downcast(self, ob: &PyAny) -> &'p mut T { + pub(crate) unsafe fn unchecked_mut_downcast(self, ob: &PyAny) -> &'p mut T { if T::OFFSET == 0 { &mut *(ob as *const _ as *mut T) } else { @@ -244,13 +244,7 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - match NonNull::new(ptr) { - Some(p) => { - let p = gil::register_owned(self, p); - self.unchecked_downcast(p) - } - None => crate::err::panic_after_error(), - } + FromPyPointer::from_owned_ptr(self, ptr) } /// Register `ffi::PyObject` pointer in release pool, @@ -259,13 +253,7 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - match NonNull::new(ptr) { - Some(p) => { - let p = gil::register_owned(self, p); - self.unchecked_mut_downcast(p) - } - None => crate::err::panic_after_error(), - } + FromPyPointer::from_owned_ptr(self, ptr) } /// Register owned `ffi::PyObject` pointer in release pool. @@ -275,13 +263,7 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - match NonNull::new(ptr) { - Some(p) => { - let p = gil::register_owned(self, p); - Ok(self.unchecked_downcast(p)) - } - None => Err(PyErr::fetch(self)), - } + FromPyPointer::from_owned_ptr_or_err(self, ptr) } /// Register owned `ffi::PyObject` pointer in release pool. @@ -291,10 +273,7 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - NonNull::new(ptr).map(|p| { - let p = gil::register_owned(self, p); - self.unchecked_downcast(p) - }) + FromPyPointer::from_owned_ptr_or_opt(self, ptr) } /// Register borrowed `ffi::PyObject` pointer in release pool. @@ -304,13 +283,7 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - match NonNull::new(ptr) { - Some(p) => { - let p = gil::register_borrowed(self, p); - self.unchecked_downcast(p) - } - None => crate::err::panic_after_error(), - } + FromPyPointer::from_borrowed_ptr(self, ptr) } /// Register borrowed `ffi::PyObject` pointer in release pool. @@ -320,13 +293,7 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - match NonNull::new(ptr) { - Some(p) => { - let p = gil::register_borrowed(self, p); - self.unchecked_mut_downcast(p) - } - None => crate::err::panic_after_error(), - } + FromPyPointer::from_borrowed_ptr(self, ptr) } /// Register borrowed `ffi::PyObject` pointer in release pool. @@ -336,13 +303,7 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - match NonNull::new(ptr) { - Some(p) => { - let p = gil::register_borrowed(self, p); - Ok(self.unchecked_downcast(p)) - } - None => Err(PyErr::fetch(self)), - } + FromPyPointer::from_borrowed_ptr_or_err(self, ptr) } /// Register borrowed `ffi::PyObject` pointer in release pool. @@ -352,10 +313,7 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - NonNull::new(ptr).map(|p| { - let p = gil::register_borrowed(self, p); - self.unchecked_downcast(p) - }) + FromPyPointer::from_borrowed_ptr_or_opt(self, ptr) } #[doc(hidden)] diff --git a/tests/test_nested_iter.rs b/tests/test_nested_iter.rs index cceda6b0..1ad82c91 100644 --- a/tests/test_nested_iter.rs +++ b/tests/test_nested_iter.rs @@ -20,7 +20,7 @@ impl Reader { fn get_optional(&self, test: Option) -> PyResult { Ok(test.unwrap_or(10)) } - fn get_iter(slf: PyRef, keys: Py) -> PyResult { + fn get_iter(slf: PyRef, keys: Py) -> PyResult { Ok(Iter { reader: slf.into(), keys: keys,