Introduce FromPyPointer for slf: PyRef/PyRefMut

This commit is contained in:
kngwyu 2019-03-29 18:57:05 +09:00
parent 515c7beac0
commit b2e01066f0
7 changed files with 121 additions and 136 deletions

View file

@ -27,35 +27,7 @@ pub enum FnType {
FnCall,
FnClass,
FnStatic,
PySelf(PySelfType),
}
/// For fn(slf: &PyRef<Self>) support
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum PySelfType {
Py,
PyRef,
PyRefMut,
}
impl PySelfType {
fn from_args<'a>(args: &[FnArg<'a>]) -> Option<Self> {
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 {

View file

@ -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)
}

View file

@ -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<PyTuple> {
}
}
pub unsafe trait FromPyPointer<'p>: Sized {
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self>;
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<Self> {
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<Self>;
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<Self> {
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<Self> {
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<Self> {
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<Self> {
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<Self> {
NonNull::new(ptr).map(|p| py.unchecked_mut_downcast(gil::register_borrowed(py, p)))
}
}
#[cfg(test)]
mod test {
use crate::types::PyList;

View file

@ -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<PyRef<T>> {
pub fn new(py: Python<'p>, value: T) -> PyResult<PyRef<T>> {
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<Self> {
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<Self> {
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<PyRefMut<T>> {
pub fn new(py: Python<'p>, value: T) -> PyResult<PyRefMut<T>> {
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<Self> {
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<Self> {
FromPyPointer::from_borrowed_ptr_or_opt(py, ptr).map(Self::from_mut)
}
}
/// Trait implements object reference extraction from python managed pointer.
pub trait AsPyRef<T: PyTypeInfo>: Sized {
/// Return reference to object.

View file

@ -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};

View file

@ -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<T: PyTypeInfo>(self, ob: &PyAny) -> &'p T {
pub(crate) unsafe fn unchecked_downcast<T: PyTypeInfo>(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<T: PyTypeInfo>(self, ob: &PyAny) -> &'p mut T {
pub(crate) unsafe fn unchecked_mut_downcast<T: PyTypeInfo>(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)]

View file

@ -20,7 +20,7 @@ impl Reader {
fn get_optional(&self, test: Option<i32>) -> PyResult<i32> {
Ok(test.unwrap_or(10))
}
fn get_iter(slf: PyRef<Self>, keys: Py<PyBytes>) -> PyResult<Iter> {
fn get_iter(slf: PyRef<Reader>, keys: Py<PyBytes>) -> PyResult<Iter> {
Ok(Iter {
reader: slf.into(),
keys: keys,