Skip to content

Commit c16a257

Browse files
committed
Make PyObject.typ : Rc<PyObject<PyClass>>
1 parent 3d07a73 commit c16a257

File tree

4 files changed

+51
-51
lines changed

4 files changed

+51
-51
lines changed

vm/src/obj/objmemory.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use std::borrow::Borrow;
2-
31
use super::objbyteinner::try_as_byte;
42
use super::objtype::{issubclass, PyClassRef};
5-
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
3+
use crate::pyobject::{
4+
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
5+
};
66
use crate::stdlib::array::PyArray;
77
use crate::vm::VirtualMachine;
88

@@ -26,12 +26,12 @@ impl PyMemoryView {
2626
bytes_object: PyObjectRef,
2727
vm: &VirtualMachine,
2828
) -> PyResult<PyMemoryViewRef> {
29-
let object_type = bytes_object.typ.borrow();
29+
let object_type = bytes_object.class();
3030

31-
if issubclass(object_type, &vm.ctx.types.memoryview_type)
32-
|| issubclass(object_type, &vm.ctx.types.bytes_type)
33-
|| issubclass(object_type, &vm.ctx.types.bytearray_type)
34-
|| issubclass(object_type, &PyArray::class(vm))
31+
if issubclass(&object_type, &vm.ctx.types.memoryview_type)
32+
|| issubclass(&object_type, &vm.ctx.types.bytes_type)
33+
|| issubclass(&object_type, &vm.ctx.types.bytearray_type)
34+
|| issubclass(&object_type, &PyArray::class(vm))
3535
{
3636
PyMemoryView {
3737
obj_ref: bytes_object.clone(),

vm/src/obj/objtype.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ pub fn new(
526526
slots: RefCell::default(),
527527
},
528528
dict: None,
529-
typ,
529+
typ: typ.into_generic_pyobj(),
530530
}
531531
.into_ref();
532532

vm/src/pyobject.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ impl PyContext {
571571

572572
pub fn new_base_object(&self, class: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
573573
PyObject {
574-
typ: class,
574+
typ: class.into_generic_pyobj(),
575575
dict: dict.map(RefCell::new),
576576
payload: objobject::PyBaseObject,
577577
}
@@ -628,7 +628,7 @@ pub struct PyObject<T>
628628
where
629629
T: ?Sized + PyObjectPayload,
630630
{
631-
pub typ: PyClassRef,
631+
pub typ: Rc<PyObject<PyClass>>,
632632
pub dict: Option<RefCell<PyDictRef>>, // __dict__ member
633633
pub payload: T,
634634
}
@@ -648,6 +648,21 @@ impl PyObject<dyn PyObjectPayload> {
648648
Err(self)
649649
}
650650
}
651+
652+
/// Dowcast this PyObjectRef to an `Rc<PyObject<T>>`. The [`downcast`](#method.downcast) method
653+
/// is generally preferred, as the `PyRef<T>` it returns implements `Deref<Target=T>`, and
654+
/// therefore can be used similarly to an `&T`.
655+
pub fn downcast_generic<T: PyObjectPayload>(
656+
self: Rc<Self>,
657+
) -> Result<Rc<PyObject<T>>, PyObjectRef> {
658+
if self.payload_is::<T>() {
659+
let ptr = Rc::into_raw(self) as *const PyObject<T>;
660+
let ret = unsafe { Rc::from_raw(ptr) };
661+
Ok(ret)
662+
} else {
663+
Err(self)
664+
}
665+
}
651666
}
652667

653668
/// A reference to a Python object.
@@ -660,6 +675,7 @@ impl PyObject<dyn PyObjectPayload> {
660675
/// situations (such as when implementing in-place methods such as `__iadd__`)
661676
/// where a reference to the same object must be returned.
662677
#[derive(Debug)]
678+
#[repr(transparent)]
663679
pub struct PyRef<T> {
664680
// invariant: this obj must always have payload of type T
665681
obj: PyObjectRef,
@@ -705,6 +721,10 @@ impl<T: PyValue> PyRef<T> {
705721
pub fn typ(&self) -> PyClassRef {
706722
self.obj.class()
707723
}
724+
725+
pub fn into_generic_pyobj(self) -> Rc<PyObject<T>> {
726+
self.into_object().downcast_generic().unwrap()
727+
}
708728
}
709729

710730
impl<T> Deref for PyRef<T>
@@ -838,13 +858,13 @@ where
838858
T: ?Sized + PyObjectPayload,
839859
{
840860
fn class(&self) -> PyClassRef {
841-
self.typ.clone()
861+
self.typ.clone().into_pyref()
842862
}
843863
}
844864

845865
impl<T> TypeProtocol for PyRef<T> {
846866
fn class(&self) -> PyClassRef {
847-
self.obj.typ.clone()
867+
self.obj.class()
848868
}
849869
}
850870

@@ -1103,7 +1123,7 @@ where
11031123
#[allow(clippy::new_ret_no_self)]
11041124
pub fn new(payload: T, typ: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
11051125
PyObject {
1106-
typ,
1126+
typ: typ.into_generic_pyobj(),
11071127
dict: dict.map(RefCell::new),
11081128
payload,
11091129
}
@@ -1114,6 +1134,13 @@ where
11141134
pub fn into_ref(self) -> PyObjectRef {
11151135
Rc::new(self)
11161136
}
1137+
1138+
pub fn into_pyref(self: Rc<Self>) -> PyRef<T>
1139+
where
1140+
T: PyValue,
1141+
{
1142+
PyRef::new_ref_unchecked(self as PyObjectRef)
1143+
}
11171144
}
11181145

11191146
impl PyObject<dyn PyObjectPayload> {

vm/src/types.rs

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ use crate::obj::objtype::{self, PyClass, PyClassRef};
3838
use crate::obj::objweakproxy;
3939
use crate::obj::objweakref;
4040
use crate::obj::objzip;
41-
use crate::pyobject::{PyAttributes, PyContext, PyObject, PyObjectPayload};
41+
use crate::pyobject::{PyAttributes, PyContext, PyObject};
4242
use std::cell::RefCell;
43-
use std::mem::{self, MaybeUninit};
43+
use std::mem::MaybeUninit;
4444
use std::ptr;
4545
use std::rc::Rc;
4646

@@ -312,41 +312,14 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
312312
let type_type_ptr =
313313
Rc::into_raw(type_type.clone()) as *mut MaybeUninit<PyClassObj> as *mut PyClassObj;
314314

315-
// same as std::raw::TraitObject (which is unstable, but accurate)
316-
#[repr(C)]
317-
struct TraitObject {
318-
data: *mut (),
319-
vtable: *mut (),
320-
}
321-
322-
let pyclass_vptr = {
323-
// dummy PyClass
324-
let cls = PyClass {
325-
name: Default::default(),
326-
bases: Default::default(),
327-
mro: Default::default(),
328-
subclasses: Default::default(),
329-
attributes: Default::default(),
330-
slots: Default::default(),
331-
};
332-
// so that we can get the vtable ptr of PyClass for PyObjectPayload
333-
mem::transmute::<_, TraitObject>(&cls as &dyn PyObjectPayload).vtable
334-
};
335-
336-
let write_typ_ptr = |ptr: *mut PyClassObj, type_type: UninitRef<PyClassObj>| {
337-
// turn type_type into a trait object, using the vtable for PyClass we got earlier
338-
let type_type = mem::transmute(TraitObject {
339-
data: mem::transmute(type_type),
340-
vtable: pyclass_vptr,
341-
});
342-
ptr::write(
343-
&mut (*ptr).typ as *mut PyClassRef as *mut MaybeUninit<PyClassRef>,
344-
type_type,
345-
);
346-
};
347-
348-
write_typ_ptr(object_type_ptr, type_type.clone());
349-
write_typ_ptr(type_type_ptr, type_type);
315+
ptr::write(
316+
&mut (*object_type_ptr).typ as *mut Rc<PyClassObj> as *mut UninitRef<PyClassObj>,
317+
type_type.clone(),
318+
);
319+
ptr::write(
320+
&mut (*type_type_ptr).typ as *mut Rc<PyClassObj> as *mut UninitRef<PyClassObj>,
321+
type_type,
322+
);
350323

351324
let type_type = PyClassRef::new_ref_unchecked(Rc::from_raw(type_type_ptr));
352325
let object_type = PyClassRef::new_ref_unchecked(Rc::from_raw(object_type_ptr));

0 commit comments

Comments
 (0)