Fix PyCell to share BorrowFlag with parents
This commit is contained in:
parent
4a5f219cc4
commit
da4ed398bb
|
@ -35,6 +35,7 @@ pub enum FnType {
|
|||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct FnSpec<'a> {
|
||||
pub tp: FnType,
|
||||
pub self_: Option<bool>,
|
||||
// Rust function name
|
||||
pub name: &'a syn::Ident,
|
||||
// Wrapped python name. This should not have any leading r#.
|
||||
|
@ -54,6 +55,28 @@ pub fn get_return_info(output: &syn::ReturnType) -> syn::Type {
|
|||
}
|
||||
|
||||
impl<'a> FnSpec<'a> {
|
||||
/// Generate the code for borrowing self
|
||||
pub(crate) fn borrow_self(&self) -> TokenStream {
|
||||
let is_mut = self
|
||||
.self_
|
||||
.expect("impl_borrow_self is called for non-self fn");
|
||||
if is_mut {
|
||||
quote! {
|
||||
match _slf.try_borrow() {
|
||||
Ok(ref_) => ref_,
|
||||
Err(e) => return e.into::<pyo3::PyErr>.restore_and_null(_py),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
match _slf.try_borrow_mut() {
|
||||
Ok(ref_) => ref_,
|
||||
Err(e) => return e.into::<pyo3::PyErr>.restore_and_null(_py),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parser function signature and function attributes
|
||||
pub fn parse(
|
||||
sig: &'a syn::Signature,
|
||||
|
@ -67,19 +90,19 @@ impl<'a> FnSpec<'a> {
|
|||
mut python_name,
|
||||
} = parse_method_attributes(meth_attrs, allow_custom_name)?;
|
||||
|
||||
let mut has_self = false;
|
||||
let mut self_ = None;
|
||||
let mut arguments = Vec::new();
|
||||
for input in sig.inputs.iter() {
|
||||
match input {
|
||||
syn::FnArg::Receiver(_) => {
|
||||
has_self = true;
|
||||
syn::FnArg::Receiver(recv) => {
|
||||
self_ = Some(recv.mutability.is_some());
|
||||
}
|
||||
syn::FnArg::Typed(syn::PatType {
|
||||
ref pat, ref ty, ..
|
||||
}) => {
|
||||
// skip first argument (cls)
|
||||
if fn_type == FnType::FnClass && !has_self {
|
||||
has_self = true;
|
||||
if fn_type == FnType::FnClass && !self_.is_none() {
|
||||
self_ = Some(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -114,7 +137,7 @@ impl<'a> FnSpec<'a> {
|
|||
|
||||
let ty = get_return_info(&sig.output);
|
||||
|
||||
if fn_type == FnType::Fn && !has_self {
|
||||
if fn_type == FnType::Fn && self_.is_none() {
|
||||
if arguments.is_empty() {
|
||||
return Err(syn::Error::new_spanned(
|
||||
name,
|
||||
|
@ -174,6 +197,7 @@ impl<'a> FnSpec<'a> {
|
|||
|
||||
Ok(FnSpec {
|
||||
tp: fn_type,
|
||||
self_,
|
||||
name,
|
||||
python_name,
|
||||
attrs: fn_attrs,
|
||||
|
|
|
@ -54,27 +54,22 @@ pub fn process_functions_in_module(func: &mut syn::ItemFn) {
|
|||
}
|
||||
|
||||
/// Transforms a rust fn arg parsed with syn into a method::FnArg
|
||||
fn wrap_fn_argument<'a>(input: &'a syn::FnArg, name: &'a Ident) -> Option<method::FnArg<'a>> {
|
||||
match input {
|
||||
syn::FnArg::Receiver(_) => None,
|
||||
syn::FnArg::Typed(ref cap) => {
|
||||
let (mutability, by_ref, ident) = match *cap.pat {
|
||||
syn::Pat::Ident(ref patid) => (&patid.mutability, &patid.by_ref, &patid.ident),
|
||||
_ => panic!("unsupported argument: {:?}", cap.pat),
|
||||
};
|
||||
fn wrap_fn_argument<'a>(cap: &'a syn::PatType, name: &'a Ident) -> method::FnArg<'a> {
|
||||
let (mutability, by_ref, ident) = match *cap.pat {
|
||||
syn::Pat::Ident(ref patid) => (&patid.mutability, &patid.by_ref, &patid.ident),
|
||||
_ => panic!("unsupported argument: {:?}", cap.pat),
|
||||
};
|
||||
|
||||
let py = crate::utils::if_type_is_python(&cap.ty);
|
||||
let opt = method::check_arg_ty_and_optional(&name, &cap.ty);
|
||||
Some(method::FnArg {
|
||||
name: ident,
|
||||
mutability,
|
||||
by_ref,
|
||||
ty: &cap.ty,
|
||||
optional: opt,
|
||||
py,
|
||||
reference: method::is_ref(&name, &cap.ty),
|
||||
})
|
||||
}
|
||||
let py = crate::utils::if_type_is_python(&cap.ty);
|
||||
let opt = method::check_arg_ty_and_optional(&name, &cap.ty);
|
||||
method::FnArg {
|
||||
name: ident,
|
||||
mutability,
|
||||
by_ref,
|
||||
ty: &cap.ty,
|
||||
optional: opt,
|
||||
py,
|
||||
reference: method::is_ref(&name, &cap.ty),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,10 +133,16 @@ pub fn add_fn_to_module(
|
|||
pyfn_attrs: Vec<pyfunction::Argument>,
|
||||
) -> TokenStream {
|
||||
let mut arguments = Vec::new();
|
||||
let mut self_ = None;
|
||||
|
||||
for input in func.sig.inputs.iter() {
|
||||
if let Some(fn_arg) = wrap_fn_argument(input, &func.sig.ident) {
|
||||
arguments.push(fn_arg);
|
||||
match input {
|
||||
syn::FnArg::Receiver(recv) => {
|
||||
self_ = Some(recv.mutability.is_some());
|
||||
}
|
||||
syn::FnArg::Typed(ref cap) => {
|
||||
arguments.push(wrap_fn_argument(cap, &func.sig.ident));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,6 +161,7 @@ pub fn add_fn_to_module(
|
|||
|
||||
let spec = method::FnSpec {
|
||||
tp: method::FnType::Fn,
|
||||
self_,
|
||||
name: &function_wrapper_ident,
|
||||
python_name,
|
||||
attrs: pyfn_attrs,
|
||||
|
|
|
@ -315,14 +315,18 @@ fn impl_class(
|
|||
}
|
||||
|
||||
let weakref = if has_weakref {
|
||||
quote! { type WeakRef = pyo3::pyclass_slots::PyClassWeakRefSlot; }
|
||||
quote! { pyo3::pyclass_slots::PyClassWeakRefSlot }
|
||||
} else if attr.has_extends {
|
||||
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::WeakRef }
|
||||
} else {
|
||||
quote! { type WeakRef = pyo3::pyclass_slots::PyClassDummySlot; }
|
||||
quote! { pyo3::pyclass_slots::PyClassDummySlot }
|
||||
};
|
||||
let dict = if has_dict {
|
||||
quote! { type Dict = pyo3::pyclass_slots::PyClassDictSlot; }
|
||||
quote! { pyo3::pyclass_slots::PyClassDictSlot }
|
||||
} else if attr.has_extends {
|
||||
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::Dict }
|
||||
} else {
|
||||
quote! { type Dict = pyo3::pyclass_slots::PyClassDummySlot; }
|
||||
quote! { pyo3::pyclass_slots::PyClassDummySlot }
|
||||
};
|
||||
let module = if let Some(m) = &attr.module {
|
||||
quote! { Some(#m) }
|
||||
|
@ -355,6 +359,16 @@ fn impl_class(
|
|||
} else {
|
||||
quote! { 0 }
|
||||
};
|
||||
let base_layout = if attr.has_extends {
|
||||
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::Layout }
|
||||
} else {
|
||||
quote! { pyo3::pycell::PyCellBase<pyo3::types::PyAny> }
|
||||
};
|
||||
let base_nativetype = if attr.has_extends {
|
||||
quote! { <Self::BaseType as pyo3::derive_utils::PyBaseTypeUtils>::BaseNativeType }
|
||||
} else {
|
||||
quote! { pyo3::types::PyAny }
|
||||
};
|
||||
|
||||
// If #cls is not extended type, we allow Self->PyObject conversion
|
||||
let into_pyobject = if !attr.has_extends {
|
||||
|
@ -373,8 +387,10 @@ fn impl_class(
|
|||
unsafe impl pyo3::type_object::PyTypeInfo for #cls {
|
||||
type Type = #cls;
|
||||
type BaseType = #base;
|
||||
type ConcreteLayout = pyo3::pyclass::PyCell<Self>;
|
||||
type Layout = pyo3::pycell::PyCell<Self>;
|
||||
type BaseLayout = #base_layout;
|
||||
type Initializer = pyo3::pyclass_init::PyClassInitializer<Self>;
|
||||
type Reference = pyo3::pycell::PyCell<Self>;
|
||||
|
||||
const NAME: &'static str = #cls_name;
|
||||
const MODULE: Option<&'static str> = #module;
|
||||
|
@ -390,20 +406,9 @@ fn impl_class(
|
|||
}
|
||||
|
||||
impl pyo3::PyClass for #cls {
|
||||
#dict
|
||||
#weakref
|
||||
}
|
||||
|
||||
impl pyo3::conversion::FromPyObjectImpl for #cls {
|
||||
type Impl = pyo3::conversion::extract_impl::Cloned;
|
||||
}
|
||||
|
||||
impl pyo3::conversion::FromPyObjectImpl for &'_ #cls {
|
||||
type Impl = pyo3::conversion::extract_impl::Reference;
|
||||
}
|
||||
|
||||
impl pyo3::conversion::FromPyObjectImpl for &'_ mut #cls {
|
||||
type Impl = pyo3::conversion::extract_impl::MutReference;
|
||||
type Dict = #dict;
|
||||
type WeakRef = #weakref;
|
||||
type BaseNativeType = #base_nativetype;
|
||||
}
|
||||
|
||||
#into_pyobject
|
||||
|
@ -472,6 +477,8 @@ fn impl_descriptors(
|
|||
FnType::Getter => {
|
||||
let spec = FnSpec {
|
||||
tp: FnType::Getter,
|
||||
// Assume that the getter has &self receiver
|
||||
self_: Some(false),
|
||||
name: &name,
|
||||
python_name: name.unraw(),
|
||||
attrs: Vec::new(),
|
||||
|
@ -488,6 +495,8 @@ fn impl_descriptors(
|
|||
);
|
||||
let spec = FnSpec {
|
||||
tp: FnType::Setter,
|
||||
// Assume that the setter has &mut self receiver
|
||||
self_: Some(true),
|
||||
name: &setter_name,
|
||||
python_name: name.unraw(),
|
||||
attrs: Vec::new(),
|
||||
|
|
|
@ -45,7 +45,11 @@ fn check_generic(sig: &syn::Signature) -> syn::Result<()> {
|
|||
/// Generate function wrapper (PyCFunction, PyCFunctionWithKeywords)
|
||||
pub fn impl_wrap(cls: &syn::Type, spec: &FnSpec<'_>, noargs: bool) -> TokenStream {
|
||||
let body = impl_call(cls, &spec);
|
||||
let slf = impl_self("e! { &mut #cls });
|
||||
let borrow_self = spec.borrow_self();
|
||||
let slf = quote! {
|
||||
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
|
||||
let _slf = #borrow_self;
|
||||
};
|
||||
impl_wrap_common(cls, spec, noargs, slf, body)
|
||||
}
|
||||
|
||||
|
@ -60,7 +64,13 @@ pub fn impl_wrap_pyslf(
|
|||
let body = quote! {
|
||||
#cls::#name(_slf, #(#names),*)
|
||||
};
|
||||
let slf = impl_self(self_ty);
|
||||
let slf = quote! {
|
||||
let _cell = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
|
||||
let _slf: #self_ty = match pyo3::derive_utils::PySelf::from_cell(_cell) {
|
||||
Ok(_slf) => _slf,
|
||||
Err(e) => return e.restore_and_null(py),
|
||||
};
|
||||
};
|
||||
impl_wrap_common(cls, spec, noargs, slf, body)
|
||||
}
|
||||
|
||||
|
@ -123,6 +133,7 @@ pub fn impl_proto_wrap(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
|
|||
let python_name = &spec.python_name;
|
||||
let cb = impl_call(cls, &spec);
|
||||
let body = impl_arg_params(&spec, cb);
|
||||
let borrow_self = spec.borrow_self();
|
||||
|
||||
quote! {
|
||||
#[allow(unused_mut)]
|
||||
|
@ -134,7 +145,8 @@ pub fn impl_proto_wrap(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
|
|||
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
|
||||
let _py = pyo3::Python::assume_gil_acquired();
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
|
||||
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
|
||||
let _slf = #borrow_self;
|
||||
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
|
||||
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
|
||||
|
||||
|
@ -266,6 +278,8 @@ pub(crate) fn impl_wrap_getter(cls: &syn::Type, spec: &FnSpec) -> syn::Result<To
|
|||
quote! { _slf.#name() }
|
||||
};
|
||||
|
||||
let borrow_self = spec.borrow_self();
|
||||
|
||||
Ok(quote! {
|
||||
unsafe extern "C" fn __wrap(
|
||||
_slf: *mut pyo3::ffi::PyObject, _: *mut ::std::os::raw::c_void) -> *mut pyo3::ffi::PyObject
|
||||
|
@ -274,7 +288,8 @@ pub(crate) fn impl_wrap_getter(cls: &syn::Type, spec: &FnSpec) -> syn::Result<To
|
|||
|
||||
let _py = pyo3::Python::assume_gil_acquired();
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
|
||||
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
|
||||
let _slf = #borrow_self;
|
||||
|
||||
let result = pyo3::derive_utils::IntoPyResult::into_py_result(#fncall);
|
||||
|
||||
|
@ -312,6 +327,7 @@ pub(crate) fn impl_wrap_setter(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Resul
|
|||
}
|
||||
};
|
||||
|
||||
let borrow_self = spec.borrow_self();
|
||||
Ok(quote! {
|
||||
#[allow(unused_mut)]
|
||||
unsafe extern "C" fn __wrap(
|
||||
|
@ -321,7 +337,8 @@ pub(crate) fn impl_wrap_setter(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Resul
|
|||
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
|
||||
let _py = pyo3::Python::assume_gil_acquired();
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
|
||||
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
|
||||
let _slf = #borrow_self;
|
||||
let _value = _py.from_borrowed_ptr(_value);
|
||||
|
||||
let _result = match <#val_ty as pyo3::FromPyObject>::extract(_value) {
|
||||
|
@ -354,12 +371,6 @@ fn impl_call(_cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
|
|||
quote! { _slf.#fname(#(#names),*) }
|
||||
}
|
||||
|
||||
fn impl_self<T: quote::ToTokens>(self_ty: &T) -> TokenStream {
|
||||
quote! {
|
||||
let _slf: #self_ty = pyo3::FromPyPointer::from_borrowed_ptr(_py, _slf);
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a bool to "true" or "false"
|
||||
fn bool_to_ident(condition: bool) -> syn::Ident {
|
||||
if condition {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use crate::callback::{CallbackConverter, PyObjectCallbackConverter};
|
||||
use crate::err::PyResult;
|
||||
use crate::{ffi, IntoPy, IntoPyPointer, PyCell, PyClass, PyObject, Python};
|
||||
use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, PyRefMut, Python};
|
||||
use std::ptr;
|
||||
|
||||
/// Python Iterator Interface.
|
||||
|
@ -13,14 +13,14 @@ use std::ptr;
|
|||
/// `https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iter`
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyIterProtocol<'p>: PyClass {
|
||||
fn __iter__(slf: &mut PyCell<Self>) -> Self::Result
|
||||
fn __iter__(slf: PyRefMut<Self>) -> Self::Result
|
||||
where
|
||||
Self: PyIterIterProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __next__(slf: &mut PyCell<Self>) -> Self::Result
|
||||
fn __next__(slf: PyRefMut<Self>) -> Self::Result
|
||||
where
|
||||
Self: PyIterNextProtocol<'p>,
|
||||
{
|
||||
|
@ -77,7 +77,7 @@ where
|
|||
{
|
||||
#[inline]
|
||||
fn tp_iter() -> Option<ffi::getiterfunc> {
|
||||
py_unary_pyref_func!(
|
||||
py_unary_refmut_func!(
|
||||
PyIterIterProtocol,
|
||||
T::__iter__,
|
||||
T::Success,
|
||||
|
@ -105,7 +105,7 @@ where
|
|||
{
|
||||
#[inline]
|
||||
fn tp_iternext() -> Option<ffi::iternextfunc> {
|
||||
py_unary_pyref_func!(
|
||||
py_unary_refmut_func!(
|
||||
PyIterNextProtocol,
|
||||
T::__next__,
|
||||
Option<T::Success>,
|
||||
|
|
|
@ -39,17 +39,16 @@ macro_rules! py_unary_func {
|
|||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_unary_pyref_func {
|
||||
macro_rules! py_unary_refmut_func {
|
||||
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr) => {{
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> *mut $crate::ffi::PyObject
|
||||
where
|
||||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
use $crate::PyCell;
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf: &mut PyCell<T> = &mut *(slf as *mut PyCell<T>);
|
||||
let res = $class::$f(slf).into();
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let res = $class::$f(slf.borrow_mut()).into();
|
||||
$crate::callback::cb_convert($conv, py, res)
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::object::PyObject;
|
|||
use crate::type_object::{PyDowncastImpl, PyTypeInfo};
|
||||
use crate::types::PyAny;
|
||||
use crate::types::PyTuple;
|
||||
use crate::{ffi, gil, Py, Python};
|
||||
use crate::{ffi, gil, Py, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
/// This trait represents that, **we can do zero-cost conversion from the object to FFI pointer**.
|
||||
|
@ -244,74 +244,43 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod extract_impl {
|
||||
use super::*;
|
||||
|
||||
pub trait ExtractImpl<'a, Target>: Sized {
|
||||
fn extract(source: &'a PyAny) -> PyResult<Target>;
|
||||
impl<'a, T> FromPyObject<'a> for &'a PyCell<T>
|
||||
where
|
||||
T: PyClass,
|
||||
{
|
||||
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
||||
PyTryFrom::try_from(obj).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub struct Cloned {
|
||||
_private: (),
|
||||
}
|
||||
pub struct Reference {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> ExtractImpl<'a, T> for Cloned
|
||||
where
|
||||
T: Clone + PyTryFrom<'a>,
|
||||
Reference: ExtractImpl<'a, &'a T>,
|
||||
{
|
||||
fn extract(source: &'a PyAny) -> PyResult<T> {
|
||||
Ok(Reference::extract(source)?.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> ExtractImpl<'a, &'a T> for Reference
|
||||
where
|
||||
T: PyTryFrom<'a>,
|
||||
{
|
||||
fn extract(source: &'a PyAny) -> PyResult<&'a T> {
|
||||
Ok(T::try_from(source)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use extract_impl::ExtractImpl;
|
||||
|
||||
/// This is an internal trait for re-using `FromPyObject` implementations for many pyo3 types.
|
||||
///
|
||||
/// Users should implement `FromPyObject` directly instead of via this trait.
|
||||
pub trait FromPyObjectImpl {
|
||||
// Implement this trait with to specify the implementor of `extract_impl::ExtractImpl` to use for
|
||||
// extracting this type from Python objects.
|
||||
//
|
||||
// Example valid implementations are `extract_impl::Cloned`, `extract_impl::Reference`, and
|
||||
// `extract_impl::MutReference`, which are for extracting `T`, `&T` and `&mut T` respectively via
|
||||
// PyTryFrom.
|
||||
//
|
||||
// We deliberately don't require Impl: ExtractImpl here because we allow #[pyclass]
|
||||
// to specify an Impl which doesn't satisfy the ExtractImpl constraints.
|
||||
//
|
||||
// e.g. non-clone #[pyclass] can still have Impl: Cloned.
|
||||
//
|
||||
// We catch invalid Impls in the blanket impl for FromPyObject, which only
|
||||
// complains when .extract() is actually used.
|
||||
|
||||
/// The type which implements `ExtractImpl`.
|
||||
type Impl;
|
||||
}
|
||||
|
||||
impl<'a, T> FromPyObject<'a> for T
|
||||
where
|
||||
T: FromPyObjectImpl + 'a,
|
||||
<T as FromPyObjectImpl>::Impl: ExtractImpl<'a, T>,
|
||||
T: PyClass + Clone,
|
||||
{
|
||||
#[inline]
|
||||
fn extract(ob: &'a PyAny) -> PyResult<T> {
|
||||
<T as FromPyObjectImpl>::Impl::extract(ob)
|
||||
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
||||
let cell: &PyCell<Self> = PyTryFrom::try_from(obj)?;
|
||||
let ref_ = unsafe { cell.try_borrow_unguarded()? };
|
||||
Ok(ref_.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> FromPyObject<'a> for PyRef<'a, T>
|
||||
where
|
||||
T: PyClass,
|
||||
{
|
||||
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
||||
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
|
||||
cell.try_borrow().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T>
|
||||
where
|
||||
T: PyClass,
|
||||
{
|
||||
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
||||
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
|
||||
cell.try_borrow_mut().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,19 +314,32 @@ pub trait PyTryFrom<'v>: Sized + PyDowncastImpl<'v> {
|
|||
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v 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>;
|
||||
/// 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. With exact type check.
|
||||
fn try_into_exact(&self) -> Result<&T, PyDowncastError>;
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'v, T> PyTryFrom<'v> for T
|
||||
where
|
||||
T: PyDowncastImpl<'v> + PyTypeInfo,
|
||||
T: PyDowncastImpl<'v> + PyTypeInfo + PyNativeType,
|
||||
{
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError> {
|
||||
let value = value.into();
|
||||
|
@ -387,6 +369,36 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'v, T> PyTryFrom<'v> for PyCell<T>
|
||||
where
|
||||
T: 'v + PyClass,
|
||||
{
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError> {
|
||||
let value = value.into();
|
||||
unsafe {
|
||||
if T::is_instance(value) {
|
||||
Ok(Self::try_from_unchecked(value))
|
||||
} else {
|
||||
Err(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(Self::try_from_unchecked(value))
|
||||
} else {
|
||||
Err(PyDowncastError)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
|
||||
Self::unchecked_downcast(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts `()` to an empty Python tuple.
|
||||
impl FromPy<()> for Py<PyTuple> {
|
||||
fn from_py(_: (), py: Python) -> Py<PyTuple> {
|
||||
|
@ -449,6 +461,21 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
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<&'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<&'p Self> {
|
||||
NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell<T>))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::types::PyList;
|
||||
|
|
|
@ -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, AsPyRef, GILPool, IntoPy, PyObject, Python};
|
||||
use crate::{ffi, GILPool, IntoPy, PyObject, Python};
|
||||
use std::ptr;
|
||||
|
||||
/// Description of a python parameter; used for `parse_args()`.
|
||||
|
@ -100,8 +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)
|
||||
unimplemented!()
|
||||
let slice = args.slice(used_args as isize, nargs as isize).into_py(py);
|
||||
py.checked_cast_as(slice).unwrap()
|
||||
} else {
|
||||
args
|
||||
};
|
||||
|
@ -199,3 +199,40 @@ impl<T: PyClass, I: Into<PyClassInitializer<T>>> IntoPyNewResult<T, I> for PyRes
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Utitlities for basetype
|
||||
pub trait PyBaseTypeUtils {
|
||||
type Dict;
|
||||
type WeakRef;
|
||||
type Layout;
|
||||
type BaseNativeType;
|
||||
}
|
||||
|
||||
impl<T: PyClass> PyBaseTypeUtils for T {
|
||||
type Dict = T::Dict;
|
||||
type WeakRef = T::WeakRef;
|
||||
type Layout = crate::pycell::PyCellInner<T>;
|
||||
type BaseNativeType = T::BaseNativeType;
|
||||
}
|
||||
|
||||
pub trait PySelf<'a, T: PyClass>: Sized {
|
||||
fn from_cell(cell: &'a crate::PyCell<T>) -> PyResult<Self>;
|
||||
}
|
||||
|
||||
impl<'a, T: PyClass> PySelf<'a, T> for &'a crate::PyCell<T> {
|
||||
fn from_cell(cell: &'a crate::PyCell<T>) -> PyResult<Self> {
|
||||
Ok(cell)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PyClass> PySelf<'a, T> for crate::PyRef<'a, T> {
|
||||
fn from_cell(cell: &'a crate::PyCell<T>) -> PyResult<Self> {
|
||||
cell.try_borrow().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PyClass> PySelf<'a, T> for crate::PyRefMut<'a, T> {
|
||||
fn from_cell(cell: &'a crate::PyCell<T>) -> PyResult<Self> {
|
||||
cell.try_borrow_mut().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,9 +59,6 @@ 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
|
||||
|
|
|
@ -72,7 +72,7 @@ impl<T> PyClassAlloc for T
|
|||
where
|
||||
T: PyTypeInfo + PyClassWithFreeList,
|
||||
{
|
||||
unsafe fn alloc(_py: Python) -> *mut Self::ConcreteLayout {
|
||||
unsafe fn alloc(_py: Python) -> *mut Self::Layout {
|
||||
if let Some(obj) = <Self as PyClassWithFreeList>::get_free_list().pop() {
|
||||
ffi::PyObject_Init(obj, <Self as PyTypeInfo>::type_object() as *const _ as _);
|
||||
obj as _
|
||||
|
@ -81,7 +81,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn dealloc(py: Python, self_: *mut Self::ConcreteLayout) {
|
||||
unsafe fn dealloc(py: Python, self_: *mut Self::Layout) {
|
||||
(*self_).py_drop(py);
|
||||
|
||||
let obj = self_ as _;
|
||||
|
|
|
@ -39,8 +39,7 @@ impl<T> Py<T> {
|
|||
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<Py<T>>
|
||||
where
|
||||
T: PyClass,
|
||||
<T::BaseType as PyTypeInfo>::ConcreteLayout:
|
||||
crate::type_object::PyObjectSizedLayout<T::BaseType>,
|
||||
T::BaseLayout: crate::type_object::PyObjectSizedLayout<T::BaseType>,
|
||||
{
|
||||
let initializer = value.into();
|
||||
let obj = unsafe { initializer.create_cell(py)? };
|
||||
|
|
|
@ -119,7 +119,7 @@
|
|||
|
||||
pub use crate::class::*;
|
||||
pub use crate::conversion::{
|
||||
AsPyPointer, FromPy, FromPyObject, FromPyPointer, IntoPy, IntoPyPointer, PyTryFrom,
|
||||
AsPyPointer, FromPy, FromPyObject, FromPyPointer, IntoPy, IntoPyPointer, PyTryFrom, PyTryInto,
|
||||
ToBorrowedObject, ToPyObject,
|
||||
};
|
||||
pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult};
|
||||
|
@ -127,7 +127,7 @@ pub use crate::gil::{init_once, GILGuard, GILPool};
|
|||
pub use crate::instance::{AsPyRef, ManagedPyRef, Py, PyNativeType};
|
||||
pub use crate::object::PyObject;
|
||||
pub use crate::objectprotocol::ObjectProtocol;
|
||||
pub use crate::pycell::PyCell;
|
||||
pub use crate::pycell::{PyCell, PyRef, PyRefMut};
|
||||
pub use crate::pyclass::PyClass;
|
||||
pub use crate::pyclass_init::PyClassInitializer;
|
||||
pub use crate::python::{prepare_freethreaded_python, Python};
|
||||
|
@ -171,7 +171,7 @@ pub mod marshal;
|
|||
mod object;
|
||||
mod objectprotocol;
|
||||
pub mod prelude;
|
||||
mod pycell;
|
||||
pub mod pycell;
|
||||
pub mod pyclass;
|
||||
pub mod pyclass_init;
|
||||
pub mod pyclass_slots;
|
||||
|
|
|
@ -15,9 +15,10 @@ pub use crate::gil::GILGuard;
|
|||
pub use crate::instance::{AsPyRef, Py};
|
||||
pub use crate::object::PyObject;
|
||||
pub use crate::objectprotocol::ObjectProtocol;
|
||||
pub use crate::pycell::{PyCell, PyRef, PyRefMut};
|
||||
pub use crate::pyclass_init::PyClassInitializer;
|
||||
pub use crate::python::Python;
|
||||
pub use crate::{FromPy, FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, ToPyObject};
|
||||
pub use crate::{FromPy, FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, PyTryInto, 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;
|
||||
|
|
167
src/pycell.rs
167
src/pycell.rs
|
@ -1,43 +1,76 @@
|
|||
//! Traits and structs for `#[pyclass]`.
|
||||
use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
|
||||
use crate::conversion::{AsPyPointer, FromPyPointer, PyTryFrom, ToPyObject};
|
||||
use crate::err::PyDowncastError;
|
||||
use crate::pyclass::PyClass;
|
||||
use crate::pyclass_init::PyClassInitializer;
|
||||
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
||||
use crate::type_object::{PyDowncastImpl, PyObjectLayout, PyObjectSizedLayout};
|
||||
use crate::type_object::{PyDowncastImpl, PyObjectLayout, PyObjectSizedLayout, PyTypeInfo};
|
||||
use crate::types::PyAny;
|
||||
use crate::{ffi, gil, PyErr, PyObject, PyResult, PyTypeInfo, Python};
|
||||
use crate::{ffi, gil, PyErr, PyNativeType, PyObject, PyResult, Python};
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::fmt;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[repr(C)]
|
||||
pub struct PyCellBase<T: PyTypeInfo> {
|
||||
ob_base: T::Layout,
|
||||
borrow_flag: Cell<BorrowFlag>,
|
||||
}
|
||||
|
||||
unsafe impl<T> PyObjectLayout<T> for PyCellBase<T>
|
||||
where
|
||||
T: PyTypeInfo + PyNativeType,
|
||||
T::Layout: PyObjectSizedLayout<T>,
|
||||
{
|
||||
const IS_NATIVE_TYPE: bool = false;
|
||||
fn get_super_or(&mut self) -> Option<&mut T::BaseLayout> {
|
||||
None
|
||||
}
|
||||
unsafe fn unchecked_ref(&self) -> &T {
|
||||
&*((&self) as *const &Self as *const _)
|
||||
}
|
||||
unsafe fn unchecked_refmut(&self) -> &mut T {
|
||||
&mut *((&self) as *const &Self as *const _ as *mut _)
|
||||
}
|
||||
}
|
||||
|
||||
// This impl ensures `PyCellBase` can be a base type.
|
||||
impl<T> PyObjectSizedLayout<T> for PyCellBase<T>
|
||||
where
|
||||
T: PyTypeInfo + PyNativeType,
|
||||
T::Layout: PyObjectSizedLayout<T>,
|
||||
{
|
||||
}
|
||||
|
||||
/// Inner type of `PyCell` without dict slots and reference counter.
|
||||
/// This struct has two usages:
|
||||
/// 1. As an inner type of `PyRef` and `PyRefMut`.
|
||||
/// 2. As a base class when `#[pyclass(Base)]` is specified.
|
||||
#[doc(hidden)]
|
||||
#[repr(C)]
|
||||
pub struct PyCellBase<T: PyClass> {
|
||||
ob_base: <T::BaseType as PyTypeInfo>::ConcreteLayout,
|
||||
pub struct PyCellInner<T: PyClass> {
|
||||
ob_base: T::BaseLayout,
|
||||
value: ManuallyDrop<UnsafeCell<T>>,
|
||||
}
|
||||
|
||||
impl<T: PyClass> AsPyPointer for PyCellBase<T> {
|
||||
impl<T: PyClass> AsPyPointer for PyCellInner<T> {
|
||||
fn as_ptr(&self) -> *mut ffi::PyObject {
|
||||
(self as *const _) as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: PyClass> PyObjectLayout<T> for PyCellBase<T> {
|
||||
unsafe impl<T: PyClass> PyObjectLayout<T> for PyCellInner<T> {
|
||||
const IS_NATIVE_TYPE: bool = false;
|
||||
fn get_super_or(&mut self) -> Option<&mut <T::BaseType as PyTypeInfo>::ConcreteLayout> {
|
||||
fn get_super_or(&mut self) -> Option<&mut T::BaseLayout> {
|
||||
Some(&mut self.ob_base)
|
||||
}
|
||||
unsafe fn unchecked_ref(&self) -> &T {
|
||||
&*self.value.get()
|
||||
}
|
||||
unsafe fn unchecked_refmut(&mut self) -> &mut T {
|
||||
unsafe fn unchecked_refmut(&self) -> &mut T {
|
||||
&mut *self.value.get()
|
||||
}
|
||||
unsafe fn py_init(&mut self, value: T) {
|
||||
|
@ -49,6 +82,20 @@ unsafe impl<T: PyClass> PyObjectLayout<T> for PyCellBase<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// This impl ensures `PyCellInner` can be a base type.
|
||||
impl<T: PyClass> PyObjectSizedLayout<T> for PyCellInner<T> {}
|
||||
|
||||
impl<T: PyClass> PyCellInner<T> {
|
||||
fn get_borrow_flag(&self) -> BorrowFlag {
|
||||
let base = (&self.ob_base) as *const _ as *const PyCellBase<T::BaseNativeType>;
|
||||
unsafe { (*base).borrow_flag.get() }
|
||||
}
|
||||
fn set_borrow_flag(&self, flag: BorrowFlag) {
|
||||
let base = (&self.ob_base) as *const _ as *const PyCellBase<T::BaseNativeType>;
|
||||
unsafe { (*base).borrow_flag.set(flag) }
|
||||
}
|
||||
}
|
||||
|
||||
/// `PyCell` represents the concrete layout of `T: PyClass` when it is converted
|
||||
/// to a Python class.
|
||||
///
|
||||
|
@ -74,8 +121,7 @@ unsafe impl<T: PyClass> PyObjectLayout<T> for PyCellBase<T> {
|
|||
/// ```
|
||||
#[repr(C)]
|
||||
pub struct PyCell<T: PyClass> {
|
||||
base: PyCellBase<T>,
|
||||
borrow_flag: Cell<BorrowFlag>,
|
||||
inner: PyCellInner<T>,
|
||||
dict: T::Dict,
|
||||
weakref: T::WeakRef,
|
||||
}
|
||||
|
@ -84,8 +130,7 @@ impl<T: PyClass> PyCell<T> {
|
|||
/// Make new `PyCell` on the Python heap and returns the reference of it.
|
||||
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self>
|
||||
where
|
||||
<T::BaseType as PyTypeInfo>::ConcreteLayout:
|
||||
crate::type_object::PyObjectSizedLayout<T::BaseType>,
|
||||
T::BaseLayout: crate::type_object::PyObjectSizedLayout<T::BaseType>,
|
||||
{
|
||||
unsafe {
|
||||
let initializer = value.into();
|
||||
|
@ -103,57 +148,51 @@ impl<T: PyClass> PyCell<T> {
|
|||
}
|
||||
|
||||
pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
|
||||
let flag = self.borrow_flag.get();
|
||||
let flag = self.inner.get_borrow_flag();
|
||||
if flag != BorrowFlag::HAS_MUTABLE_BORROW {
|
||||
Err(PyBorrowError { _private: () })
|
||||
} else {
|
||||
self.borrow_flag.set(flag.increment());
|
||||
Ok(PyRef {
|
||||
value: &self.base,
|
||||
flag: &self.borrow_flag,
|
||||
})
|
||||
self.inner.set_borrow_flag(flag.increment());
|
||||
Ok(PyRef { inner: &self.inner })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError> {
|
||||
if self.borrow_flag.get() != BorrowFlag::UNUSED {
|
||||
if self.inner.get_borrow_flag() != BorrowFlag::UNUSED {
|
||||
Err(PyBorrowMutError { _private: () })
|
||||
} else {
|
||||
self.borrow_flag.set(BorrowFlag::HAS_MUTABLE_BORROW);
|
||||
Ok(PyRefMut {
|
||||
value: unsafe { &mut *(self.base.as_ptr() as *mut _) },
|
||||
flag: &self.borrow_flag,
|
||||
})
|
||||
self.inner.set_borrow_flag(BorrowFlag::HAS_MUTABLE_BORROW);
|
||||
Ok(PyRefMut { inner: &self.inner })
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
|
||||
if self.borrow_flag.get() != BorrowFlag::HAS_MUTABLE_BORROW {
|
||||
if self.inner.get_borrow_flag() != BorrowFlag::HAS_MUTABLE_BORROW {
|
||||
Err(PyBorrowError { _private: () })
|
||||
} else {
|
||||
Ok(&*self.base.value.get())
|
||||
Ok(&*self.inner.value.get())
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn try_borrow_mut_unguarded(&self) -> Result<&mut T, PyBorrowMutError> {
|
||||
if self.borrow_flag.get() != BorrowFlag::UNUSED {
|
||||
if self.inner.get_borrow_flag() != BorrowFlag::UNUSED {
|
||||
Err(PyBorrowMutError { _private: () })
|
||||
} else {
|
||||
Ok(&mut *self.base.value.get())
|
||||
Ok(&mut *self.inner.value.get())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self>
|
||||
where
|
||||
<T::BaseType as PyTypeInfo>::ConcreteLayout:
|
||||
crate::type_object::PyObjectSizedLayout<T::BaseType>,
|
||||
T::BaseLayout: crate::type_object::PyObjectSizedLayout<T::BaseType>,
|
||||
{
|
||||
let base = T::alloc(py);
|
||||
if base.is_null() {
|
||||
return Err(PyErr::fetch(py));
|
||||
}
|
||||
let base = base as *mut PyCellBase<T::BaseNativeType>;
|
||||
(*base).borrow_flag = Cell::new(BorrowFlag::UNUSED);
|
||||
let self_ = base as *mut Self;
|
||||
(*self_).borrow_flag = Cell::new(BorrowFlag::UNUSED);
|
||||
(*self_).dict = T::Dict::new();
|
||||
(*self_).weakref = T::WeakRef::new();
|
||||
Ok(self_)
|
||||
|
@ -162,23 +201,23 @@ impl<T: PyClass> PyCell<T> {
|
|||
|
||||
unsafe impl<T: PyClass> PyObjectLayout<T> for PyCell<T> {
|
||||
const IS_NATIVE_TYPE: bool = false;
|
||||
fn get_super_or(&mut self) -> Option<&mut <T::BaseType as PyTypeInfo>::ConcreteLayout> {
|
||||
Some(&mut self.base.ob_base)
|
||||
fn get_super_or(&mut self) -> Option<&mut T::BaseLayout> {
|
||||
Some(&mut self.inner.ob_base)
|
||||
}
|
||||
unsafe fn unchecked_ref(&self) -> &T {
|
||||
self.base.unchecked_ref()
|
||||
self.inner.unchecked_ref()
|
||||
}
|
||||
unsafe fn unchecked_refmut(&mut self) -> &mut T {
|
||||
self.base.unchecked_refmut()
|
||||
unsafe fn unchecked_refmut(&self) -> &mut T {
|
||||
self.inner.unchecked_refmut()
|
||||
}
|
||||
unsafe fn py_init(&mut self, value: T) {
|
||||
self.base.value = ManuallyDrop::new(UnsafeCell::new(value));
|
||||
self.inner.value = ManuallyDrop::new(UnsafeCell::new(value));
|
||||
}
|
||||
unsafe fn py_drop(&mut self, py: Python) {
|
||||
ManuallyDrop::drop(&mut self.base.value);
|
||||
ManuallyDrop::drop(&mut self.inner.value);
|
||||
self.dict.clear_dict(py);
|
||||
self.weakref.clear_weakrefs(self.as_ptr(), py);
|
||||
self.base.ob_base.py_drop(py);
|
||||
self.inner.ob_base.py_drop(py);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,8 +228,6 @@ unsafe impl<'py, T: 'py + PyClass> PyDowncastImpl<'py> for PyCell<T> {
|
|||
private_impl! {}
|
||||
}
|
||||
|
||||
impl<T: PyClass> PyObjectSizedLayout<T> for PyCell<T> {}
|
||||
|
||||
impl<T: PyClass> AsPyPointer for PyCell<T> {
|
||||
fn as_ptr(&self) -> *mut ffi::PyObject {
|
||||
(self as *const _) as *mut _
|
||||
|
@ -203,35 +240,13 @@ impl<T: PyClass> ToPyObject for &PyCell<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: PyClass> ToPyObject for &mut PyCell<T> {
|
||||
fn to_object(&self, py: Python<'_>) -> PyObject {
|
||||
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
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<&'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<&'p Self> {
|
||||
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>,
|
||||
inner: &'p PyCellInner<T>,
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> PyRef<'p, T> {
|
||||
pub fn get_super(&'p self) -> &'p T::BaseType {
|
||||
unsafe { self.value.ob_base.unchecked_ref() }
|
||||
unsafe { self.inner.ob_base.unchecked_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,27 +255,27 @@ impl<'p, T: PyClass> Deref for PyRef<'p, T> {
|
|||
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { self.value.unchecked_ref() }
|
||||
unsafe { self.inner.unchecked_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> Drop for PyRef<'p, T> {
|
||||
fn drop(&mut self) {
|
||||
self.flag.set(self.flag.get().decrement());
|
||||
let flag = self.inner.get_borrow_flag();
|
||||
self.inner.set_borrow_flag(flag.decrement())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PyRefMut<'p, T: PyClass> {
|
||||
value: &'p mut PyCellBase<T>,
|
||||
flag: &'p Cell<BorrowFlag>,
|
||||
inner: &'p PyCellInner<T>,
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> PyRefMut<'p, T> {
|
||||
pub fn get_super(&'p self) -> &'p T::BaseType {
|
||||
unsafe { self.value.ob_base.unchecked_ref() }
|
||||
unsafe { self.inner.ob_base.unchecked_ref() }
|
||||
}
|
||||
pub fn get_super_mut(&'p mut self) -> &'p mut T::BaseType {
|
||||
unsafe { self.value.ob_base.unchecked_refmut() }
|
||||
pub fn get_super_mut(&'p self) -> &'p mut T::BaseType {
|
||||
unsafe { self.inner.ob_base.unchecked_refmut() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,20 +284,20 @@ impl<'p, T: PyClass> Deref for PyRefMut<'p, T> {
|
|||
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { self.value.unchecked_ref() }
|
||||
unsafe { self.inner.unchecked_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> DerefMut for PyRefMut<'p, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { self.value.unchecked_refmut() }
|
||||
unsafe { self.inner.unchecked_refmut() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> Drop for PyRefMut<'p, T> {
|
||||
fn drop(&mut self) {
|
||||
self.flag.set(BorrowFlag::UNUSED);
|
||||
self.inner.set_borrow_flag(BorrowFlag::UNUSED)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use crate::class::methods::{PyMethodDefType, PyMethodsProtocol};
|
||||
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
||||
use crate::type_object::{type_flags, PyObjectLayout};
|
||||
use crate::{class, ffi, gil, PyCell, PyErr, PyResult, PyTypeInfo, Python};
|
||||
use crate::{class, ffi, gil, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Python};
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
|
@ -10,9 +10,8 @@ use std::ptr;
|
|||
#[inline]
|
||||
pub(crate) unsafe fn default_alloc<T: PyTypeInfo>() -> *mut ffi::PyObject {
|
||||
let type_obj = T::type_object();
|
||||
if T::FLAGS & type_flags::EXTENDED != 0
|
||||
&& <T::BaseType as PyTypeInfo>::ConcreteLayout::IS_NATIVE_TYPE
|
||||
{
|
||||
// if the class derives native types(e.g., PyDict), call special new
|
||||
if T::FLAGS & type_flags::EXTENDED != 0 && T::BaseLayout::IS_NATIVE_TYPE {
|
||||
let base_tp = <T::BaseType as PyTypeInfo>::type_object();
|
||||
if let Some(base_new) = base_tp.tp_new {
|
||||
return base_new(type_obj as *const _ as _, ptr::null_mut(), ptr::null_mut());
|
||||
|
@ -28,7 +27,7 @@ pub trait PyClassAlloc: PyTypeInfo + Sized {
|
|||
///
|
||||
/// # Safety
|
||||
/// This function must return a valid pointer to the Python heap.
|
||||
unsafe fn alloc(_py: Python) -> *mut Self::ConcreteLayout {
|
||||
unsafe fn alloc(_py: Python) -> *mut Self::Layout {
|
||||
default_alloc::<Self>() as _
|
||||
}
|
||||
|
||||
|
@ -36,7 +35,7 @@ pub trait PyClassAlloc: PyTypeInfo + Sized {
|
|||
///
|
||||
/// # Safety
|
||||
/// `self_` must be a valid pointer to the Python heap.
|
||||
unsafe fn dealloc(py: Python, self_: *mut Self::ConcreteLayout) {
|
||||
unsafe fn dealloc(py: Python, self_: *mut Self::Layout) {
|
||||
(*self_).py_drop(py);
|
||||
let obj = self_ as _;
|
||||
if ffi::PyObject_CallFinalizerFromDealloc(obj) < 0 {
|
||||
|
@ -72,10 +71,12 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) {
|
|||
/// The `#[pyclass]` attribute automatically implements this trait for your Rust struct,
|
||||
/// so you don't have to use this trait directly.
|
||||
pub trait PyClass:
|
||||
PyTypeInfo<ConcreteLayout = PyCell<Self>> + Sized + PyClassAlloc + PyMethodsProtocol
|
||||
PyTypeInfo<Layout = PyCell<Self>> + Sized + PyClassAlloc + PyMethodsProtocol
|
||||
{
|
||||
type Dict: PyClassDict;
|
||||
type WeakRef: PyClassWeakRef;
|
||||
/// The closest native ancestor.
|
||||
type BaseNativeType: PyTypeInfo + PyNativeType;
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
|
@ -111,12 +112,12 @@ where
|
|||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let _pool = gil::GILPool::new_no_pointers(py);
|
||||
<T as PyClassAlloc>::dealloc(py, (obj as *mut T::ConcreteLayout) as _)
|
||||
<T as PyClassAlloc>::dealloc(py, (obj as *mut T::Layout) as _)
|
||||
}
|
||||
type_object.tp_dealloc = Some(tp_dealloc_callback::<T>);
|
||||
|
||||
// type size
|
||||
type_object.tp_basicsize = std::mem::size_of::<T::ConcreteLayout>() as ffi::Py_ssize_t;
|
||||
type_object.tp_basicsize = std::mem::size_of::<T::Layout>() as ffi::Py_ssize_t;
|
||||
|
||||
let mut offset = type_object.tp_basicsize;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::marker::PhantomData;
|
|||
/// This trait is intended to use internally for distinguishing `#[pyclass]` and
|
||||
/// Python native types.
|
||||
pub trait PyObjectInit<T: PyTypeInfo>: Sized {
|
||||
fn init_class(self, layout: &mut T::ConcreteLayout);
|
||||
fn init_class<L: PyObjectLayout<T>>(self, layout: &mut L);
|
||||
private_decl! {}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ pub trait PyObjectInit<T: PyTypeInfo>: Sized {
|
|||
pub struct PyNativeTypeInitializer<T: PyTypeInfo>(PhantomData<T>);
|
||||
|
||||
impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
|
||||
fn init_class(self, _layout: &mut T::ConcreteLayout) {}
|
||||
fn init_class<L: PyObjectLayout<T>>(self, _layout: &mut L) {}
|
||||
private_impl! {}
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,7 @@ impl<T: PyClass> PyClassInitializer<T> {
|
|||
pub fn add_subclass<S>(self, subclass_value: S) -> PyClassInitializer<S>
|
||||
where
|
||||
S: PyClass + PyTypeInfo<BaseType = T>,
|
||||
S::BaseLayout: PyObjectSizedLayout<T>,
|
||||
S::BaseType: PyTypeInfo<Initializer = Self>,
|
||||
{
|
||||
PyClassInitializer::new(subclass_value, self)
|
||||
|
@ -117,7 +118,7 @@ impl<T: PyClass> PyClassInitializer<T> {
|
|||
pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCell<T>>
|
||||
where
|
||||
T: PyClass,
|
||||
<T::BaseType as PyTypeInfo>::ConcreteLayout: PyObjectSizedLayout<T::BaseType>,
|
||||
T::BaseLayout: PyObjectSizedLayout<T::BaseType>,
|
||||
{
|
||||
let cell = PyCell::internal_new(py)?;
|
||||
self.init_class(&mut *cell);
|
||||
|
@ -126,12 +127,12 @@ impl<T: PyClass> PyClassInitializer<T> {
|
|||
}
|
||||
|
||||
impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
|
||||
fn init_class(self, obj: &mut T::ConcreteLayout) {
|
||||
fn init_class<L: PyObjectLayout<T>>(self, layout: &mut L) {
|
||||
let Self { init, super_init } = self;
|
||||
unsafe {
|
||||
obj.py_init(init);
|
||||
layout.py_init(init);
|
||||
}
|
||||
if let Some(super_obj) = obj.get_super_or() {
|
||||
if let Some(super_obj) = layout.get_super_or() {
|
||||
super_init.init_class(super_obj);
|
||||
}
|
||||
}
|
||||
|
@ -151,6 +152,7 @@ where
|
|||
impl<S, B> From<(S, B)> for PyClassInitializer<S>
|
||||
where
|
||||
S: PyClass + PyTypeInfo<BaseType = B>,
|
||||
S::BaseLayout: PyObjectSizedLayout<B>,
|
||||
B: PyClass + PyTypeInfo<Initializer = PyClassInitializer<B>>,
|
||||
B::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<B::BaseType>>,
|
||||
{
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
//! Python type object information
|
||||
|
||||
use crate::instance::Py;
|
||||
use crate::pyclass::{initialize_type_object, PyClass};
|
||||
use crate::pyclass_init::PyObjectInit;
|
||||
use crate::types::{PyAny, PyType};
|
||||
use crate::{ffi, AsPyPointer, Python};
|
||||
use crate::{ffi, AsPyPointer, Py, Python};
|
||||
use std::cell::UnsafeCell;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
@ -17,14 +16,13 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||
/// This trait is intended to be used internally.
|
||||
pub unsafe trait PyObjectLayout<T: PyTypeInfo> {
|
||||
const IS_NATIVE_TYPE: bool = true;
|
||||
|
||||
fn get_super_or(&mut self) -> Option<&mut <T::BaseType as PyTypeInfo>::ConcreteLayout> {
|
||||
fn get_super_or(&mut self) -> Option<&mut T::BaseLayout> {
|
||||
None
|
||||
}
|
||||
unsafe fn py_init(&mut self, _value: T) {}
|
||||
unsafe fn py_drop(&mut self, _py: Python) {}
|
||||
unsafe fn unchecked_ref(&self) -> &T;
|
||||
unsafe fn unchecked_refmut(&mut self) -> &mut T;
|
||||
unsafe fn unchecked_refmut(&self) -> &mut T;
|
||||
}
|
||||
|
||||
/// `T: PyObjectSizedLayout<U>` represents `T` is not a instance of
|
||||
|
@ -100,9 +98,14 @@ pub unsafe trait PyTypeInfo: Sized {
|
|||
type BaseType: PyTypeInfo + PyTypeObject;
|
||||
|
||||
/// Layout
|
||||
type ConcreteLayout: PyObjectLayout<Self>;
|
||||
type Layout: PyObjectLayout<Self>;
|
||||
|
||||
/// This type is an abstraction layer for `AsPyRef`.
|
||||
/// Layout of Basetype
|
||||
type BaseLayout: PyObjectLayout<Self::BaseType>;
|
||||
|
||||
/// Abstraction layer for `AsPyRef`.
|
||||
///
|
||||
/// Simply, it's `Self` for native types and `PyCell<Self>` for pyclasses.
|
||||
type Reference;
|
||||
|
||||
/// Initializer for layout
|
||||
|
|
|
@ -27,8 +27,8 @@ unsafe impl crate::type_object::PyObjectLayout<PyAny> for ffi::PyObject {
|
|||
unsafe fn unchecked_ref(&self) -> &PyAny {
|
||||
&*((&self) as *const &Self as *const _)
|
||||
}
|
||||
unsafe fn unchecked_refmut(&mut self) -> &mut PyAny {
|
||||
&mut *((&self) as *const &mut Self as *const _ as *mut _)
|
||||
unsafe fn unchecked_refmut(&self) -> &mut PyAny {
|
||||
&mut *((&self) as *const &Self as *const _ as *mut _)
|
||||
}
|
||||
}
|
||||
impl crate::type_object::PyObjectSizedLayout<PyAny> for ffi::PyObject {}
|
||||
|
|
|
@ -62,8 +62,8 @@ macro_rules! impl_layout {
|
|||
unsafe fn unchecked_ref(&self) -> &$name {
|
||||
&*((&self) as *const &Self as *const _)
|
||||
}
|
||||
unsafe fn unchecked_refmut(&mut self) -> &mut $name {
|
||||
&mut *((&self) as *const &mut Self as *const _ as *mut _)
|
||||
unsafe fn unchecked_refmut(&self) -> &mut $name {
|
||||
&mut *((&self) as *const &Self as *const _ as *mut _)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -74,6 +74,12 @@ macro_rules! pyobject_native_type {
|
|||
($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => {
|
||||
impl_layout!($name, $layout);
|
||||
impl $crate::type_object::PyObjectSizedLayout<$name> for $layout {}
|
||||
impl $crate::derive_utils::PyBaseTypeUtils for $name {
|
||||
type Dict = $crate::pyclass_slots::PyClassDummySlot;
|
||||
type WeakRef = $crate::pyclass_slots::PyClassDummySlot;
|
||||
type Layout = $crate::pycell::PyCellBase<$name>;
|
||||
type BaseNativeType = $name;
|
||||
}
|
||||
pyobject_native_type_named!($name $(,$type_param)*);
|
||||
pyobject_native_type_convert!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*);
|
||||
pyobject_native_type_extract!($name $(,$type_param)*);
|
||||
|
@ -117,8 +123,10 @@ macro_rules! pyobject_native_var_type {
|
|||
// because rust-numpy has a special implementation.
|
||||
macro_rules! pyobject_native_type_extract {
|
||||
($name: ty $(,$type_param: ident)*) => {
|
||||
impl<$($type_param,)*> $crate::conversion::FromPyObjectImpl for &'_ $name {
|
||||
type Impl = $crate::conversion::extract_impl::Reference;
|
||||
impl<'py, $($type_param,)*> $crate::FromPyObject<'py> for &'py $name {
|
||||
fn extract(obj: &'py crate::types::PyAny) -> $crate::PyResult<Self> {
|
||||
$crate::PyTryFrom::try_from(obj).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +138,8 @@ macro_rules! pyobject_native_type_convert(
|
|||
unsafe impl<$($type_param,)*> $crate::type_object::PyTypeInfo for $name {
|
||||
type Type = ();
|
||||
type BaseType = $crate::types::PyAny;
|
||||
type ConcreteLayout = $layout;
|
||||
type Layout = $layout;
|
||||
type BaseLayout = ffi::PyObject;
|
||||
type Reference = $name;
|
||||
type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ fn empty_class_with_new() {
|
|||
assert!(typeobj
|
||||
.call((), None)
|
||||
.unwrap()
|
||||
.cast_as::<EmptyClassWithNew>()
|
||||
.cast_as::<PyCell<EmptyClassWithNew>>()
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,9 @@ fn new_with_one_arg() {
|
|||
let py = gil.python();
|
||||
let typeobj = py.get_type::<NewWithOneArg>();
|
||||
let wrp = typeobj.call((42,), None).unwrap();
|
||||
let obj = wrp.cast_as::<NewWithOneArg>().unwrap();
|
||||
assert_eq!(obj._data, 42);
|
||||
let obj = wrp.cast_as::<PyCell<NewWithOneArg>>().unwrap();
|
||||
let obj_ref = obj.borrow();
|
||||
assert_eq!(obj_ref._data, 42);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
|
@ -73,7 +74,8 @@ fn new_with_two_args() {
|
|||
.call((10, 20), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.unwrap();
|
||||
let obj = wrp.cast_as::<NewWithTwoArgs>().unwrap();
|
||||
assert_eq!(obj._data1, 10);
|
||||
assert_eq!(obj._data2, 20);
|
||||
let obj = wrp.cast_as::<PyCell<NewWithTwoArgs>>().unwrap();
|
||||
let obj_ref = obj.borrow();
|
||||
assert_eq!(obj_ref._data1, 10);
|
||||
assert_eq!(obj_ref._data2, 20);
|
||||
}
|
||||
|
|
4
tests/test_dunder.rs
Executable file → Normal file
4
tests/test_dunder.rs
Executable file → Normal file
|
@ -53,11 +53,11 @@ struct Iterator {
|
|||
|
||||
#[pyproto]
|
||||
impl<'p> PyIterProtocol for Iterator {
|
||||
fn __iter__(slf: &mut PyCell<Self>) -> PyResult<Py<Iterator>> {
|
||||
fn __iter__(slf: PyRefMut<Self>) -> PyResult<Py<Iterator>> {
|
||||
Ok(slf.into())
|
||||
}
|
||||
|
||||
fn __next__(slf: &mut PyCell<Self>) -> PyResult<Option<i32>> {
|
||||
fn __next__(slf: PyRefMut<Self>) -> PyResult<Option<i32>> {
|
||||
Ok(slf.iter.next())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use pyo3::class::PyTraverseError;
|
|||
use pyo3::class::PyVisit;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyAny, PyTuple};
|
||||
use pyo3::{ffi, py_run, AsPyPointer, PyCell};
|
||||
use pyo3::{ffi, py_run, AsPyPointer, PyCell, PyTryInto};
|
||||
use std::cell::RefCell;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
@ -153,7 +153,7 @@ fn gc_integration() {
|
|||
{
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let inst = PyCell::new_mut(
|
||||
let inst = PyCell::new(
|
||||
py,
|
||||
GCIntegration {
|
||||
self_ref: RefCell::new(py.None()),
|
||||
|
@ -164,7 +164,8 @@ fn gc_integration() {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
*inst.self_ref.borrow_mut() = inst.to_object(py);
|
||||
let borrow = inst.borrow_mut();
|
||||
*borrow.self_ref.borrow_mut() = inst.to_object(py);
|
||||
}
|
||||
|
||||
let gil = Python::acquire_gil();
|
||||
|
@ -188,7 +189,7 @@ impl PyGCProtocol for GCIntegration2 {
|
|||
fn gc_integration2() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let inst = PyCell::new_ref(py, GCIntegration2 {}).unwrap();
|
||||
let inst = PyCell::new(py, GCIntegration2 {}).unwrap();
|
||||
py_run!(py, inst, "import gc; assert inst in gc.get_objects()");
|
||||
}
|
||||
|
||||
|
@ -199,7 +200,7 @@ struct WeakRefSupport {}
|
|||
fn weakref_support() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let inst = PyCell::new_ref(py, WeakRefSupport {}).unwrap();
|
||||
let inst = PyCell::new(py, WeakRefSupport {}).unwrap();
|
||||
py_run!(
|
||||
py,
|
||||
inst,
|
||||
|
@ -264,12 +265,11 @@ fn inheritance_with_new_methods_with_drop() {
|
|||
let typeobj = py.get_type::<SubClassWithDrop>();
|
||||
let inst = typeobj.call((), None).unwrap();
|
||||
|
||||
let obj = SubClassWithDrop::try_from_mut(inst).unwrap();
|
||||
obj.data = Some(Arc::clone(&drop_called1));
|
||||
|
||||
let base: &mut <SubClassWithDrop as pyo3::PyTypeInfo>::BaseType =
|
||||
unsafe { py.mut_from_borrowed_ptr(inst.as_ptr()) };
|
||||
base.data = Some(Arc::clone(&drop_called2));
|
||||
let obj: &PyCell<SubClassWithDrop> = inst.try_into().unwrap();
|
||||
let mut obj_ref_mut = obj.borrow_mut();
|
||||
obj_ref_mut.data = Some(Arc::clone(&drop_called1));
|
||||
let super_ = obj_ref_mut.get_super_mut();
|
||||
super_.data = Some(Arc::clone(&drop_called2));
|
||||
}
|
||||
|
||||
assert!(drop_called1.load(Ordering::Relaxed));
|
||||
|
|
|
@ -64,7 +64,7 @@ impl PySequenceProtocol for ByteSequence {
|
|||
}
|
||||
}
|
||||
|
||||
fn __concat__(&self, other: &Self) -> PyResult<Self> {
|
||||
fn __concat__(&self, other: PyRef<'p, Self>) -> PyResult<Self> {
|
||||
let mut elements = self.elements.clone();
|
||||
elements.extend_from_slice(&other.elements);
|
||||
Ok(Self { elements })
|
||||
|
|
Loading…
Reference in a new issue