diff --git a/vm/src/obj/objmemory.rs b/vm/src/obj/objmemory.rs index 5e37ff2c60..c4f9c47768 100644 --- a/vm/src/obj/objmemory.rs +++ b/vm/src/obj/objmemory.rs @@ -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 { - 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(), diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 49a0711c12..34a9e9e327 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -526,7 +526,7 @@ pub fn new( slots: RefCell::default(), }, dict: None, - typ, + typ: typ.into_typed_pyobj(), } .into_ref(); diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 786e1a6bf6..86a11bf97f 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -571,7 +571,7 @@ impl PyContext { pub fn new_base_object(&self, class: PyClassRef, dict: Option) -> PyObjectRef { PyObject { - typ: class, + typ: class.into_typed_pyobj(), dict: dict.map(RefCell::new), payload: objobject::PyBaseObject, } @@ -628,7 +628,7 @@ pub struct PyObject where T: ?Sized + PyObjectPayload, { - pub typ: PyClassRef, + pub typ: Rc>, pub dict: Option>, // __dict__ member pub payload: T, } @@ -648,6 +648,21 @@ impl PyObject { Err(self) } } + + /// Downcast this PyObjectRef to an `Rc>`. The [`downcast`](#method.downcast) method + /// is generally preferred, as the `PyRef` it returns implements `Deref`, and + /// therefore can be used similarly to an `&T`. + pub fn downcast_generic( + self: Rc, + ) -> Result>, PyObjectRef> { + if self.payload_is::() { + let ptr = Rc::into_raw(self) as *const PyObject; + let ret = unsafe { Rc::from_raw(ptr) }; + Ok(ret) + } else { + Err(self) + } + } } /// A reference to a Python object. @@ -660,6 +675,7 @@ impl PyObject { /// 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 { // invariant: this obj must always have payload of type T obj: PyObjectRef, @@ -705,6 +721,10 @@ impl PyRef { pub fn typ(&self) -> PyClassRef { self.obj.class() } + + pub fn into_typed_pyobj(self) -> Rc> { + self.into_object().downcast_generic().unwrap() + } } impl Deref for PyRef @@ -838,13 +858,13 @@ where T: ?Sized + PyObjectPayload, { fn class(&self) -> PyClassRef { - self.typ.clone() + self.typ.clone().into_pyref() } } impl TypeProtocol for PyRef { 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) -> PyObjectRef { PyObject { - typ, + typ: typ.into_typed_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) -> PyRef + where + T: PyValue, + { + PyRef::new_ref_unchecked(self as PyObjectRef) + } } impl PyObject { diff --git a/vm/src/types.rs b/vm/src/types.rs index fc8caec054..a55fb02789 100644 --- a/vm/src/types.rs +++ b/vm/src/types.rs @@ -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 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| { - // 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, - 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 as *mut UninitRef, + type_type.clone(), + ); + ptr::write( + &mut (*type_type_ptr).typ as *mut Rc as *mut UninitRef, + 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));