Skip to content

Commit 3c15d89

Browse files
Avoid some cloning
1 parent e5066da commit 3c15d89

File tree

1 file changed

+13
-8
lines changed

1 file changed

+13
-8
lines changed

vm/src/pyobject.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -700,16 +700,23 @@ where
700700
}
701701

702702
impl PyObject<dyn PyObjectPayload> {
703-
pub fn downcast<T: PyObjectPayload>(self: Rc<Self>) -> Option<PyRef<T>> {
703+
/// Attempt to downcast this reference to a subclass.
704+
///
705+
/// If the downcast fails, the original ref is returned in as `Err` so
706+
/// another downcast can be attempted without unnecessary cloning.
707+
///
708+
/// Note: The returned `Result` is _not_ a `PyResult`, even though the
709+
/// types are compatible.
710+
pub fn downcast<T: PyObjectPayload>(self: Rc<Self>) -> Result<PyRef<T>, PyObjectRef> {
704711
if self.payload_is::<T>() {
705-
Some({
712+
Ok({
706713
PyRef {
707714
obj: self,
708715
_payload: PhantomData,
709716
}
710717
})
711718
} else {
712-
None
719+
Err(self)
713720
}
714721
}
715722
}
@@ -1228,12 +1235,10 @@ where
12281235
B: PyValue,
12291236
{
12301237
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
1231-
// TODO: downcast could probably be reworked a bit to make these clones not necessary
1232-
obj.clone()
1233-
.downcast::<A>()
1238+
obj.downcast::<A>()
12341239
.map(Either2::A)
1235-
.or_else(|| obj.clone().downcast::<B>().map(Either2::B))
1236-
.ok_or_else(|| {
1240+
.or_else(|obj| obj.clone().downcast::<B>().map(Either2::B))
1241+
.map_err(|obj| {
12371242
vm.new_type_error(format!(
12381243
"must be {} or {}, not {}",
12391244
A::class(vm),

0 commit comments

Comments
 (0)