Skip to content

Commit 2a8373c

Browse files
committed
refactor length now use sequence and mapping protocol
1 parent 807c4b5 commit 2a8373c

File tree

5 files changed

+26
-44
lines changed

5 files changed

+26
-44
lines changed

vm/src/protocol/mapping.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ impl PyMapping<PyObjectRef> {
4343
}
4444
PyMappingMethods::default()
4545
}
46+
47+
pub fn length(&self, vm: &VirtualMachine) -> PyResult<usize> {
48+
if let Some(f) = self.methods(vm).length {
49+
f(self.0.clone(), vm)
50+
} else {
51+
Err(vm.new_type_error(format!(
52+
"object of type '{}' has no len() or not a mapping",
53+
self.0.class().name()
54+
)))
55+
}
56+
}
4657
}
4758

4859
impl<T> PyMapping<T>

vm/src/protocol/object.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
bytesinner::ByteInnerNewOptions,
77
common::{hash::PyHash, str::to_ascii},
88
function::{IntoPyObject, OptionalArg},
9-
protocol::PyIter,
9+
protocol::{PyIter, PyMapping, PySequence},
1010
pyref_type_error,
1111
types::{Constructor, PyComparisonOp},
1212
utils::Either,
@@ -404,11 +404,11 @@ impl PyObject {
404404
// int PyObject_TypeCheck(PyObject *o, PyTypeObject *type)
405405

406406
pub fn length(&self, vm: &VirtualMachine) -> PyResult<usize> {
407-
vm.obj_len_opt(self).unwrap_or_else(|| {
408-
Err(vm.new_type_error(format!(
409-
"object of type '{}' has no len()",
410-
self.class().name()
411-
)))
412-
})
407+
let seq = PySequence::from(self);
408+
if let Ok(len) = seq.length(vm) {
409+
Ok(len)
410+
} else {
411+
PyMapping::try_from_object(vm, self.to_owned())?.length(vm)
412+
}
413413
}
414414
}

vm/src/protocol/sequence.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ impl PySequence<'_> {
297297
if let Some(tuple) = self.obj.downcast_ref_if_exact::<PyTuple>(vm) {
298298
Ok(tuple.to_owned())
299299
} else if let Some(list) = self.obj.downcast_ref_if_exact::<PyList>(vm) {
300-
Ok(vm.ctx.new_tuple(list.borrow_vec().to_vec()).into())
300+
Ok(vm.ctx.new_tuple(list.borrow_vec().to_vec()))
301301
} else {
302302
let iter = self.obj.to_owned().get_iter(vm)?;
303303
let iter = iter.iter(vm)?;

vm/src/types/slot.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ macro_rules! then_some_closure {
163163
}
164164

165165
fn slot_length(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
166-
let ret = vm.call_special_method(obj.to_owned(), "__len__", ())?;
166+
let ret = vm.call_special_method(obj, "__len__", ())?;
167167
let len = ret.payload::<PyInt>().ok_or_else(|| {
168168
vm.new_type_error(format!(
169169
"'{}' object cannot be interpreted as an integer",

vm/src/vm.rs

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::{
3131
TypeProtocol,
3232
};
3333
use crossbeam_utils::atomic::AtomicCell;
34-
use num_traits::{Signed, ToPrimitive};
34+
use num_traits::ToPrimitive;
3535
use std::borrow::Cow;
3636
use std::cell::{Cell, Ref, RefCell};
3737
use std::collections::{HashMap, HashSet};
@@ -1673,41 +1673,12 @@ impl VirtualMachine {
16731673
.invoke((), self)
16741674
}
16751675

1676-
pub fn obj_len_opt(&self, obj: &PyObject) -> Option<PyResult<usize>> {
1677-
self.get_special_method(obj.to_owned(), "__len__")
1678-
.map(Result::ok)
1679-
.transpose()
1680-
.map(|meth| {
1681-
let len = meth?.invoke((), self)?;
1682-
let len = len
1683-
.payload_if_subclass::<PyInt>(self)
1684-
.ok_or_else(|| {
1685-
self.new_type_error(format!(
1686-
"'{}' object cannot be interpreted as an integer",
1687-
len.class().name()
1688-
))
1689-
})?
1690-
.as_bigint();
1691-
if len.is_negative() {
1692-
return Err(self.new_value_error("__len__() should return >= 0".to_owned()));
1693-
}
1694-
let len = len.to_isize().ok_or_else(|| {
1695-
self.new_overflow_error(
1696-
"cannot fit 'int' into an index-sized integer".to_owned(),
1697-
)
1698-
})?;
1699-
Ok(len as usize)
1700-
})
1701-
}
1702-
17031676
pub fn length_hint_opt(&self, iter: PyObjectRef) -> PyResult<Option<usize>> {
1704-
if let Some(len) = self.obj_len_opt(&iter) {
1705-
match len {
1706-
Ok(len) => return Ok(Some(len)),
1707-
Err(e) => {
1708-
if !e.isinstance(&self.ctx.exceptions.type_error) {
1709-
return Err(e);
1710-
}
1677+
match iter.length(self) {
1678+
Ok(len) => return Ok(Some(len)),
1679+
Err(e) => {
1680+
if !e.isinstance(&self.ctx.exceptions.type_error) {
1681+
return Err(e);
17111682
}
17121683
}
17131684
}

0 commit comments

Comments
 (0)