Make PyObject.typ : Rc<PyObject<PyClass>>

This commit is contained in:
Noah
2020-03-12 11:45:59 -05:00
parent 3d07a73346
commit c16a257235
4 changed files with 51 additions and 51 deletions

View File

@@ -1,8 +1,8 @@
use std::borrow::Borrow;
use super::objbyteinner::try_as_byte;
use super::objtype::{issubclass, PyClassRef};
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::pyobject::{
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
};
use crate::stdlib::array::PyArray;
use crate::vm::VirtualMachine;
@@ -26,12 +26,12 @@ impl PyMemoryView {
bytes_object: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyMemoryViewRef> {
let object_type = bytes_object.typ.borrow();
let object_type = bytes_object.class();
if issubclass(object_type, &vm.ctx.types.memoryview_type)
|| issubclass(object_type, &vm.ctx.types.bytes_type)
|| issubclass(object_type, &vm.ctx.types.bytearray_type)
|| issubclass(object_type, &PyArray::class(vm))
if issubclass(&object_type, &vm.ctx.types.memoryview_type)
|| issubclass(&object_type, &vm.ctx.types.bytes_type)
|| issubclass(&object_type, &vm.ctx.types.bytearray_type)
|| issubclass(&object_type, &PyArray::class(vm))
{
PyMemoryView {
obj_ref: bytes_object.clone(),

View File

@@ -526,7 +526,7 @@ pub fn new(
slots: RefCell::default(),
},
dict: None,
typ,
typ: typ.into_generic_pyobj(),
}
.into_ref();

View File

@@ -571,7 +571,7 @@ impl PyContext {
pub fn new_base_object(&self, class: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
PyObject {
typ: class,
typ: class.into_generic_pyobj(),
dict: dict.map(RefCell::new),
payload: objobject::PyBaseObject,
}
@@ -628,7 +628,7 @@ pub struct PyObject<T>
where
T: ?Sized + PyObjectPayload,
{
pub typ: PyClassRef,
pub typ: Rc<PyObject<PyClass>>,
pub dict: Option<RefCell<PyDictRef>>, // __dict__ member
pub payload: T,
}
@@ -648,6 +648,21 @@ impl PyObject<dyn PyObjectPayload> {
Err(self)
}
}
/// Dowcast this PyObjectRef to an `Rc<PyObject<T>>`. The [`downcast`](#method.downcast) method
/// is generally preferred, as the `PyRef<T>` it returns implements `Deref<Target=T>`, and
/// therefore can be used similarly to an `&T`.
pub fn downcast_generic<T: PyObjectPayload>(
self: Rc<Self>,
) -> Result<Rc<PyObject<T>>, PyObjectRef> {
if self.payload_is::<T>() {
let ptr = Rc::into_raw(self) as *const PyObject<T>;
let ret = unsafe { Rc::from_raw(ptr) };
Ok(ret)
} else {
Err(self)
}
}
}
/// A reference to a Python object.
@@ -660,6 +675,7 @@ impl PyObject<dyn PyObjectPayload> {
/// situations (such as when implementing in-place methods such as `__iadd__`)
/// where a reference to the same object must be returned.
#[derive(Debug)]
#[repr(transparent)]
pub struct PyRef<T> {
// invariant: this obj must always have payload of type T
obj: PyObjectRef,
@@ -705,6 +721,10 @@ impl<T: PyValue> PyRef<T> {
pub fn typ(&self) -> PyClassRef {
self.obj.class()
}
pub fn into_generic_pyobj(self) -> Rc<PyObject<T>> {
self.into_object().downcast_generic().unwrap()
}
}
impl<T> Deref for PyRef<T>
@@ -838,13 +858,13 @@ where
T: ?Sized + PyObjectPayload,
{
fn class(&self) -> PyClassRef {
self.typ.clone()
self.typ.clone().into_pyref()
}
}
impl<T> TypeProtocol for PyRef<T> {
fn class(&self) -> PyClassRef {
self.obj.typ.clone()
self.obj.class()
}
}
@@ -1103,7 +1123,7 @@ where
#[allow(clippy::new_ret_no_self)]
pub fn new(payload: T, typ: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
PyObject {
typ,
typ: typ.into_generic_pyobj(),
dict: dict.map(RefCell::new),
payload,
}
@@ -1114,6 +1134,13 @@ where
pub fn into_ref(self) -> PyObjectRef {
Rc::new(self)
}
pub fn into_pyref(self: Rc<Self>) -> PyRef<T>
where
T: PyValue,
{
PyRef::new_ref_unchecked(self as PyObjectRef)
}
}
impl PyObject<dyn PyObjectPayload> {

View File

@@ -38,9 +38,9 @@ use crate::obj::objtype::{self, PyClass, PyClassRef};
use crate::obj::objweakproxy;
use crate::obj::objweakref;
use crate::obj::objzip;
use crate::pyobject::{PyAttributes, PyContext, PyObject, PyObjectPayload};
use crate::pyobject::{PyAttributes, PyContext, PyObject};
use std::cell::RefCell;
use std::mem::{self, MaybeUninit};
use std::mem::MaybeUninit;
use std::ptr;
use std::rc::Rc;
@@ -312,41 +312,14 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
let type_type_ptr =
Rc::into_raw(type_type.clone()) as *mut MaybeUninit<PyClassObj> as *mut PyClassObj;
// same as std::raw::TraitObject (which is unstable, but accurate)
#[repr(C)]
struct TraitObject {
data: *mut (),
vtable: *mut (),
}
let pyclass_vptr = {
// dummy PyClass
let cls = PyClass {
name: Default::default(),
bases: Default::default(),
mro: Default::default(),
subclasses: Default::default(),
attributes: Default::default(),
slots: Default::default(),
};
// so that we can get the vtable ptr of PyClass for PyObjectPayload
mem::transmute::<_, TraitObject>(&cls as &dyn PyObjectPayload).vtable
};
let write_typ_ptr = |ptr: *mut PyClassObj, type_type: UninitRef<PyClassObj>| {
// turn type_type into a trait object, using the vtable for PyClass we got earlier
let type_type = mem::transmute(TraitObject {
data: mem::transmute(type_type),
vtable: pyclass_vptr,
});
ptr::write(
&mut (*ptr).typ as *mut PyClassRef as *mut MaybeUninit<PyClassRef>,
type_type,
);
};
write_typ_ptr(object_type_ptr, type_type.clone());
write_typ_ptr(type_type_ptr, type_type);
ptr::write(
&mut (*object_type_ptr).typ as *mut Rc<PyClassObj> as *mut UninitRef<PyClassObj>,
type_type.clone(),
);
ptr::write(
&mut (*type_type_ptr).typ as *mut Rc<PyClassObj> as *mut UninitRef<PyClassObj>,
type_type,
);
let type_type = PyClassRef::new_ref_unchecked(Rc::from_raw(type_type_ptr));
let object_type = PyClassRef::new_ref_unchecked(Rc::from_raw(object_type_ptr));