Prototype Implementation of RefCell-like PyCell

This commit is contained in:
kngwyu 2020-02-09 16:36:32 +09:00
parent 5d4e7374e9
commit c43fb9fcdf
12 changed files with 286 additions and 110 deletions

View File

@ -234,11 +234,7 @@ where
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() {
Ok(arg) => slf.__getattr__(arg).into(),
Err(e) => Err(e),
};
let result = call_ref!(slf, __getattr__, arg);
crate::callback::cb_convert(PyObjectCallbackConverter, py, result)
}
Some(wrap::<T>)
@ -512,10 +508,7 @@ where
let arg = py.from_borrowed_ptr::<PyAny>(arg);
let res = match extract_op(op) {
Ok(op) => match arg.extract() {
Ok(arg) => slf.__richcmp__(arg, op).into(),
Err(e) => Err(e),
},
Ok(op) => call_ref!(slf, __richcmp__, arg ; op),
Err(e) => Err(e),
};
match res {

View File

@ -95,7 +95,7 @@ where
let _pool = crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let result = slf.bf_getbuffer(arg1, arg2).into();
let result = slf.borrow().bf_getbuffer(arg1, arg2).into();
crate::callback::cb_convert(UnitCallbackConverter, py, result)
}
Some(wrap::<T>)

View File

@ -98,7 +98,7 @@ where
arg,
_py: py,
};
match slf.__traverse__(visit) {
match slf.borrow().__traverse__(visit) {
Ok(()) => 0,
Err(PyTraverseError(code)) => code,
}
@ -135,7 +135,7 @@ where
let _pool = crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
slf.__clear__();
slf.borrow_mut().__clear__();
0
}
Some(tp_clear::<T>)

View File

@ -12,7 +12,17 @@ macro_rules! py_unary_func {
*mut $crate::ffi::PyObject
);
};
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr, $ret_type:ty) => {{
// Use call_ref! by default
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr, $ret_type:ty) => {
py_unary_func!($trait, $class::$f, $res_type, $conv, $ret_type, call_ref);
};
($trait:ident,
$class:ident :: $f:ident,
$res_type:ty,
$conv:expr,
$ret_type:ty,
$call: ident
) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> $ret_type
where
T: for<'p> $trait<'p>,
@ -20,7 +30,7 @@ macro_rules! py_unary_func {
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let res = slf.$f().into();
let res = $call!(slf, $f);
$crate::callback::cb_convert($conv, py, res.map(|x| x))
}
Some(wrap::<$class>)
@ -57,8 +67,7 @@ macro_rules! py_len_func {
let py = Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let result = slf.$f().into();
let result = call_ref!(slf, $f);
$crate::callback::cb_convert($conv, py, result)
}
Some(wrap::<$class>)
@ -77,8 +86,11 @@ macro_rules! py_binary_func {
*mut $crate::ffi::PyObject
)
};
// Use call_ref! by default
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr, $return:ty) => {{
#[allow(unused_mut)]
py_binary_func!($trait, $class::$f, $res_type, $conv, $return, call_ref)
}};
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr, $return:ty, $call:ident) => {{
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject, arg: *mut ffi::PyObject) -> $return
where
T: for<'p> $trait<'p>,
@ -88,11 +100,7 @@ macro_rules! py_binary_func {
let _pool = $crate::GILPool::new(py);
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() {
Ok(arg) => slf.$f(arg).into(),
Err(e) => Err(e.into()),
};
let result = $call!(slf, $f, arg);
$crate::callback::cb_convert($conv, py, result)
}
Some(wrap::<$class>)
@ -103,7 +111,6 @@ macro_rules! py_binary_func {
#[doc(hidden)]
macro_rules! py_binary_num_func {
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr) => {{
#[allow(unused_mut)]
unsafe extern "C" fn wrap<T>(
lhs: *mut ffi::PyObject,
rhs: *mut ffi::PyObject,
@ -130,11 +137,12 @@ macro_rules! py_binary_num_func {
}};
}
// NOTE(kngwyu):
// Now(2020 2/9) This macro is used only for inplace operation so I used call_refmut here.
#[macro_export]
#[doc(hidden)]
macro_rules! py_binary_self_func {
($trait:ident, $class:ident :: $f:ident) => {{
#[allow(unused_mut)]
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
@ -146,13 +154,9 @@ macro_rules! py_binary_self_func {
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf1 = py.from_borrowed_ptr::<$crate::PyCell<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() {
Ok(arg) => slf1.$f(arg).into(),
Err(e) => Err(e.into()),
};
let result = call_refmut!(slf_, $f, arg);
match result {
Ok(_) => {
ffi::Py_INCREF(slf);
@ -171,8 +175,17 @@ macro_rules! py_binary_self_func {
#[macro_export]
#[doc(hidden)]
macro_rules! py_ssizearg_func {
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr) => {{
#[allow(unused_mut)]
// Use call_ref! by default
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr) => {
py_ssizearg_func!(
$trait,
$class::$f,
$res_type,
$conv,
call_ref
)
};
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr, $call:ident) => {{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject,
arg: $crate::ffi::Py_ssize_t,
@ -183,7 +196,7 @@ macro_rules! py_ssizearg_func {
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let result = slf.$f(arg.into()).into();
let result = $call!(slf, $f ; arg.into());
$crate::callback::cb_convert($conv, py, result)
}
Some(wrap::<$class>)
@ -219,13 +232,7 @@ macro_rules! py_ternary_func {
let arg1 = py.from_borrowed_ptr::<$crate::types::PyAny>(arg1);
let arg2 = py.from_borrowed_ptr::<$crate::types::PyAny>(arg2);
let result = match arg1.extract() {
Ok(arg1) => match arg2.extract() {
Ok(arg2) => slf.$f(arg1, arg2).into(),
Err(e) => Err(e.into()),
},
Err(e) => Err(e.into()),
};
let result = call_ref!(slf, $f, arg1, arg2);
$crate::callback::cb_convert($conv, py, result)
}
@ -286,18 +293,10 @@ macro_rules! py_ternary_self_func {
let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py);
let slf1 = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let slf_cell = 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);
let result = match arg1.extract() {
Ok(arg1) => match arg2.extract() {
Ok(arg2) => slf1.$f(arg1, arg2).into(),
Err(e) => Err(e.into()),
},
Err(e) => Err(e.into()),
};
let result = call_refmut!(slf_cell, $f, arg1, arg2);
match result {
Ok(_) => slf,
Err(e) => {
@ -337,13 +336,7 @@ macro_rules! py_func_set {
} else {
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() {
Ok(value) => slf.$fn_set(name, value).into(),
Err(e) => Err(e.into()),
},
Err(e) => Err(e.into()),
}
call_refmut!(slf, $fn_set, name, value)
};
match result {
Ok(_) => 0,
@ -378,10 +371,7 @@ macro_rules! py_func_del {
let slf = py.from_borrowed_ptr::<$crate::PyCell<U>>(slf);
let name = py.from_borrowed_ptr::<$crate::types::PyAny>(name);
match name.extract() {
Ok(name) => slf.$fn_del(name).into(),
Err(e) => Err(e.into()),
}
call_refmut!(slf, $fn_del, name)
} else {
Err(PyErr::new::<exceptions::NotImplementedError, _>(
"Subscript assignment not supported",
@ -419,19 +409,10 @@ macro_rules! py_func_set_del {
let name = py.from_borrowed_ptr::<$crate::types::PyAny>(name);
let result = if value.is_null() {
match name.extract() {
Ok(name) => slf.$fn_del(name).into(),
Err(e) => Err(e.into()),
}
call_refmut!(slf, $fn_del, name)
} else {
let value = py.from_borrowed_ptr::<$crate::types::PyAny>(value);
match name.extract() {
Ok(name) => match value.extract() {
Ok(value) => slf.$fn_set(name, value).into(),
Err(e) => Err(e.into()),
},
Err(e) => Err(e.into()),
}
call_refmut!(slf, $fn_set, name, value)
};
match result {
Ok(_) => 0,
@ -444,3 +425,34 @@ macro_rules! py_func_set_del {
Some(wrap::<$generic>)
}};
}
// Utitlities for extract arguments + call method for PyCell<T>
macro_rules! call_ref {
($slf: expr, $fn: ident $(; $args: expr)*) => {
match $slf.try_borrow_unguarded() {
Ok(slf) => slf.$fn($($args,)*).into(),
Err(e) => Err(e.into()),
}
};
($slf: expr, $fn: ident, $raw_arg: expr $(,$raw_args: expr)* $(; $args: expr)*) => {
match $raw_arg.extract() {
Ok(arg) => call_ref!($slf, $fn $(,$raw_args)* ;arg $(;$args)*),
Err(e) => Err(e.into()),
}
};
}
macro_rules! call_refmut {
($slf: expr, $fn: ident $(; $args: expr)*) => {
match $slf.try_borrow_mut_unguarded() {
Ok(slf) => slf.$fn($($args,)*).into(),
Err(e) => Err(e.into()),
}
};
($slf: expr, $fn: ident, $raw_arg: expr $(,$raw_args: expr)* $(; $args: expr)*) => {
match $raw_arg.extract() {
Ok(arg) => call_refmut!($slf, $fn $(,$raw_args)* ;arg $(;$args)*),
Err(e) => Err(e.into()),
}
};
}

View File

@ -242,7 +242,9 @@ mod anext {
PyAsyncAnextProtocol,
T::__anext__,
Option<T::Success>,
IterANextResultConverter
IterANextResultConverter,
*mut crate::ffi::PyObject,
call_refmut
)
}
}

View File

@ -273,7 +273,10 @@ mod sq_ass_item_impl {
} else {
let value = py.from_borrowed_ptr::<PyAny>(value);
match value.extract() {
Ok(value) => slf.__setitem__(key.into(), value).into(),
Ok(value) => match slf.try_borrow_mut_unguarded() {
Ok(slf_) => slf_.__setitem__(key.into(), value).into(),
Err(e) => e.into(),
},
Err(e) => Err(e),
}
};
@ -321,7 +324,7 @@ mod sq_ass_item_impl {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let result = if value.is_null() {
slf.__delitem__(key.into()).into()
slf.borrow_mut().__delitem__(key.into()).into()
} else {
Err(PyErr::new::<exceptions::NotImplementedError, _>(format!(
"Item assignment not supported by {:?}",
@ -372,11 +375,14 @@ mod sq_ass_item_impl {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let result = if value.is_null() {
slf.__delitem__(key.into()).into()
call_refmut!(slf, __delitem__; key.into())
} else {
let value = py.from_borrowed_ptr::<PyAny>(value);
match value.extract() {
Ok(value) => slf.__setitem__(key.into(), value).into(),
Ok(value) => match slf.try_borrow_mut_unguarded() {
Ok(slf_) => slf_.__setitem__(key.into(), value).into(),
Err(e) => e.into(),
},
Err(e) => Err(e),
}
};
@ -497,7 +503,9 @@ where
PySequenceInplaceConcatProtocol,
T::__inplace_concat__,
T,
PyObjectCallbackConverter
PyObjectCallbackConverter,
*mut crate::ffi::PyObject,
call_refmut
)
}
}
@ -524,7 +532,8 @@ where
PySequenceInplaceRepeatProtocol,
T::__inplace_repeat__,
T,
PyObjectCallbackConverter
PyObjectCallbackConverter,
call_refmut
)
}
}

View File

@ -100,7 +100,8 @@ pub fn parse_fn_args<'p>(
// Adjust the remaining args
let args = if accept_args {
let py = args.py();
args.slice(used_args as isize, nargs as isize).as_ref(py)
// args.slice(used_args as isize, nargs as isize).as_ref(py)
unimplemented!()
} else {
args
};

View File

@ -59,6 +59,9 @@ pub type PyResult<T> = Result<T, PyErr>;
/// Marker type that indicates an error while downcasting
pub struct PyDowncastError;
/// Marker type for `PyCell`.
pub struct PyBorrowError;
/// Helper conversion trait that allows to use custom arguments for exception constructor.
pub trait PyErrArguments {
/// Arguments for exception
@ -401,7 +404,7 @@ impl<'a> IntoPy<PyObject> for &'a PyErr {
}
}
/// Converts `PyDowncastError` to Python `TypeError`.
/// Convert `PyDowncastError` to Python `TypeError`.
impl std::convert::From<PyDowncastError> for PyErr {
fn from(_err: PyDowncastError) -> PyErr {
exceptions::TypeError.into()

View File

@ -23,3 +23,10 @@ macro_rules! private_impl {
}
}
}
macro_rules! pyo3_exception {
($name: ident, $base: ty) => {
$crate::impl_exception_boilerplate!($name);
$crate::create_exception_type_object!(pyo3_runtime, $name, $base);
};
}

View File

@ -165,7 +165,6 @@ pub mod ffi;
pub mod freelist;
mod gil;
mod instance;
mod pyref;
#[macro_use]
mod internal_tricks;
pub mod marshal;

View File

@ -6,10 +6,44 @@ use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{PyDowncastImpl, PyObjectLayout, PyObjectSizedLayout};
use crate::types::PyAny;
use crate::{ffi, gil, PyErr, PyObject, PyResult, PyTypeInfo, Python};
use std::cell::{Cell, UnsafeCell};
use std::fmt;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
/// `PyCell` represents the concrete layout of `T: PyClass` when it is converted
/// Inner type of `PyCell` without dict slots and reference counter.
#[doc(hidden)]
#[repr(C)]
pub struct PyCellBase<T: PyClass> {
ob_base: <T::BaseType as PyTypeInfo>::ConcreteLayout,
value: ManuallyDrop<UnsafeCell<T>>,
}
impl<T: PyClass> PyCellBase<T> {
fn get(&self) -> &T {
unsafe { &*self.value.get() }
}
fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.value.get() }
}
}
impl<T: PyClass> PyObjectLayout<T> for PyCellBase<T> {
const IS_NATIVE_TYPE: bool = false;
fn get_super_or(&mut self) -> Option<&mut <T::BaseType as PyTypeInfo>::ConcreteLayout> {
Some(&mut self.ob_base)
}
unsafe fn py_init(&mut self, value: T) {
self.value = ManuallyDrop::new(UnsafeCell::new(value));
}
unsafe fn py_drop(&mut self, py: Python) {
ManuallyDrop::drop(&mut self.value);
self.ob_base.py_drop(py);
}
}
/// `Pycell` represents the concrete layout of `T: PyClass` when it is converted
/// to a Python class.
///
/// You can use it to test your `#[pyclass]` correctly works.
@ -35,7 +69,8 @@ use std::ptr::NonNull;
#[repr(C)]
pub struct PyCell<T: PyClass> {
ob_base: <T::BaseType as PyTypeInfo>::ConcreteLayout,
pyclass: ManuallyDrop<T>,
value: ManuallyDrop<UnsafeCell<T>>,
borrow_flag: BorrowFlag,
dict: T::Dict,
weakref: T::WeakRef,
}
@ -54,14 +89,40 @@ impl<T: PyClass> PyCell<T> {
}
}
/// Get the reference of base object.
pub fn get_super(&self) -> &<T::BaseType as PyTypeInfo>::ConcreteLayout {
&self.ob_base
pub fn borrow(&self) -> PyRef<'_, T> {
unsafe {
unimplemented!()
// if self.borrow.get() == usize::max_value() {
// borrow_fail();
// }
// self.borrow.set(self.borrow.get() + 1);
// Ref {
// value: &*self.value.get(),
// borrow: &self.borrow,
// }
}
}
/// Get the mutable reference of base object.
pub fn get_super_mut(&mut self) -> &mut <T::BaseType as PyTypeInfo>::ConcreteLayout {
&mut self.ob_base
pub fn borrow_mut(&self) -> PyRefMut<'_, T> {
unsafe {
unimplemented!()
// if self.borrow.get() != 0 {
// borrow_fail();
// }
// self.borrow.set(usize::max_value());
// RefMut {
// value: &mut *self.value.get(),
// borrow: &self.borrow,
// }
}
}
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
unimplemented!()
}
pub unsafe fn try_borrow_mut_unguarded(&self) -> Result<&mut T, PyBorrowMutError> {
unimplemented!()
}
pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self>
@ -74,6 +135,7 @@ impl<T: PyClass> PyCell<T> {
return Err(PyErr::fetch(py));
}
let self_ = base as *mut Self;
(*self_).borrow_flag = BorrowFlag::UNUSED;
(*self_).dict = T::Dict::new();
(*self_).weakref = T::WeakRef::new();
Ok(self_)
@ -85,15 +147,15 @@ 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 py_init(&mut self, value: T) {
self.value = ManuallyDrop::new(UnsafeCell::new(value));
}
unsafe fn py_drop(&mut self, py: Python) {
ManuallyDrop::drop(&mut self.pyclass);
ManuallyDrop::drop(&mut self.value);
self.dict.clear_dict(py);
self.weakref.clear_weakrefs(self.as_ptr(), py);
self.ob_base.py_drop(py);
}
unsafe fn py_init(&mut self, value: T) {
self.pyclass = ManuallyDrop::new(value);
}
}
unsafe impl<'py, T: 'py + PyClass> PyDowncastImpl<'py> for PyCell<T> {
@ -111,19 +173,6 @@ impl<T: PyClass> AsPyPointer for PyCell<T> {
}
}
impl<T: PyClass> std::ops::Deref for PyCell<T> {
type Target = T;
fn deref(&self) -> &T {
self.pyclass.deref()
}
}
impl<T: PyClass> std::ops::DerefMut for PyCell<T> {
fn deref_mut(&mut self) -> &mut T {
self.pyclass.deref_mut()
}
}
impl<T: PyClass> ToPyObject for &PyCell<T> {
fn to_object(&self, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
@ -150,3 +199,102 @@ where
NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell<T>))
}
}
pub struct PyRef<'p, T: PyClass> {
value: &'p PyCellBase<T>,
flag: &'p Cell<BorrowFlag>,
}
impl<'p, T: PyClass> PyRef<'p, T> {
fn get_super(&'p self) -> &'p T::BaseType {
unimplemented!()
}
}
impl<'p, T: PyClass> Deref for PyRef<'p, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.value.get()
}
}
impl<'p, T: PyClass> Drop for PyRef<'p, T> {
fn drop(&mut self) {
self.flag.set(self.flag.get());
}
}
pub struct PyRefMut<'p, T: PyClass> {
value: &'p mut PyCellBase<T>,
flag: &'p Cell<BorrowFlag>,
}
impl<'p, T: PyClass> Deref for PyRefMut<'p, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.value.get()
}
}
impl<'p, T: PyClass> DerefMut for PyRefMut<'p, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.value.get_mut()
}
}
impl<'p, T: PyClass> Drop for PyRefMut<'p, T> {
fn drop(&mut self) {
self.flag.set(BorrowFlag::UNUSED);
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
struct BorrowFlag(usize);
impl BorrowFlag {
const UNUSED: BorrowFlag = BorrowFlag(0);
const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::max_value());
fn decrement(self) -> Self {
Self(self.0 - 1)
}
}
pub struct PyBorrowError {
_private: (),
}
impl fmt::Debug for PyBorrowError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PyBorrowError").finish()
}
}
impl fmt::Display for PyBorrowError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt("Already mutably borrowed", f)
}
}
pub struct PyBorrowMutError {
_private: (),
}
impl fmt::Debug for PyBorrowMutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PyBorrowMutError").finish()
}
}
impl fmt::Display for PyBorrowMutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt("Already borrowed", f)
}
}
pyo3_exception!(PyBorrowError, crate::exceptions::Exception);
pyo3_exception!(PyBorrowMutError, crate::exceptions::Exception);

View File

@ -53,9 +53,11 @@ pub mod type_flags {
}
/// 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
// DEVELOPPER NOTE(kngwyu):
// `&PyCell` is a pointer but `&PyAny` is a pointer of a pointer, so we need
// two different abstraction for them.
// This mismatch eventually should be fixed with https://github.com/PyO3/pyo3/issues/679,
// but now it's not the time.
pub unsafe trait PyDowncastImpl<'py> {
unsafe fn unchecked_downcast(obj: &PyAny) -> &'py Self;
private_decl! {}