New AsPyRef

This commit is contained in:
kngwyu 2020-02-10 17:30:48 +09:00
parent c43fb9fcdf
commit 4a5f219cc4
7 changed files with 125 additions and 60 deletions

View file

@ -252,8 +252,12 @@ pub mod extract_impl {
fn extract(source: &'a PyAny) -> PyResult<Target>; fn extract(source: &'a PyAny) -> PyResult<Target>;
} }
pub struct Cloned; pub struct Cloned {
pub struct Reference; _private: (),
}
pub struct Reference {
_private: (),
}
impl<'a, T: 'a> ExtractImpl<'a, T> for Cloned impl<'a, T: 'a> ExtractImpl<'a, T> for Cloned
where where

View file

@ -3,7 +3,7 @@ use crate::err::{PyErr, PyResult};
use crate::gil; use crate::gil;
use crate::object::PyObject; use crate::object::PyObject;
use crate::objectprotocol::ObjectProtocol; use crate::objectprotocol::ObjectProtocol;
use crate::type_object::{PyObjectLayout, PyTypeInfo}; use crate::type_object::PyTypeInfo;
use crate::types::PyAny; use crate::types::PyAny;
use crate::{ use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyCell, PyClass, PyClassInitializer, ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyCell, PyClass, PyClassInitializer,
@ -121,13 +121,13 @@ impl<T> Py<T> {
pub trait AsPyRef<T: PyTypeInfo>: Sized { pub trait AsPyRef<T: PyTypeInfo>: Sized {
/// Return reference to object. /// Return reference to object.
fn as_ref(&self, py: Python) -> &T; fn as_ref(&self, py: Python) -> &T::Reference;
} }
impl<T: PyTypeInfo> AsPyRef<T> for Py<T> { impl<T: PyTypeInfo> AsPyRef<T> for Py<T> {
fn as_ref(&self, _py: Python) -> &T { fn as_ref(&self, _py: Python) -> &T::Reference {
let any = self as *const Py<T> as *const PyAny; let ptr = self as *const Py<T> as *const T::Reference;
unimplemented!() unsafe { &*ptr }
} }
} }

View file

@ -158,7 +158,7 @@ impl PyObject {
/// Extracts some type from the Python object. /// Extracts some type from the Python object.
/// This is a wrapper function around `FromPyObject::extract()`. /// This is a wrapper function around `FromPyObject::extract()`.
pub fn extract<'p, D>(&'p self, py: Python) -> PyResult<D> pub fn extract<'p, D>(&'p self, py: Python<'p>) -> PyResult<D>
where where
D: FromPyObject<'p>, D: FromPyObject<'p>,
{ {

View file

@ -13,6 +13,9 @@ use std::ops::{Deref, DerefMut};
use std::ptr::NonNull; use std::ptr::NonNull;
/// Inner type of `PyCell` without dict slots and reference counter. /// 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)] #[doc(hidden)]
#[repr(C)] #[repr(C)]
pub struct PyCellBase<T: PyClass> { pub struct PyCellBase<T: PyClass> {
@ -20,20 +23,23 @@ pub struct PyCellBase<T: PyClass> {
value: ManuallyDrop<UnsafeCell<T>>, value: ManuallyDrop<UnsafeCell<T>>,
} }
impl<T: PyClass> PyCellBase<T> { impl<T: PyClass> AsPyPointer for PyCellBase<T> {
fn get(&self) -> &T { fn as_ptr(&self) -> *mut ffi::PyObject {
unsafe { &*self.value.get() } (self as *const _) as *mut _
}
fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.value.get() }
} }
} }
impl<T: PyClass> PyObjectLayout<T> for PyCellBase<T> { unsafe impl<T: PyClass> PyObjectLayout<T> for PyCellBase<T> {
const IS_NATIVE_TYPE: bool = false; 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::BaseType as PyTypeInfo>::ConcreteLayout> {
Some(&mut self.ob_base) Some(&mut self.ob_base)
} }
unsafe fn unchecked_ref(&self) -> &T {
&*self.value.get()
}
unsafe fn unchecked_refmut(&mut self) -> &mut T {
&mut *self.value.get()
}
unsafe fn py_init(&mut self, value: T) { unsafe fn py_init(&mut self, value: T) {
self.value = ManuallyDrop::new(UnsafeCell::new(value)); self.value = ManuallyDrop::new(UnsafeCell::new(value));
} }
@ -43,7 +49,7 @@ impl<T: PyClass> PyObjectLayout<T> for PyCellBase<T> {
} }
} }
/// `Pycell` represents the concrete layout of `T: PyClass` when it is converted /// `PyCell` represents the concrete layout of `T: PyClass` when it is converted
/// to a Python class. /// to a Python class.
/// ///
/// You can use it to test your `#[pyclass]` correctly works. /// You can use it to test your `#[pyclass]` correctly works.
@ -68,9 +74,8 @@ impl<T: PyClass> PyObjectLayout<T> for PyCellBase<T> {
/// ``` /// ```
#[repr(C)] #[repr(C)]
pub struct PyCell<T: PyClass> { pub struct PyCell<T: PyClass> {
ob_base: <T::BaseType as PyTypeInfo>::ConcreteLayout, base: PyCellBase<T>,
value: ManuallyDrop<UnsafeCell<T>>, borrow_flag: Cell<BorrowFlag>,
borrow_flag: BorrowFlag,
dict: T::Dict, dict: T::Dict,
weakref: T::WeakRef, weakref: T::WeakRef,
} }
@ -90,39 +95,52 @@ impl<T: PyClass> PyCell<T> {
} }
pub fn borrow(&self) -> PyRef<'_, T> { pub fn borrow(&self) -> PyRef<'_, T> {
unsafe { self.try_borrow().expect("Already mutably borrowed")
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,
// }
}
} }
pub fn borrow_mut(&self) -> PyRefMut<'_, T> { pub fn borrow_mut(&self) -> PyRefMut<'_, T> {
unsafe { self.try_borrow_mut().expect("Already borrowed")
unimplemented!() }
// if self.borrow.get() != 0 {
// borrow_fail(); pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
// } let flag = self.borrow_flag.get();
// self.borrow.set(usize::max_value()); if flag != BorrowFlag::HAS_MUTABLE_BORROW {
// RefMut { Err(PyBorrowError { _private: () })
// value: &mut *self.value.get(), } else {
// borrow: &self.borrow, self.borrow_flag.set(flag.increment());
// } Ok(PyRef {
value: &self.base,
flag: &self.borrow_flag,
})
}
}
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError> {
if self.borrow_flag.get() != 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,
})
} }
} }
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> { pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
unimplemented!() if self.borrow_flag.get() != BorrowFlag::HAS_MUTABLE_BORROW {
Err(PyBorrowError { _private: () })
} else {
Ok(&*self.base.value.get())
}
} }
pub unsafe fn try_borrow_mut_unguarded(&self) -> Result<&mut T, PyBorrowMutError> { pub unsafe fn try_borrow_mut_unguarded(&self) -> Result<&mut T, PyBorrowMutError> {
unimplemented!() if self.borrow_flag.get() != BorrowFlag::UNUSED {
Err(PyBorrowMutError { _private: () })
} else {
Ok(&mut *self.base.value.get())
}
} }
pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self> pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self>
@ -135,26 +153,32 @@ impl<T: PyClass> PyCell<T> {
return Err(PyErr::fetch(py)); return Err(PyErr::fetch(py));
} }
let self_ = base as *mut Self; let self_ = base as *mut Self;
(*self_).borrow_flag = BorrowFlag::UNUSED; (*self_).borrow_flag = Cell::new(BorrowFlag::UNUSED);
(*self_).dict = T::Dict::new(); (*self_).dict = T::Dict::new();
(*self_).weakref = T::WeakRef::new(); (*self_).weakref = T::WeakRef::new();
Ok(self_) Ok(self_)
} }
} }
impl<T: PyClass> PyObjectLayout<T> for PyCell<T> { unsafe impl<T: PyClass> PyObjectLayout<T> for PyCell<T> {
const IS_NATIVE_TYPE: bool = false; 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::BaseType as PyTypeInfo>::ConcreteLayout> {
Some(&mut self.ob_base) Some(&mut self.base.ob_base)
}
unsafe fn unchecked_ref(&self) -> &T {
self.base.unchecked_ref()
}
unsafe fn unchecked_refmut(&mut self) -> &mut T {
self.base.unchecked_refmut()
} }
unsafe fn py_init(&mut self, value: T) { unsafe fn py_init(&mut self, value: T) {
self.value = ManuallyDrop::new(UnsafeCell::new(value)); self.base.value = ManuallyDrop::new(UnsafeCell::new(value));
} }
unsafe fn py_drop(&mut self, py: Python) { unsafe fn py_drop(&mut self, py: Python) {
ManuallyDrop::drop(&mut self.value); ManuallyDrop::drop(&mut self.base.value);
self.dict.clear_dict(py); self.dict.clear_dict(py);
self.weakref.clear_weakrefs(self.as_ptr(), py); self.weakref.clear_weakrefs(self.as_ptr(), py);
self.ob_base.py_drop(py); self.base.ob_base.py_drop(py);
} }
} }
@ -206,8 +230,8 @@ pub struct PyRef<'p, T: PyClass> {
} }
impl<'p, T: PyClass> PyRef<'p, T> { impl<'p, T: PyClass> PyRef<'p, T> {
fn get_super(&'p self) -> &'p T::BaseType { pub fn get_super(&'p self) -> &'p T::BaseType {
unimplemented!() unsafe { self.value.ob_base.unchecked_ref() }
} }
} }
@ -216,13 +240,13 @@ impl<'p, T: PyClass> Deref for PyRef<'p, T> {
#[inline] #[inline]
fn deref(&self) -> &T { fn deref(&self) -> &T {
self.value.get() unsafe { self.value.unchecked_ref() }
} }
} }
impl<'p, T: PyClass> Drop for PyRef<'p, T> { impl<'p, T: PyClass> Drop for PyRef<'p, T> {
fn drop(&mut self) { fn drop(&mut self) {
self.flag.set(self.flag.get()); self.flag.set(self.flag.get().decrement());
} }
} }
@ -231,19 +255,28 @@ pub struct PyRefMut<'p, T: PyClass> {
flag: &'p Cell<BorrowFlag>, flag: &'p Cell<BorrowFlag>,
} }
impl<'p, T: PyClass> PyRefMut<'p, T> {
pub fn get_super(&'p self) -> &'p T::BaseType {
unsafe { self.value.ob_base.unchecked_ref() }
}
pub fn get_super_mut(&'p mut self) -> &'p mut T::BaseType {
unsafe { self.value.ob_base.unchecked_refmut() }
}
}
impl<'p, T: PyClass> Deref for PyRefMut<'p, T> { impl<'p, T: PyClass> Deref for PyRefMut<'p, T> {
type Target = T; type Target = T;
#[inline] #[inline]
fn deref(&self) -> &T { fn deref(&self) -> &T {
self.value.get() unsafe { self.value.unchecked_ref() }
} }
} }
impl<'p, T: PyClass> DerefMut for PyRefMut<'p, T> { impl<'p, T: PyClass> DerefMut for PyRefMut<'p, T> {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut T { fn deref_mut(&mut self) -> &mut T {
self.value.get_mut() unsafe { self.value.unchecked_refmut() }
} }
} }
@ -259,7 +292,10 @@ struct BorrowFlag(usize);
impl BorrowFlag { impl BorrowFlag {
const UNUSED: BorrowFlag = BorrowFlag(0); const UNUSED: BorrowFlag = BorrowFlag(0);
const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::max_value()); const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::max_value());
fn decrement(self) -> Self { const fn increment(self) -> Self {
Self(self.0 + 1)
}
const fn decrement(self) -> Self {
Self(self.0 - 1) Self(self.0 - 1)
} }
} }

View file

@ -15,15 +15,16 @@ use std::sync::atomic::{AtomicBool, Ordering};
/// is of `PyAny`. /// is of `PyAny`.
/// ///
/// This trait is intended to be used internally. /// This trait is intended to be used internally.
pub trait PyObjectLayout<T: PyTypeInfo> { pub unsafe trait PyObjectLayout<T: PyTypeInfo> {
const IS_NATIVE_TYPE: bool = true; 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::BaseType as PyTypeInfo>::ConcreteLayout> {
None None
} }
unsafe fn py_init(&mut self, _value: T) {} unsafe fn py_init(&mut self, _value: T) {}
unsafe fn py_drop(&mut self, _py: Python) {} unsafe fn py_drop(&mut self, _py: Python) {}
unsafe fn unchecked_ref(&self) -> &T;
unsafe fn unchecked_refmut(&mut self) -> &mut T;
} }
/// `T: PyObjectSizedLayout<U>` represents `T` is not a instance of /// `T: PyObjectSizedLayout<U>` represents `T` is not a instance of
@ -101,6 +102,9 @@ pub unsafe trait PyTypeInfo: Sized {
/// Layout /// Layout
type ConcreteLayout: PyObjectLayout<Self>; type ConcreteLayout: PyObjectLayout<Self>;
/// This type is an abstraction layer for `AsPyRef`.
type Reference;
/// Initializer for layout /// Initializer for layout
type Initializer: PyObjectInit<Self>; type Initializer: PyObjectInit<Self>;

View file

@ -23,7 +23,14 @@ use crate::{ffi, PyObject};
/// ``` /// ```
#[repr(transparent)] #[repr(transparent)]
pub struct PyAny(PyObject, Unsendable); pub struct PyAny(PyObject, Unsendable);
impl crate::type_object::PyObjectLayout<PyAny> for ffi::PyObject {} 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 _)
}
}
impl crate::type_object::PyObjectSizedLayout<PyAny> for ffi::PyObject {} impl crate::type_object::PyObjectSizedLayout<PyAny> for ffi::PyObject {}
pyobject_native_type_named!(PyAny); pyobject_native_type_named!(PyAny);
pyobject_native_type_convert!( pyobject_native_type_convert!(

View file

@ -56,10 +56,23 @@ macro_rules! pyobject_native_type_named (
}; };
); );
macro_rules! impl_layout {
($name: ty, $layout: path) => {
unsafe impl $crate::type_object::PyObjectLayout<$name> for $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 _)
}
}
};
}
#[macro_export] #[macro_export]
macro_rules! pyobject_native_type { macro_rules! pyobject_native_type {
($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { ($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => {
impl $crate::type_object::PyObjectLayout<$name> for $layout {} impl_layout!($name, $layout);
impl $crate::type_object::PyObjectSizedLayout<$name> for $layout {} impl $crate::type_object::PyObjectSizedLayout<$name> for $layout {}
pyobject_native_type_named!($name $(,$type_param)*); pyobject_native_type_named!($name $(,$type_param)*);
pyobject_native_type_convert!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); pyobject_native_type_convert!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*);
@ -81,7 +94,7 @@ macro_rules! pyobject_native_type {
#[macro_export] #[macro_export]
macro_rules! pyobject_native_var_type { macro_rules! pyobject_native_var_type {
($name: ty, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { ($name: ty, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => {
impl $crate::type_object::PyObjectLayout<$name> for $crate::ffi::PyObject {} impl_layout!($name, $crate::ffi::PyObject);
pyobject_native_type_named!($name $(,$type_param)*); pyobject_native_type_named!($name $(,$type_param)*);
pyobject_native_type_convert!($name, $crate::ffi::PyObject, pyobject_native_type_convert!($name, $crate::ffi::PyObject,
$typeobject, $module, $checkfunction $(,$type_param)*); $typeobject, $module, $checkfunction $(,$type_param)*);
@ -118,6 +131,7 @@ macro_rules! pyobject_native_type_convert(
type Type = (); type Type = ();
type BaseType = $crate::types::PyAny; type BaseType = $crate::types::PyAny;
type ConcreteLayout = $layout; type ConcreteLayout = $layout;
type Reference = $name;
type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>; type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>;
const NAME: &'static str = stringify!($name); const NAME: &'static str = stringify!($name);