Skip to content

Commit a104d43

Browse files
authored
Merge pull request RustPython#1811 from RustPython/coolreader18/typ-generic-pyobj
Make PyObject.typ a Rc<PyObject<PyClass>>
2 parents ceb11d6 + 7143b93 commit a104d43

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
@@ -545,7 +545,7 @@ pub fn new(
545545
slots: RefCell::default(),
546546
},
547547
dict: None,
548-
typ,
548+
typ: typ.into_typed_pyobj(),
549549
}
550550
.into_ref();
551551

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_typed_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+
/// Downcast 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_typed_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

@@ -1110,7 +1130,7 @@ where
11101130
#[allow(clippy::new_ret_no_self)]
11111131
pub fn new(payload: T, typ: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
11121132
PyObject {
1113-
typ,
1133+
typ: typ.into_typed_pyobj(),
11141134
dict: dict.map(RefCell::new),
11151135
payload,
11161136
}
@@ -1121,6 +1141,13 @@ where
11211141
pub fn into_ref(self) -> PyObjectRef {
11221142
Rc::new(self)
11231143
}
1144+
1145+
pub fn into_pyref(self: Rc<Self>) -> PyRef<T>
1146+
where
1147+
T: PyValue,
1148+
{
1149+
PyRef::new_ref_unchecked(self as PyObjectRef)
1150+
}
11241151
}
11251152

11261153
impl PyObject<dyn PyObjectPayload> {

vm/src/types.rs

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

@@ -327,41 +327,14 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
327327
let type_type_ptr =
328328
Rc::into_raw(type_type.clone()) as *mut MaybeUninit<PyClassObj> as *mut PyClassObj;
329329

330-
// same as std::raw::TraitObject (which is unstable, but accurate)
331-
#[repr(C)]
332-
struct TraitObject {
333-
data: *mut (),
334-
vtable: *mut (),
335-
}
336-
337-
let pyclass_vptr = {
338-
// dummy PyClass
339-
let cls = PyClass {
340-
name: Default::default(),
341-
bases: Default::default(),
342-
mro: Default::default(),
343-
subclasses: Default::default(),
344-
attributes: Default::default(),
345-
slots: Default::default(),
346-
};
347-
// so that we can get the vtable ptr of PyClass for PyObjectPayload
348-
mem::transmute::<_, TraitObject>(&cls as &dyn PyObjectPayload).vtable
349-
};
350-
351-
let write_typ_ptr = |ptr: *mut PyClassObj, type_type: UninitRef<PyClassObj>| {
352-
// turn type_type into a trait object, using the vtable for PyClass we got earlier
353-
let type_type = mem::transmute(TraitObject {
354-
data: mem::transmute(type_type),
355-
vtable: pyclass_vptr,
356-
});
357-
ptr::write(
358-
&mut (*ptr).typ as *mut PyClassRef as *mut MaybeUninit<PyClassRef>,
359-
type_type,
360-
);
361-
};
362-
363-
write_typ_ptr(object_type_ptr, type_type.clone());
364-
write_typ_ptr(type_type_ptr, type_type);
330+
ptr::write(
331+
&mut (*object_type_ptr).typ as *mut Rc<PyClassObj> as *mut UninitRef<PyClassObj>,
332+
type_type.clone(),
333+
);
334+
ptr::write(
335+
&mut (*type_type_ptr).typ as *mut Rc<PyClassObj> as *mut UninitRef<PyClassObj>,
336+
type_type,
337+
);
365338

366339
let type_type = PyClassRef::new_ref_unchecked(Rc::from_raw(type_type_ptr));
367340
let object_type = PyClassRef::new_ref_unchecked(Rc::from_raw(object_type_ptr));

0 commit comments

Comments
 (0)