Introduce PyDownCastImpl and Change PyTryFrom and FromPyPointer

This commit is contained in:
kngwyu 2020-02-09 16:35:52 +09:00
parent a2408cacbb
commit 5d4e7374e9
24 changed files with 149 additions and 339 deletions

View file

@ -11,14 +11,9 @@
use crate::callback::{BoolCallbackConverter, HashConverter, PyObjectCallbackConverter};
use crate::class::methods::PyMethodDef;
use crate::err::{PyErr, PyResult};
use crate::ffi;
use crate::objectprotocol::ObjectProtocol;
use crate::type_object::PyTypeInfo;
use crate::types::PyAny;
use crate::FromPyObject;
use crate::IntoPyPointer;
use crate::Python;
use crate::{exceptions, IntoPy, PyObject};
use crate::{exceptions, ffi, FromPyObject, IntoPy, IntoPyPointer, PyClass, PyObject, Python};
use std::os::raw::c_int;
use std::ptr;
@ -35,7 +30,7 @@ pub enum CompareOp {
/// Basic python class customization
#[allow(unused_variables)]
pub trait PyObjectProtocol<'p>: PyTypeInfo {
pub trait PyObjectProtocol<'p>: PyClass {
fn __getattr__(&'p self, name: Self::Name) -> Self::Result
where
Self: PyObjectGetAttrProtocol<'p>,
@ -237,7 +232,7 @@ where
return existing;
}
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<crate::types::PyAny>(arg);
let result = match arg.extract() {
@ -513,7 +508,7 @@ where
{
let py = Python::assume_gil_acquired();
let _pool = crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<PyAny>(arg);
let res = match extract_op(op) {

View file

@ -6,8 +6,7 @@
//! c-api
use crate::callback::UnitCallbackConverter;
use crate::err::PyResult;
use crate::ffi;
use crate::type_object::PyTypeInfo;
use crate::{ffi, PyClass};
use std::os::raw::c_int;
/// Buffer protocol interface
@ -15,7 +14,7 @@ use std::os::raw::c_int;
/// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
/// c-api
#[allow(unused_variables)]
pub trait PyBufferProtocol<'p>: PyTypeInfo {
pub trait PyBufferProtocol<'p>: PyClass {
fn bf_getbuffer(&'p self, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result
where
Self: PyBufferGetBufferProtocol<'p>,
@ -94,7 +93,7 @@ where
{
let py = crate::Python::assume_gil_acquired();
let _pool = crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let result = slf.bf_getbuffer(arg1, arg2).into();
crate::callback::cb_convert(UnitCallbackConverter, py, result)

View file

@ -6,12 +6,11 @@
use crate::class::methods::PyMethodDef;
use crate::err::PyResult;
use crate::type_object::PyTypeInfo;
use crate::PyObject;
use crate::{PyClass, PyObject};
/// Context manager interface
#[allow(unused_variables)]
pub trait PyContextProtocol<'p>: PyTypeInfo {
pub trait PyContextProtocol<'p>: PyClass {
fn __enter__(&'p mut self) -> Self::Result
where
Self: PyContextEnterProtocol<'p>,

View file

@ -8,15 +8,13 @@
use crate::callback::{PyObjectCallbackConverter, UnitCallbackConverter};
use crate::class::methods::PyMethodDef;
use crate::err::PyResult;
use crate::type_object::PyTypeInfo;
use crate::types::{PyAny, PyType};
use crate::FromPyObject;
use crate::{ffi, IntoPy, PyObject};
use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject};
use std::os::raw::c_int;
/// Descriptor interface
#[allow(unused_variables)]
pub trait PyDescrProtocol<'p>: PyTypeInfo {
pub trait PyDescrProtocol<'p>: PyClass {
fn __get__(&'p self, instance: &'p PyAny, owner: Option<&'p PyType>) -> Self::Result
where
Self: PyDescrGetProtocol<'p>,

View file

@ -3,17 +3,14 @@
//! Python GC support
//!
use crate::ffi;
use crate::type_object::PyTypeInfo;
use crate::AsPyPointer;
use crate::Python;
use crate::{ffi, AsPyPointer, PyCell, PyClass, Python};
use std::os::raw::{c_int, c_void};
#[repr(transparent)]
pub struct PyTraverseError(c_int);
/// GC support
pub trait PyGCProtocol<'p>: PyTypeInfo {
pub trait PyGCProtocol<'p>: PyClass {
fn __traverse__(&'p self, visit: PyVisit) -> Result<(), PyTraverseError>;
fn __clear__(&'p mut self);
}
@ -94,7 +91,7 @@ where
{
let py = Python::assume_gil_acquired();
let _pool = crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let visit = PyVisit {
visit,
@ -136,7 +133,7 @@ where
{
let py = Python::assume_gil_acquired();
let _pool = crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
slf.__clear__();
0

View file

@ -19,7 +19,7 @@ macro_rules! py_unary_func {
{
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let res = slf.$f().into();
$crate::callback::cb_convert($conv, py, res.map(|x| x))
}
@ -56,7 +56,7 @@ macro_rules! py_len_func {
{
let py = Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let result = slf.$f().into();
$crate::callback::cb_convert($conv, py, result)
@ -86,7 +86,7 @@ macro_rules! py_binary_func {
use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<$crate::types::PyAny>(arg);
let result = match arg.extract() {
@ -146,7 +146,7 @@ macro_rules! py_binary_self_func {
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf1 = py.mut_from_borrowed_ptr::<T>(slf);
let slf1 = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<$crate::types::PyAny>(arg);
let result = match arg.extract() {
@ -182,7 +182,7 @@ macro_rules! py_ssizearg_func {
{
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let result = slf.$f(arg.into()).into();
$crate::callback::cb_convert($conv, py, result)
}
@ -215,7 +215,7 @@ macro_rules! py_ternary_func {
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg1 = py.from_borrowed_ptr::<$crate::types::PyAny>(arg1);
let arg2 = py.from_borrowed_ptr::<$crate::types::PyAny>(arg2);
@ -286,7 +286,7 @@ macro_rules! py_ternary_self_func {
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf1 = py.mut_from_borrowed_ptr::<T>(slf);
let slf1 = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg1 = py.from_borrowed_ptr::<$crate::types::PyAny>(arg1);
let arg2 = py.from_borrowed_ptr::<$crate::types::PyAny>(arg2);
@ -325,7 +325,7 @@ macro_rules! py_func_set {
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<$generic>(slf);
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
let result = if value.is_null() {
Err($crate::PyErr::new::<exceptions::NotImplementedError, _>(
@ -335,7 +335,7 @@ macro_rules! py_func_set {
),
))
} else {
let name = py.mut_from_borrowed_ptr::<$crate::types::PyAny>(name);
let name = py.from_borrowed_ptr::<$crate::types::PyAny>(name);
let value = py.from_borrowed_ptr::<$crate::types::PyAny>(value);
match name.extract() {
Ok(name) => match value.extract() {
@ -375,7 +375,7 @@ macro_rules! py_func_del {
let _pool = $crate::GILPool::new(py);
let result = if value.is_null() {
let slf = py.mut_from_borrowed_ptr::<U>(slf);
let slf = py.from_borrowed_ptr::<$crate::PyCell<U>>(slf);
let name = py.from_borrowed_ptr::<$crate::types::PyAny>(name);
match name.extract() {
@ -415,7 +415,7 @@ macro_rules! py_func_set_del {
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<$generic>(slf);
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
let name = py.from_borrowed_ptr::<$crate::types::PyAny>(name);
let result = if value.is_null() {

View file

@ -6,15 +6,11 @@
use crate::callback::{LenResultConverter, PyObjectCallbackConverter};
use crate::class::methods::PyMethodDef;
use crate::err::{PyErr, PyResult};
use crate::ffi;
use crate::type_object::PyTypeInfo;
use crate::FromPyObject;
use crate::Python;
use crate::{exceptions, IntoPy, PyObject};
use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject, Python};
/// Mapping interface
#[allow(unused_variables)]
pub trait PyMappingProtocol<'p>: PyTypeInfo {
pub trait PyMappingProtocol<'p>: PyClass {
fn __len__(&'p self) -> Self::Result
where
Self: PyMappingLenProtocol<'p>,

View file

@ -7,13 +7,11 @@ use crate::callback::PyObjectCallbackConverter;
use crate::class::basic::PyObjectProtocolImpl;
use crate::class::methods::PyMethodDef;
use crate::err::PyResult;
use crate::type_object::PyTypeInfo;
use crate::FromPyObject;
use crate::{ffi, IntoPy, PyObject};
use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject};
/// Number interface
#[allow(unused_variables)]
pub trait PyNumberProtocol<'p>: PyTypeInfo {
pub trait PyNumberProtocol<'p>: PyClass {
fn __add__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
where
Self: PyNumberAddProtocol<'p>,

View file

@ -11,15 +11,13 @@
use crate::callback::PyObjectCallbackConverter;
use crate::class::methods::PyMethodDef;
use crate::err::PyResult;
use crate::ffi;
use crate::type_object::PyTypeInfo;
use crate::PyObject;
use crate::{ffi, PyClass, PyObject};
/// Python Async/Await support interface.
///
/// Each method in this trait corresponds to Python async/await implementation.
#[allow(unused_variables)]
pub trait PyAsyncProtocol<'p>: PyTypeInfo {
pub trait PyAsyncProtocol<'p>: PyClass {
fn __await__(&'p self) -> Self::Result
where
Self: PyAsyncAwaitProtocol<'p>,

View file

@ -5,18 +5,14 @@
use crate::callback::{BoolCallbackConverter, LenResultConverter, PyObjectCallbackConverter};
use crate::err::{PyErr, PyResult};
use crate::ffi;
use crate::objectprotocol::ObjectProtocol;
use crate::type_object::PyTypeInfo;
use crate::types::PyAny;
use crate::FromPyObject;
use crate::Python;
use crate::{exceptions, IntoPy, PyObject};
use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject, Python};
use std::os::raw::c_int;
/// Sequence interface
#[allow(unused_variables)]
pub trait PySequenceProtocol<'p>: PyTypeInfo + Sized {
pub trait PySequenceProtocol<'p>: PyClass + Sized {
fn __len__(&'p self) -> Self::Result
where
Self: PySequenceLenProtocol<'p>,
@ -267,7 +263,7 @@ mod sq_ass_item_impl {
{
let py = Python::assume_gil_acquired();
let _pool = crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let result = if value.is_null() {
Err(PyErr::new::<exceptions::NotImplementedError, _>(format!(
@ -322,7 +318,7 @@ mod sq_ass_item_impl {
{
let py = Python::assume_gil_acquired();
let _pool = crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let result = if value.is_null() {
slf.__delitem__(key.into()).into()
@ -373,7 +369,7 @@ mod sq_ass_item_impl {
{
let py = Python::assume_gil_acquired();
let _pool = crate::GILPool::new(py);
let slf = py.mut_from_borrowed_ptr::<T>(slf);
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let result = if value.is_null() {
slf.__delitem__(key.into()).into()

View file

@ -3,7 +3,7 @@
//! Conversions between various states of rust and python types and their wrappers.
use crate::err::{self, PyDowncastError, PyResult};
use crate::object::PyObject;
use crate::type_object::{PyObjectLayout, PyTypeInfo};
use crate::type_object::{PyDowncastImpl, PyTypeInfo};
use crate::types::PyAny;
use crate::types::PyTuple;
use crate::{ffi, gil, Py, Python};
@ -254,11 +254,10 @@ pub mod extract_impl {
pub struct Cloned;
pub struct Reference;
pub struct MutReference;
impl<'a, T: 'a> ExtractImpl<'a, T> for Cloned
where
T: Clone,
T: Clone + PyTryFrom<'a>,
Reference: ExtractImpl<'a, &'a T>,
{
fn extract(source: &'a PyAny) -> PyResult<T> {
@ -266,7 +265,7 @@ pub mod extract_impl {
}
}
impl<'a, T> ExtractImpl<'a, &'a T> for Reference
impl<'a, T: 'a> ExtractImpl<'a, &'a T> for Reference
where
T: PyTryFrom<'a>,
{
@ -274,15 +273,6 @@ pub mod extract_impl {
Ok(T::try_from(source)?)
}
}
impl<'a, T> ExtractImpl<'a, &'a mut T> for MutReference
where
T: PyTryFrom<'a>,
{
fn extract(source: &'a PyAny) -> PyResult<&'a mut T> {
Ok(T::try_from_mut(source)?)
}
}
}
use extract_impl::ExtractImpl;
@ -312,8 +302,8 @@ pub trait FromPyObjectImpl {
impl<'a, T> FromPyObject<'a> for T
where
T: FromPyObjectImpl,
<T as FromPyObjectImpl>::Impl: ExtractImpl<'a, Self>,
T: FromPyObjectImpl + 'a,
<T as FromPyObjectImpl>::Impl: ExtractImpl<'a, T>,
{
#[inline]
fn extract(ob: &'a PyAny) -> PyResult<T> {
@ -337,108 +327,50 @@ where
}
}
/// Trait implemented by Python object types that allow a checked downcast.
/// This trait is similar to `std::convert::TryInto`
pub trait PyTryInto<T>: Sized {
/// Cast from PyObject to a concrete Python object type.
fn try_into(&self) -> Result<&T, PyDowncastError>;
/// Cast from PyObject to a concrete Python object type. With exact type check.
fn try_into_exact(&self) -> Result<&T, PyDowncastError>;
/// Cast from PyObject to a concrete Python object type.
fn try_into_mut(&self) -> Result<&mut T, PyDowncastError>;
/// Cast from PyObject to a concrete Python object type. With exact type check.
fn try_into_mut_exact(&self) -> Result<&mut T, PyDowncastError>;
}
/// Trait implemented by Python object types that allow a checked downcast.
/// This trait is similar to `std::convert::TryFrom`
pub trait PyTryFrom<'v>: Sized {
pub trait PyTryFrom<'v>: Sized + PyDowncastImpl<'v> {
/// Cast from a concrete Python object type to PyObject.
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError>;
/// Cast from a concrete Python object type to PyObject. With exact type check.
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError>;
/// Cast from a concrete Python object type to PyObject.
fn try_from_mut<V: Into<&'v PyAny>>(value: V) -> Result<&'v mut Self, PyDowncastError>;
/// Cast from a concrete Python object type to PyObject. With exact type check.
fn try_from_mut_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v mut Self, PyDowncastError>;
/// Cast a PyAny to a specific type of PyObject. The caller must
/// have already verified the reference is for this type.
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self;
/// Cast a PyAny to a specific type of PyObject. The caller must
/// have already verified the reference is for this type.
#[allow(clippy::mut_from_ref)]
unsafe fn try_from_mut_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v mut Self;
}
// TryFrom implies TryInto
impl<U> PyTryInto<U> for PyAny
where
U: for<'v> PyTryFrom<'v>,
{
fn try_into(&self) -> Result<&U, PyDowncastError> {
U::try_from(self)
}
fn try_into_exact(&self) -> Result<&U, PyDowncastError> {
U::try_from_exact(self)
}
fn try_into_mut(&self) -> Result<&mut U, PyDowncastError> {
U::try_from_mut(self)
}
fn try_into_mut_exact(&self) -> Result<&mut U, PyDowncastError> {
U::try_from_mut_exact(self)
}
}
// /// Trait implemented by Python object types that allow a checked downcast.
// /// This trait is similar to `std::convert::TryInto`
// pub trait PyTryInto<'v, T: PyDowncastImpl<'v>>: Sized {
// /// Cast from PyObject to a concrete Python object type.
// fn try_into(&self) -> Result<&T, PyDowncastError>;
// /// Cast from PyObject to a concrete Python object type. With exact type check.
// fn try_into_exact(&self) -> Result<&T, PyDowncastError>;
// }
impl<'v, T> PyTryFrom<'v> for T
where
T: PyTypeInfo,
T: PyDowncastImpl<'v> + PyTypeInfo,
{
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v T, PyDowncastError> {
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError> {
let value = value.into();
unsafe {
if T::is_instance(value) {
Ok(PyTryFrom::try_from_unchecked(value))
Ok(Self::try_from_unchecked(value))
} else {
Err(PyDowncastError)
}
}
}
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v T, PyDowncastError> {
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError> {
let value = value.into();
unsafe {
if T::is_exact_instance(value) {
Ok(PyTryFrom::try_from_unchecked(value))
} else {
Err(PyDowncastError)
}
}
}
fn try_from_mut<V: Into<&'v PyAny>>(value: V) -> Result<&'v mut T, PyDowncastError> {
let value = value.into();
unsafe {
if T::is_instance(value) {
Ok(PyTryFrom::try_from_mut_unchecked(value))
} else {
Err(PyDowncastError)
}
}
}
fn try_from_mut_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v mut T, PyDowncastError> {
let value = value.into();
unsafe {
if T::is_exact_instance(value) {
Ok(PyTryFrom::try_from_mut_unchecked(value))
Ok(Self::try_from_unchecked(value))
} else {
Err(PyDowncastError)
}
@ -446,15 +378,8 @@ where
}
#[inline]
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v T {
let value = value.into();
T::ConcreteLayout::internal_ref_cast(value)
}
#[inline]
unsafe fn try_from_mut_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v mut T {
let value = value.into();
T::ConcreteLayout::internal_mut_cast(value)
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
Self::unchecked_downcast(value.into())
}
}
@ -467,33 +392,37 @@ impl FromPy<()> for Py<PyTuple> {
/// Raw level conversion between `*mut ffi::PyObject` and PyO3 types.
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 {
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self>;
unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p 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 {
unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p 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> {
unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult<&'p 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 {
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Option<&'p Self>;
unsafe fn from_borrowed_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p 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 {
unsafe fn from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p 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> {
unsafe fn from_borrowed_ptr_or_err(
py: Python<'p>,
ptr: *mut ffi::PyObject,
) -> PyResult<&'p Self> {
match Self::from_borrowed_ptr_or_opt(py, ptr) {
Some(s) => Ok(s),
None => Err(err::PyErr::fetch(py)),
@ -501,29 +430,18 @@ pub unsafe trait FromPyPointer<'p>: Sized {
}
}
unsafe impl<'p, T> FromPyPointer<'p> for &'p T
unsafe impl<'p, T> FromPyPointer<'p> for T
where
T: PyTypeInfo,
T: 'p + crate::PyNativeType,
{
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| T::ConcreteLayout::internal_ref_cast(gil::register_owned(py, p)))
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> {
NonNull::new(ptr).map(|p| Self::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| T::ConcreteLayout::internal_ref_cast(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| T::ConcreteLayout::internal_mut_cast(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| T::ConcreteLayout::internal_mut_cast(gil::register_borrowed(py, p)))
unsafe fn from_borrowed_ptr_or_opt(
py: Python<'p>,
ptr: *mut ffi::PyObject,
) -> Option<&'p Self> {
NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_borrowed(py, p)))
}
}

View file

@ -11,7 +11,7 @@ use crate::instance::PyNativeType;
use crate::pyclass::PyClass;
use crate::pyclass_init::PyClassInitializer;
use crate::types::{PyAny, PyDict, PyModule, PyTuple};
use crate::{ffi, GILPool, IntoPy, PyObject, Python};
use crate::{ffi, AsPyRef, GILPool, IntoPy, PyObject, Python};
use std::ptr;
/// Description of a python parameter; used for `parse_args()`.
@ -100,8 +100,7 @@ pub fn parse_fn_args<'p>(
// Adjust the remaining args
let args = if accept_args {
let py = args.py();
let slice = args.slice(used_args as isize, nargs as isize).into_py(py);
py.checked_cast_as(slice).unwrap()
args.slice(used_args as isize, nargs as isize).as_ref(py)
} else {
args
};

View file

@ -127,7 +127,7 @@ pub trait AsPyRef<T: PyTypeInfo>: Sized {
impl<T: PyTypeInfo> AsPyRef<T> for Py<T> {
fn as_ref(&self, _py: Python) -> &T {
let any = self as *const Py<T> as *const PyAny;
unsafe { T::ConcreteLayout::internal_ref_cast(&*any) }
unimplemented!()
}
}

View file

@ -119,7 +119,7 @@
pub use crate::class::*;
pub use crate::conversion::{
AsPyPointer, FromPy, FromPyObject, FromPyPointer, IntoPy, IntoPyPointer, PyTryFrom, PyTryInto,
AsPyPointer, FromPy, FromPyObject, FromPyPointer, IntoPy, IntoPyPointer, PyTryFrom,
ToBorrowedObject, ToPyObject,
};
pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult};
@ -165,6 +165,7 @@ pub mod ffi;
pub mod freelist;
mod gil;
mod instance;
mod pyref;
#[macro_use]
mod internal_tricks;
pub mod marshal;

View file

@ -149,9 +149,9 @@ impl PyObject {
}
/// Casts the PyObject to a concrete Python object type.
pub fn cast_as<D>(&self, py: Python) -> Result<&D, PyDowncastError>
pub fn cast_as<'p, D>(&'p self, py: Python<'p>) -> Result<&'p D, PyDowncastError>
where
D: for<'v> PyTryFrom<'v>,
D: PyTryFrom<'p>,
{
D::try_from(self.as_ref(py))
}

View file

@ -3,16 +3,11 @@
use crate::class::basic::CompareOp;
use crate::err::{self, PyDowncastError, PyErr, PyResult};
use crate::exceptions::TypeError;
use crate::ffi;
use crate::instance::PyNativeType;
use crate::object::PyObject;
use crate::type_object::PyTypeInfo;
use crate::types::{PyAny, PyDict, PyIterator, PyString, PyTuple, PyType};
use crate::AsPyPointer;
use crate::IntoPyPointer;
use crate::Py;
use crate::Python;
use crate::{FromPyObject, IntoPy, PyTryFrom, ToBorrowedObject, ToPyObject};
use crate::{
ffi, AsPyPointer, FromPyObject, FromPyPointer, IntoPy, IntoPyPointer, Py, PyNativeType,
PyObject, PyTryFrom, PyTypeInfo, Python, ToBorrowedObject, ToPyObject,
};
use std::cmp::Ordering;
use std::os::raw::c_int;
@ -176,15 +171,10 @@ pub trait ObjectProtocol {
fn get_type_ptr(&self) -> *mut ffi::PyTypeObject;
/// Gets the Python base object for this object.
fn get_base(&self) -> &<Self as PyTypeInfo>::BaseType
fn get_base<'py>(&'py self) -> &'py <Self as PyTypeInfo>::BaseType
where
Self: PyTypeInfo;
/// Gets the Python base object for this object.
fn get_mut_base(&mut self) -> &mut <Self as PyTypeInfo>::BaseType
where
Self: PyTypeInfo;
Self: PyTypeInfo,
<Self as PyTypeInfo>::BaseType: FromPyPointer<'py>;
/// Casts the PyObject to a concrete Python object type.
fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError>
@ -455,20 +445,14 @@ where
unsafe { (*self.as_ptr()).ob_type }
}
fn get_base(&self) -> &<Self as PyTypeInfo>::BaseType
fn get_base<'py>(&'py self) -> &'py <Self as PyTypeInfo>::BaseType
where
Self: PyTypeInfo,
<Self as PyTypeInfo>::BaseType: FromPyPointer<'py>,
{
unsafe { self.py().from_borrowed_ptr(self.as_ptr()) }
}
fn get_mut_base(&mut self) -> &mut <Self as PyTypeInfo>::BaseType
where
Self: PyTypeInfo,
{
unsafe { self.py().mut_from_borrowed_ptr(self.as_ptr()) }
}
fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError>
where
D: PyTryFrom<'a>,

View file

@ -17,7 +17,7 @@ pub use crate::object::PyObject;
pub use crate::objectprotocol::ObjectProtocol;
pub use crate::pyclass_init::PyClassInitializer;
pub use crate::python::Python;
pub use crate::{FromPy, FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, PyTryInto, ToPyObject};
pub use crate::{FromPy, FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, ToPyObject};
// This is only part of the prelude because we need it for the pymodule function
pub use crate::types::PyModule;
pub use pyo3cls::pymodule;

View file

@ -3,7 +3,7 @@ use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
use crate::pyclass::PyClass;
use crate::pyclass_init::PyClassInitializer;
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{PyObjectLayout, PyObjectSizedLayout};
use crate::type_object::{PyDowncastImpl, PyObjectLayout, PyObjectSizedLayout};
use crate::types::PyAny;
use crate::{ffi, gil, PyErr, PyObject, PyResult, PyTypeInfo, Python};
use std::mem::ManuallyDrop;
@ -42,20 +42,7 @@ pub struct PyCell<T: PyClass> {
impl<T: PyClass> PyCell<T> {
/// Make new `PyCell` on the Python heap and returns the reference of it.
pub fn new_ref(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self>
where
<T::BaseType as PyTypeInfo>::ConcreteLayout:
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
unsafe {
let initializer = value.into();
let self_ = initializer.create_cell(py)?;
FromPyPointer::from_owned_ptr_or_err(py, self_ as _)
}
}
/// Make new `PyCell` on the Python heap and returns the mutable reference of it.
pub fn new_mut(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&mut Self>
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self>
where
<T::BaseType as PyTypeInfo>::ConcreteLayout:
crate::type_object::PyObjectSizedLayout<T::BaseType>,
@ -98,14 +85,6 @@ impl<T: PyClass> PyObjectLayout<T> for PyCell<T> {
fn get_super_or(&mut self) -> Option<&mut <T::BaseType as PyTypeInfo>::ConcreteLayout> {
Some(&mut self.ob_base)
}
unsafe fn internal_ref_cast(obj: &PyAny) -> &T {
let cell = obj.as_ptr() as *const Self;
&(*cell).pyclass
}
unsafe fn internal_mut_cast(obj: &PyAny) -> &mut T {
let cell = obj.as_ptr() as *const _ as *mut Self;
&mut (*cell).pyclass
}
unsafe fn py_drop(&mut self, py: Python) {
ManuallyDrop::drop(&mut self.pyclass);
self.dict.clear_dict(py);
@ -117,6 +96,13 @@ impl<T: PyClass> PyObjectLayout<T> for PyCell<T> {
}
}
unsafe impl<'py, T: 'py + PyClass> PyDowncastImpl<'py> for PyCell<T> {
unsafe fn unchecked_downcast(obj: &PyAny) -> &'py Self {
&*(obj.as_ptr() as *const Self)
}
private_impl! {}
}
impl<T: PyClass> PyObjectSizedLayout<T> for PyCell<T> {}
impl<T: PyClass> AsPyPointer for PyCell<T> {
@ -150,28 +136,17 @@ impl<T: PyClass> ToPyObject for &mut PyCell<T> {
}
}
unsafe impl<'p, T> FromPyPointer<'p> for &'p PyCell<T>
unsafe impl<'p, T> FromPyPointer<'p> for PyCell<T>
where
T: PyClass,
{
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> {
NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyCell<T>))
}
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
unsafe fn from_borrowed_ptr_or_opt(
py: Python<'p>,
ptr: *mut ffi::PyObject,
) -> Option<&'p Self> {
NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell<T>))
}
}
unsafe impl<'p, T> FromPyPointer<'p> for &'p mut PyCell<T>
where
T: PyClass,
{
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr)
.map(|p| &mut *(gil::register_owned(py, p).as_ptr() as *const _ as *mut PyCell<T>))
}
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr)
.map(|p| &mut *(gil::register_borrowed(py, p).as_ptr() as *const _ as *mut PyCell<T>))
}
}

View file

@ -7,7 +7,7 @@ use crate::ffi;
use crate::gil::{self, GILGuard};
use crate::instance::AsPyRef;
use crate::object::PyObject;
use crate::type_object::{PyObjectLayout, PyTypeInfo, PyTypeObject};
use crate::type_object::{PyDowncastImpl, PyObjectLayout, PyTypeInfo, PyTypeObject};
use crate::types::{PyAny, PyDict, PyModule, PyType};
use crate::AsPyPointer;
use crate::{FromPyPointer, IntoPyPointer, PyTryFrom};
@ -275,19 +275,19 @@ impl<'p> Python<'p> {
/// Register object in release pool, and try to downcast to specific type.
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'p T, PyDowncastError>
where
T: PyTypeInfo,
T: PyTryFrom<'p>,
{
let p = unsafe { gil::register_owned(self, obj.into_nonnull()) };
<T as PyTryFrom>::try_from(p)
let obj = unsafe { gil::register_owned(self, obj.into_nonnull()) };
<T as PyTryFrom>::try_from(obj)
}
/// Register object in release pool, and do unchecked downcast to specific type.
pub unsafe fn cast_as<T>(self, obj: PyObject) -> &'p T
where
T: PyTypeInfo,
T: PyDowncastImpl<'p> + PyTypeInfo,
{
let p = gil::register_owned(self, obj.into_nonnull());
T::ConcreteLayout::internal_ref_cast(p)
let obj = gil::register_owned(self, obj.into_nonnull());
T::unchecked_downcast(obj)
}
/// Register `ffi::PyObject` pointer in release pool
@ -304,16 +304,7 @@ impl<'p> Python<'p> {
#[allow(clippy::wrong_self_convention)]
pub unsafe fn from_owned_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p T
where
T: PyTypeInfo,
{
FromPyPointer::from_owned_ptr(self, ptr)
}
/// Register `ffi::PyObject` pointer in release pool,
/// Do unchecked downcast to specific type. Returns mutable reference.
pub unsafe fn mut_from_owned_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p mut T
where
T: PyTypeInfo,
T: FromPyPointer<'p>,
{
FromPyPointer::from_owned_ptr(self, ptr)
}
@ -324,7 +315,7 @@ impl<'p> Python<'p> {
#[allow(clippy::wrong_self_convention)]
pub unsafe fn from_owned_ptr_or_err<T>(self, ptr: *mut ffi::PyObject) -> PyResult<&'p T>
where
T: PyTypeInfo,
T: FromPyPointer<'p>,
{
FromPyPointer::from_owned_ptr_or_err(self, ptr)
}
@ -335,7 +326,7 @@ impl<'p> Python<'p> {
#[allow(clippy::wrong_self_convention)]
pub unsafe fn from_owned_ptr_or_opt<T>(self, ptr: *mut ffi::PyObject) -> Option<&'p T>
where
T: PyTypeInfo,
T: FromPyPointer<'p>,
{
FromPyPointer::from_owned_ptr_or_opt(self, ptr)
}
@ -346,17 +337,7 @@ impl<'p> Python<'p> {
#[allow(clippy::wrong_self_convention)]
pub unsafe fn from_borrowed_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p T
where
T: PyTypeInfo,
{
FromPyPointer::from_borrowed_ptr(self, ptr)
}
/// Register borrowed `ffi::PyObject` pointer in release pool.
/// Panics if the pointer is `null`.
/// do unchecked downcast to specific type.
pub unsafe fn mut_from_borrowed_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p mut T
where
T: PyTypeInfo,
T: FromPyPointer<'p>,
{
FromPyPointer::from_borrowed_ptr(self, ptr)
}
@ -367,7 +348,7 @@ impl<'p> Python<'p> {
#[allow(clippy::wrong_self_convention)]
pub unsafe fn from_borrowed_ptr_or_err<T>(self, ptr: *mut ffi::PyObject) -> PyResult<&'p T>
where
T: PyTypeInfo,
T: FromPyPointer<'p>,
{
FromPyPointer::from_borrowed_ptr_or_err(self, ptr)
}
@ -378,7 +359,7 @@ impl<'p> Python<'p> {
#[allow(clippy::wrong_self_convention)]
pub unsafe fn from_borrowed_ptr_or_opt<T>(self, ptr: *mut ffi::PyObject) -> Option<&'p T>
where
T: PyTypeInfo,
T: FromPyPointer<'p>,
{
FromPyPointer::from_borrowed_ptr_or_opt(self, ptr)
}

View file

@ -22,15 +22,6 @@ pub trait PyObjectLayout<T: PyTypeInfo> {
None
}
unsafe fn internal_ref_cast(obj: &PyAny) -> &T {
&*(obj as *const _ as *const T)
}
#[allow(clippy::mut_from_ref)]
unsafe fn internal_mut_cast(obj: &PyAny) -> &mut T {
&mut *(obj as *const _ as *const T as *mut T)
}
unsafe fn py_init(&mut self, _value: T) {}
unsafe fn py_drop(&mut self, _py: Python) {}
}
@ -61,6 +52,25 @@ pub mod type_flags {
pub const EXTENDED: usize = 1 << 4;
}
/// Reference abstraction for `PyClass` and `PyNativeType`.
// NOTE: This trait is separated from PyTypeInfo since make it PyTypeInfo<`py> is confusing...
// When GAT and type Ref<'py> becomes stable, let's merge this trait to
// PyConcreteLayout or Py
pub unsafe trait PyDowncastImpl<'py> {
unsafe fn unchecked_downcast(obj: &PyAny) -> &'py Self;
private_decl! {}
}
unsafe impl<'py, T> PyDowncastImpl<'py> for T
where
T: 'py + crate::PyNativeType,
{
unsafe fn unchecked_downcast(obj: &PyAny) -> &'py Self {
&*(obj as *const _ as *const Self)
}
private_impl! {}
}
/// Python type information.
/// All Python native types(e.g., `PyDict`) and `#[pyclass]` structs implement this trait.
///

View file

@ -36,17 +36,10 @@ pyobject_native_type_convert!(
pyobject_native_type_extract!(PyAny);
impl PyAny {
pub fn downcast_ref<T>(&self) -> Result<&T, PyDowncastError>
pub fn downcast<T>(&self) -> Result<&T, PyDowncastError>
where
T: for<'gil> PyTryFrom<'gil>,
for<'py> T: PyTryFrom<'py>,
{
T::try_from(self)
}
pub fn downcast_mut<T>(&self) -> Result<&mut T, PyDowncastError>
where
T: for<'gil> PyTryFrom<'gil>,
{
T::try_from_mut(self)
<T as PyTryFrom>::try_from(self)
}
}

View file

@ -79,7 +79,7 @@ impl PyModule {
/// Return the index (`__all__`) of the module, creating one if needed.
pub fn index(&self) -> PyResult<&PyList> {
match self.getattr("__all__") {
Ok(idx) => idx.downcast_ref().map_err(PyErr::from),
Ok(idx) => idx.downcast().map_err(PyErr::from),
Err(err) => {
if err.is_instance::<exceptions::AttributeError>(self.py()) {
let l = PyList::empty(self.py());

View file

@ -298,34 +298,11 @@ impl<'v> PyTryFrom<'v> for PySequence {
<PySequence as PyTryFrom>::try_from(value)
}
fn try_from_mut<V: Into<&'v PyAny>>(value: V) -> Result<&'v mut PySequence, PyDowncastError> {
let value = value.into();
unsafe {
if ffi::PySequence_Check(value.as_ptr()) != 0 {
Ok(<PySequence as PyTryFrom>::try_from_mut_unchecked(value))
} else {
Err(PyDowncastError)
}
}
}
fn try_from_mut_exact<V: Into<&'v PyAny>>(
value: V,
) -> Result<&'v mut PySequence, PyDowncastError> {
<PySequence as PyTryFrom>::try_from_mut(value)
}
#[inline]
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v PySequence {
let ptr = value.into() as *const _ as *const PySequence;
&*ptr
}
#[inline]
unsafe fn try_from_mut_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v mut PySequence {
let ptr = value.into() as *const _ as *mut PySequence;
&mut *ptr
}
}
#[cfg(test)]

View file

@ -3,15 +3,11 @@
use crate::conversion::FromPyObject;
use crate::conversion::{PyTryFrom, ToPyObject};
use crate::err::{PyErr, PyResult};
use crate::gil;
use crate::instance::PyNativeType;
use crate::internal_tricks::Unsendable;
use crate::object::PyObject;
use crate::types::PyAny;
use crate::AsPyPointer;
use crate::IntoPy;
use crate::Python;
use crate::{ffi, FromPy};
use crate::{ffi, gil, AsPyPointer, FromPy, IntoPy, Python};
use std::borrow::Cow;
use std::ffi::CStr;
use std::os::raw::c_char;