finish off implementation
This commit is contained in:
parent
7520b49ac1
commit
6f39deaa37
|
@ -592,29 +592,12 @@ fn impl_enum_class(
|
|||
let default_items =
|
||||
gen_default_items(cls, vec![default_repr_impl, default_richcmp, default_int]);
|
||||
|
||||
let mutability = if args.is_immutable {
|
||||
quote! {
|
||||
unsafe impl _pyo3::pyclass::ImmutablePyClass for #cls {}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
unsafe impl _pyo3::pyclass::MutablePyClass for #cls {}
|
||||
|
||||
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls
|
||||
{
|
||||
type Target = _pyo3::PyRefMut<'a, #cls>;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
const _: () = {
|
||||
use #krate as _pyo3;
|
||||
|
||||
#pytypeinfo
|
||||
|
||||
#mutability
|
||||
|
||||
#pyclass_impls
|
||||
|
||||
#default_items
|
||||
|
@ -801,7 +784,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
};
|
||||
|
||||
let base_nativetype = if attr.has_extends {
|
||||
quote! { <Self::BaseType as _pyo3::impl_::pyclass::PyClassBaseType>::BaseNativeType }
|
||||
quote! { <Self::BaseType as _pyo3::impl_::pyclass::PyClassBaseType<Self::Mutability>>::BaseNativeType }
|
||||
} else {
|
||||
quote! { _pyo3::PyAny }
|
||||
};
|
||||
|
@ -810,7 +793,6 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
type Dict = #dict;
|
||||
type WeakRef = #weakref;
|
||||
type BaseNativeType = #base_nativetype;
|
||||
type Mutability = _pyo3::pycell::Immutable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -944,7 +926,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
};
|
||||
|
||||
quote! {
|
||||
impl _pyo3::impl_::pyclass::PyClassImpl<#mutability> for #cls {
|
||||
impl _pyo3::impl_::pyclass::PyClassImpl for #cls {
|
||||
const DOC: &'static str = #doc;
|
||||
const IS_GC: bool = #is_gc;
|
||||
const IS_BASETYPE: bool = #is_basetype;
|
||||
|
@ -954,6 +936,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
type BaseType = #base;
|
||||
type ThreadChecker = #thread_checker;
|
||||
#inventory
|
||||
type Mutability = #mutability;
|
||||
|
||||
fn for_all_items(visitor: &mut dyn ::std::ops::FnMut(& _pyo3::impl_::pyclass::PyClassItems)) {
|
||||
use _pyo3::impl_::pyclass::*;
|
||||
|
@ -985,9 +968,9 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
#dict_offset
|
||||
|
||||
#weaklist_offset
|
||||
|
||||
#inventory_class
|
||||
}
|
||||
|
||||
#inventory_class
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@ use crate::{
|
|||
exceptions::{PyAttributeError, PyNotImplementedError},
|
||||
ffi,
|
||||
impl_::freelist::FreeList,
|
||||
pycell::{Mutability, PyCellLayout},
|
||||
pycell::{Mutability, Mutable, PyCellLayout},
|
||||
pyclass::MutablePyClass,
|
||||
pyclass_init::PyObjectInit,
|
||||
type_object::{PyLayout, PyTypeObject},
|
||||
PyCell, PyClass, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
|
||||
|
@ -145,7 +146,7 @@ unsafe impl Sync for PyClassItems {}
|
|||
///
|
||||
/// Users are discouraged from implementing this trait manually; it is a PyO3 implementation detail
|
||||
/// and may be changed at any time.
|
||||
pub trait PyClassImpl<M: Mutability>: Sized {
|
||||
pub trait PyClassImpl: Sized {
|
||||
/// Class doc string
|
||||
const DOC: &'static str = "\0";
|
||||
|
||||
|
@ -162,7 +163,10 @@ pub trait PyClassImpl<M: Mutability>: Sized {
|
|||
type Layout: PyLayout<Self>;
|
||||
|
||||
/// Base class
|
||||
type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType<M>;
|
||||
type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType<Self::Mutability>;
|
||||
|
||||
/// Immutable or mutable
|
||||
type Mutability: Mutability;
|
||||
|
||||
/// This handles following two situations:
|
||||
/// 1. In case `T` is `Send`, stub `ThreadChecker` is used and does nothing.
|
||||
|
@ -818,13 +822,13 @@ impl<T> PyClassThreadChecker<T> for ThreadCheckerImpl<T> {
|
|||
/// Thread checker for types that have `Send` and `extends=...`.
|
||||
/// Ensures that `T: Send` and the parent is not accessed by another thread.
|
||||
#[doc(hidden)]
|
||||
pub struct ThreadCheckerInherited<T: Send, U: PyClassBaseType<M>, M: Mutability>(
|
||||
pub struct ThreadCheckerInherited<T: PyClass + Send, U: PyClassBaseType<T::Mutability>>(
|
||||
PhantomData<T>,
|
||||
U::ThreadChecker,
|
||||
);
|
||||
|
||||
impl<T: Send, U: PyClassBaseType<M>, M: Mutability> PyClassThreadChecker<T>
|
||||
for ThreadCheckerInherited<T, U, M>
|
||||
impl<T: PyClass + Send, U: PyClassBaseType<T::Mutability>> PyClassThreadChecker<T>
|
||||
for ThreadCheckerInherited<T, U>
|
||||
{
|
||||
fn ensure(&self) {
|
||||
self.1.ensure();
|
||||
|
@ -843,8 +847,10 @@ pub trait PyClassBaseType<M: Mutability>: Sized {
|
|||
type Initializer: PyObjectInit<Self>;
|
||||
}
|
||||
|
||||
/// All PyClasses can be used as a base type.
|
||||
impl<T: PyClass> PyClassBaseType<T::Mutability> for T {
|
||||
/// All mutable PyClasses can be used as a base type.
|
||||
///
|
||||
/// In the future this will be extended to immutable PyClasses too.
|
||||
impl<T: MutablePyClass> PyClassBaseType<Mutable> for T {
|
||||
type LayoutAsBase = crate::pycell::PyCell<T>;
|
||||
type BaseNativeType = T::BaseNativeType;
|
||||
type ThreadChecker = T::ThreadChecker;
|
||||
|
|
|
@ -700,8 +700,8 @@ impl<'p, T: PyClass> PyRef<'p, T> {
|
|||
|
||||
impl<'p, T, U> AsRef<U> for PyRef<'p, T>
|
||||
where
|
||||
T: PyClass<BaseType = U>,
|
||||
U: PyClass,
|
||||
T: MutablePyClass<BaseType = U>, // For now, only mutable classes can be extended
|
||||
U: MutablePyClass,
|
||||
{
|
||||
fn as_ref(&self) -> &T::BaseType {
|
||||
unsafe { &*self.inner.ob_base.get_ptr() }
|
||||
|
@ -710,8 +710,8 @@ where
|
|||
|
||||
impl<'p, T, U> PyRef<'p, T>
|
||||
where
|
||||
T: PyClass<BaseType = U>,
|
||||
U: PyClass,
|
||||
T: MutablePyClass<BaseType = U>, // For now, only mutable classes can be extended
|
||||
U: MutablePyClass,
|
||||
{
|
||||
/// Gets a `PyRef<T::BaseType>`.
|
||||
///
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//! `PyClass` and related traits.
|
||||
use crate::pycell::Mutability;
|
||||
use crate::pycell::{Immutable, Mutable};
|
||||
use crate::{
|
||||
callback::IntoPyCallbackOutput,
|
||||
ffi,
|
||||
|
@ -23,7 +23,7 @@ use std::{
|
|||
/// The `#[pyclass]` attribute automatically implements this trait for your Rust struct,
|
||||
/// so you normally don't have to use this trait directly.
|
||||
pub trait PyClass:
|
||||
PyTypeInfo<AsRefTarget = PyCell<Self>> + PyClassImpl<Self::Mutability, Layout = PyCell<Self>>
|
||||
PyTypeInfo<AsRefTarget = PyCell<Self>> + PyClassImpl<Layout = PyCell<Self>>
|
||||
{
|
||||
/// Specify this class has `#[pyclass(dict)]` or not.
|
||||
type Dict: PyClassDict;
|
||||
|
@ -32,12 +32,13 @@ pub trait PyClass:
|
|||
/// The closest native ancestor. This is `PyAny` by default, and when you declare
|
||||
/// `#[pyclass(extends=PyDict)]`, it's `PyDict`.
|
||||
type BaseNativeType: PyTypeInfo + PyNativeType;
|
||||
|
||||
type Mutability: Mutability;
|
||||
}
|
||||
|
||||
pub unsafe trait MutablePyClass: PyClass {}
|
||||
pub unsafe trait ImmutablePyClass: PyClass {}
|
||||
pub trait MutablePyClass: PyClass<Mutability = Mutable> {}
|
||||
pub trait ImmutablePyClass: PyClass<Mutability = Immutable> {}
|
||||
|
||||
impl<T> MutablePyClass for T where T: PyClass<Mutability = Mutable> {}
|
||||
impl<T> ImmutablePyClass for T where T: PyClass<Mutability = Immutable> {}
|
||||
|
||||
fn into_raw<T>(vec: Vec<T>) -> *mut c_void {
|
||||
Box::into_raw(vec.into_boxed_slice()) as _
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
//! Contains initialization utilities for `#[pyclass]`.
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::impl_::pyclass::{PyClassBaseType, PyClassDict, PyClassThreadChecker, PyClassWeakRef};
|
||||
use crate::pycell::Mutability;
|
||||
use crate::pyclass::MutablePyClass;
|
||||
use crate::{ffi, PyCell, PyClass, PyErr, PyResult, Python};
|
||||
use crate::{
|
||||
ffi::PyTypeObject,
|
||||
pycell::{BorrowFlag, PyCellContents},
|
||||
pycell::PyCellContents,
|
||||
type_object::{get_tp_alloc, PyTypeInfo},
|
||||
};
|
||||
use std::{
|
||||
cell::{Cell, UnsafeCell},
|
||||
cell::UnsafeCell,
|
||||
marker::PhantomData,
|
||||
mem::{ManuallyDrop, MaybeUninit},
|
||||
};
|
||||
|
@ -193,7 +195,7 @@ impl<T: PyClass> PyClassInitializer<T> {
|
|||
pub fn add_subclass<S>(self, subclass_value: S) -> PyClassInitializer<S>
|
||||
where
|
||||
S: PyClass<BaseType = T>,
|
||||
S::BaseType: PyClassBaseType<T::Mutability, Initializer = Self>,
|
||||
S::BaseType: PyClassBaseType<S::Mutability, Initializer = Self>,
|
||||
{
|
||||
PyClassInitializer::new(subclass_value, self)
|
||||
}
|
||||
|
@ -234,9 +236,9 @@ impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
|
|||
/// Layout of a PyCellBase after base new has been called, but the borrow flag has not
|
||||
/// yet been initialized.
|
||||
#[repr(C)]
|
||||
struct PartiallyInitializedPyCellBase<T: PyClass> {
|
||||
struct PartiallyInitializedPyCellBase<T, M: Mutability> {
|
||||
_ob_base: T,
|
||||
borrow_flag: MaybeUninit<T::Mutability>,
|
||||
borrow_flag: MaybeUninit<M>,
|
||||
}
|
||||
|
||||
/// Layout of a PyCell after base new has been called, but the contents have not yet been
|
||||
|
@ -251,11 +253,8 @@ impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
|
|||
let obj = super_init.into_new_object(py, subtype)?;
|
||||
|
||||
// FIXME: Only need to initialize borrow flag once per whole hierarchy
|
||||
let base: *mut PartiallyInitializedPyCellBase<T::BaseNativeType> = obj as _;
|
||||
std::ptr::write(
|
||||
(*base).borrow_flag.as_mut_ptr(),
|
||||
Cell::new(BorrowFlag::UNUSED),
|
||||
);
|
||||
let base: *mut PartiallyInitializedPyCellBase<T::BaseNativeType, T::Mutability> = obj as _;
|
||||
std::ptr::write((*base).borrow_flag.as_mut_ptr(), T::Mutability::new());
|
||||
|
||||
// FIXME: Initialize borrow flag if necessary??
|
||||
let cell: *mut PartiallyInitializedPyCell<T> = obj as _;
|
||||
|
@ -287,9 +286,9 @@ where
|
|||
|
||||
impl<S, B> From<(S, B)> for PyClassInitializer<S>
|
||||
where
|
||||
S: PyClass<BaseType = B>,
|
||||
B: PyClass,
|
||||
B::BaseType: PyClassBaseType<Initializer = PyNativeTypeInitializer<B::BaseType>>,
|
||||
S: MutablePyClass<BaseType = B>,
|
||||
B: MutablePyClass,
|
||||
B::BaseType: PyClassBaseType<S::Mutability, Initializer = PyNativeTypeInitializer<B::BaseType>>,
|
||||
{
|
||||
fn from(sub_and_base: (S, B)) -> PyClassInitializer<S> {
|
||||
let (sub, base) = sub_and_base;
|
||||
|
|
|
@ -196,8 +196,8 @@ macro_rules! pyobject_native_type_sized {
|
|||
($name:ty, $layout:path $(;$generics:ident)*) => {
|
||||
unsafe impl $crate::type_object::PyLayout<$name> for $layout {}
|
||||
impl $crate::type_object::PySizedLayout<$name> for $layout {}
|
||||
impl<'a, $($generics,)*> $crate::impl_::pyclass::PyClassBaseType<$crate::pycell::Mutable> for $name {
|
||||
type LayoutAsBase = $crate::pycell::PyCellBase<$layout, $crate::pycell::Mutable>;
|
||||
impl<'a, M: $crate::pycell::Mutability, $($generics,)*> $crate::impl_::pyclass::PyClassBaseType<M> for $name {
|
||||
type LayoutAsBase = $crate::pycell::PyCellBase<$layout, M>;
|
||||
type BaseNativeType = $name;
|
||||
type ThreadChecker = $crate::impl_::pyclass::ThreadCheckerStub<$crate::PyObject>;
|
||||
type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>;
|
||||
|
|
|
@ -17,6 +17,7 @@ fn test_compile_errors() {
|
|||
|
||||
fn _test_compile_errors() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/ui/invalid_immutable_pyclass_borrow.rs");
|
||||
t.compile_fail("tests/ui/invalid_macro_args.rs");
|
||||
t.compile_fail("tests/ui/invalid_need_module_arg_position.rs");
|
||||
t.compile_fail("tests/ui/invalid_property_args.rs");
|
||||
|
@ -28,12 +29,8 @@ fn _test_compile_errors() {
|
|||
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
|
||||
t.compile_fail("tests/ui/invalid_pymodule_args.rs");
|
||||
t.compile_fail("tests/ui/reject_generics.rs");
|
||||
<<<<<<< HEAD
|
||||
t.compile_fail("tests/ui/invalid_pymethod_proto_args.rs");
|
||||
t.compile_fail("tests/ui/invalid_pymethod_proto_args_py.rs");
|
||||
=======
|
||||
t.compile_fail("tests/ui/invalid_immutable_pyclass_borrow.rs");
|
||||
>>>>>>> 0fa03a67cd (Implement opt-in immutable pyclasses)
|
||||
|
||||
tests_rust_1_49(&t);
|
||||
tests_rust_1_56(&t);
|
||||
|
|
|
@ -4,7 +4,8 @@ error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
|||
5 | #[pyclass(extends=PyDict)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
|
||||
= note: required because of the requirements on the impl of `MutablePyClass` for `PyDict`
|
||||
= note: required because of the requirements on the impl of `PyClassBaseType<Mutable>` for `PyDict`
|
||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
||||
|
@ -13,10 +14,11 @@ error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
|||
5 | #[pyclass(extends=PyDict)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
|
||||
= note: required because of the requirements on the impl of `MutablePyClass` for `PyDict`
|
||||
= note: required because of the requirements on the impl of `PyClassBaseType<Mutable>` for `PyDict`
|
||||
note: required by a bound in `ThreadCheckerInherited`
|
||||
--> src/impl_/pyclass.rs
|
||||
|
|
||||
| pub struct ThreadCheckerInherited<T: Send, U: PyClassBaseType>(PhantomData<T>, U::ThreadChecker);
|
||||
| ^^^^^^^^^^^^^^^ required by this bound in `ThreadCheckerInherited`
|
||||
| pub struct ThreadCheckerInherited<T: PyClass + Send, U: PyClassBaseType<T::Mutability>>(
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ThreadCheckerInherited`
|
||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
error[E0277]: the trait bound `Foo: MutablePyClass` is not satisfied
|
||||
--> tests/ui/invalid_immutable_pyclass_borrow.rs:10:33
|
||||
|
|
||||
10 | let borrow = foo.as_ref(py).borrow_mut();
|
||||
| ^^^^^^^^^^ the trait `MutablePyClass` is not implemented for `Foo`
|
||||
error[E0271]: type mismatch resolving `<Foo as PyClassImpl>::Mutability == Mutable`
|
||||
--> tests/ui/invalid_immutable_pyclass_borrow.rs:10:33
|
||||
|
|
||||
10 | let borrow = foo.as_ref(py).borrow_mut();
|
||||
| ^^^^^^^^^^ expected struct `Mutable`, found struct `Immutable`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `MutablePyClass` for `Foo`
|
||||
note: required by a bound in `PyCell::<T>::borrow_mut`
|
||||
--> src/pycell.rs
|
||||
|
|
||||
| T: MutablePyClass,
|
||||
| ^^^^^^^^^^^^^^ required by this bound in `PyCell::<T>::borrow_mut`
|
||||
|
|
|
@ -11,20 +11,8 @@ note: required because it appears within the type `NotThreadSafe`
|
|||
5 | struct NotThreadSafe {
|
||||
| ^^^^^^^^^^^^^
|
||||
note: required by a bound in `ThreadCheckerStub`
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
--> src/impl_/pyclass.rs
|
||||
|
|
||||
| pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||
=======
|
||||
--> src/class/impl_.rs:731:33
|
||||
|
|
||||
731 | pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||
>>>>>>> 0fa03a67cd (Implement opt-in immutable pyclasses)
|
||||
=======
|
||||
--> src/class/impl_.rs:728:33
|
||||
|
|
||||
728 | pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||
>>>>>>> 7cded1178d (Fix formatting.)
|
||||
| ^^^^ required by this bound in `ThreadCheckerStub`
|
||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
Loading…
Reference in New Issue