Skip to content

Commit 1d81546

Browse files
authored
Merge pull request RustPython#4513 from xiaozhiyan/optimize-pypydict-to_attributes-to-reuse-pyrefexact
Optimize Py<PyDict>::to_attributes() to reuse PyRefExact
2 parents 461f749 + 9206ad5 commit 1d81546

File tree

9 files changed

+24
-21
lines changed

9 files changed

+24
-21
lines changed

vm/src/builtins/complex.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ impl Constructor for PyComplex {
128128
let val = if cls.is(vm.ctx.types.complex_type) && imag_missing {
129129
match val.downcast_exact::<PyComplex>(vm) {
130130
Ok(c) => {
131-
return Ok(c.into());
131+
return Ok(c.into_pyref().into());
132132
}
133133
Err(val) => val,
134134
}

vm/src/builtins/dict.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{
22
set::PySetInner, IterStatus, PositionIterInternal, PyBaseExceptionRef, PyGenericAlias,
3-
PyMappingProxy, PySet, PyStrRef, PyTupleRef, PyType, PyTypeRef,
3+
PyMappingProxy, PySet, PyStr, PyTupleRef, PyType, PyTypeRef,
44
};
55
use crate::{
66
atomic_func,
@@ -11,7 +11,6 @@ use crate::{
1111
},
1212
class::{PyClassDef, PyClassImpl},
1313
common::ascii,
14-
convert::ToPyObject,
1514
dictdatatype::{self, DictKey},
1615
function::{
1716
ArgIterable, FuncArgs, KwArgs, OptionalArg, PyArithmeticValue::*, PyComparisonValue,
@@ -24,7 +23,8 @@ use crate::{
2423
IterNextIterable, Iterable, PyComparisonOp, Unconstructible, Unhashable,
2524
},
2625
vm::VirtualMachine,
27-
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
26+
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyRefExact, PyResult,
27+
TryFromObject,
2828
};
2929
use once_cell::sync::Lazy;
3030
use rustpython_common::lock::PyMutex;
@@ -65,8 +65,9 @@ impl PyDict {
6565

6666
// Used in update and ior.
6767
pub(crate) fn merge_object(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
68-
let other = match other.downcast_exact(vm) {
69-
Ok(dict_other) => return self.merge_dict(dict_other, vm),
68+
let casted: Result<PyRefExact<PyDict>, _> = other.downcast_exact(vm);
69+
let other = match casted {
70+
Ok(dict_other) => return self.merge_dict(dict_other.into_pyref(), vm),
7071
Err(other) => other,
7172
};
7273
let dict = &self.entries;
@@ -227,7 +228,7 @@ impl PyDict {
227228
for key in iterable.iter(vm)? {
228229
pydict.setitem(key?, value.clone(), vm)?;
229230
}
230-
Ok(pydict.to_pyobject(vm))
231+
Ok(pydict.into_pyref().into())
231232
}
232233
Err(pyobj) => {
233234
for key in iterable.iter(vm)? {
@@ -533,9 +534,8 @@ impl Py<PyDict> {
533534
pub fn to_attributes(&self, vm: &VirtualMachine) -> PyAttributes {
534535
let mut attrs = PyAttributes::default();
535536
for (key, value) in self {
536-
// TODO: use PyRefExact for interning
537-
let key: PyStrRef = key.downcast().expect("dict has non-string keys");
538-
attrs.insert(vm.ctx.intern_str(key.as_str()), value);
537+
let key: PyRefExact<PyStr> = key.downcast_exact(vm).expect("dict has non-string keys");
538+
attrs.insert(vm.ctx.intern_str(key), value);
539539
}
540540
attrs
541541
}

vm/src/builtins/int.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl Constructor for PyInt {
231231
let val = if cls.is(vm.ctx.types.int_type) {
232232
match val.downcast_exact::<PyInt>(vm) {
233233
Ok(i) => {
234-
return Ok(i.to_pyobject(vm));
234+
return Ok(i.into_pyref().into());
235235
}
236236
Err(val) => val,
237237
}

vm/src/builtins/set.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ impl PySetInner {
354354
self.merge_set(any_set, vm)
355355
// check Dict
356356
} else if let Ok(dict) = iterable.to_owned().downcast_exact::<PyDict>(vm) {
357-
self.merge_dict(dict, vm)
357+
self.merge_dict(dict.into_pyref(), vm)
358358
} else {
359359
// add iterable that is not AnySet or Dict
360360
for item in iterable.try_into_value::<ArgIterable>(vm)?.iter(vm)? {
@@ -799,7 +799,7 @@ impl Constructor for PyFrozenSet {
799799
let elements = if let OptionalArg::Present(iterable) = iterable {
800800
let iterable = if cls.is(vm.ctx.types.frozenset_type) {
801801
match iterable.downcast_exact::<Self>(vm) {
802-
Ok(fs) => return Ok(fs.into()),
802+
Ok(fs) => return Ok(fs.into_pyref().into()),
803803
Err(iterable) => iterable,
804804
}
805805
} else {

vm/src/builtins/tuple.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl Constructor for PyTuple {
9595
let elements = if let OptionalArg::Present(iterable) = iterable {
9696
let iterable = if cls.is(vm.ctx.types.tuple_type) {
9797
match iterable.downcast_exact::<Self>(vm) {
98-
Ok(tuple) => return Ok(tuple.into()),
98+
Ok(tuple) => return Ok(tuple.into_pyref().into()),
9999
Err(iterable) => iterable,
100100
}
101101
} else {

vm/src/bytesinner.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,7 @@ impl ByteInnerNewOptions {
7979
// construct an exact bytes from an exact bytes do not clone
8080
let obj = if cls.is(PyBytes::class(vm)) {
8181
match obj.downcast_exact::<PyBytes>(vm) {
82-
Ok(b) => {
83-
return Ok(b);
84-
}
82+
Ok(b) => return Ok(b.into_pyref()),
8583
Err(obj) => obj,
8684
}
8785
} else {

vm/src/object/core.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//! but not to do to remember it is a PyRef object.
1313
1414
use super::{
15-
ext::{AsObject, PyResult},
15+
ext::{AsObject, PyRefExact, PyResult},
1616
payload::PyObjectPayload,
1717
PyAtomicRef,
1818
};
@@ -564,15 +564,15 @@ impl PyObjectRef {
564564
pub fn downcast_exact<T: PyObjectPayload + crate::PyPayload>(
565565
self,
566566
vm: &VirtualMachine,
567-
) -> Result<PyRef<T>, Self> {
567+
) -> Result<PyRefExact<T>, Self> {
568568
if self.class().is(T::class(vm)) {
569569
// TODO: is this always true?
570570
assert!(
571571
self.payload_is::<T>(),
572572
"obj.__class__ is T::class() but payload is not T"
573573
);
574574
// SAFETY: just asserted that payload_is::<T>()
575-
Ok(unsafe { PyRef::from_obj_unchecked(self) })
575+
Ok(unsafe { PyRefExact::new_unchecked(PyRef::from_obj_unchecked(self)) })
576576
} else {
577577
Err(self)
578578
}

vm/src/object/ext.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ impl<T: PyPayload> std::borrow::ToOwned for PyExact<T> {
107107
}
108108
}
109109

110+
/// PyRef but guaranteed not to be a subtype instance
110111
#[derive(Debug)]
111112
#[repr(transparent)]
112113
pub struct PyRefExact<T: PyObjectPayload> {

vm/src/stdlib/builtins.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,11 @@ mod builtins {
872872
// Use downcast_exact to keep ref to old object on error.
873873
let metaclass = kwargs
874874
.pop_kwarg("metaclass")
875-
.map(|metaclass| metaclass.downcast_exact::<PyType>(vm))
875+
.map(|metaclass| {
876+
metaclass
877+
.downcast_exact::<PyType>(vm)
878+
.map(|m| m.into_pyref())
879+
})
876880
.unwrap_or_else(|| Ok(vm.ctx.types.type_type.to_owned()));
877881

878882
let (metaclass, meta_name) = match metaclass {

0 commit comments

Comments
 (0)