mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
refactor length now use sequence and mapping protocol
This commit is contained in:
committed by
Jeong YunWon
parent
dc31fd3901
commit
52b458d524
@@ -32,6 +32,17 @@ impl<'a> From<&'a PyObject> for PyMapping<'a> {
|
||||
methods: OnceCell::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn length(&self, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
if let Some(f) = self.methods(vm).length {
|
||||
f(self.0.clone(), vm)
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"object of type '{}' has no len() or not a mapping",
|
||||
self.0.class().name()
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<PyObject> for PyMapping<'_> {
|
||||
|
||||
@@ -408,12 +408,12 @@ impl PyObject {
|
||||
// int PyObject_TypeCheck(PyObject *o, PyTypeObject *type)
|
||||
|
||||
pub fn length(&self, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
vm.obj_len_opt(self).unwrap_or_else(|| {
|
||||
Err(vm.new_type_error(format!(
|
||||
"object of type '{}' has no len()",
|
||||
self.class().name()
|
||||
)))
|
||||
})
|
||||
let seq = PySequence::from(self);
|
||||
if let Ok(len) = seq.length(vm) {
|
||||
Ok(len)
|
||||
} else {
|
||||
PyMapping::try_from_object(vm, self.to_owned())?.length(vm)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_item<K: DictKey + IntoPyObject + Clone>(
|
||||
|
||||
@@ -297,7 +297,7 @@ impl PySequence<'_> {
|
||||
if let Some(tuple) = self.obj.downcast_ref_if_exact::<PyTuple>(vm) {
|
||||
Ok(tuple.to_owned())
|
||||
} else if let Some(list) = self.obj.downcast_ref_if_exact::<PyList>(vm) {
|
||||
Ok(vm.ctx.new_tuple(list.borrow_vec().to_vec()).into())
|
||||
Ok(vm.ctx.new_tuple(list.borrow_vec().to_vec()))
|
||||
} else {
|
||||
let iter = self.obj.to_owned().get_iter(vm)?;
|
||||
let iter = iter.iter(vm)?;
|
||||
|
||||
@@ -166,7 +166,7 @@ macro_rules! then_some_closure {
|
||||
|
||||
pub use crate::builtins::object::{generic_getattr, generic_setattr};
|
||||
fn slot_length(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
let ret = vm.call_special_method(obj.to_owned(), "__len__", ())?;
|
||||
let ret = vm.call_special_method(obj, "__len__", ())?;
|
||||
let len = ret.payload::<PyInt>().ok_or_else(|| {
|
||||
vm.new_type_error(format!(
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
|
||||
41
vm/src/vm.rs
41
vm/src/vm.rs
@@ -30,7 +30,7 @@ use crate::{
|
||||
PyObjectWrap, PyRef, PyRefExact, PyResult, PyValue, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use num_traits::{Signed, ToPrimitive};
|
||||
use num_traits::ToPrimitive;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::{Cell, Ref, RefCell};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@@ -1672,41 +1672,12 @@ impl VirtualMachine {
|
||||
.invoke((), self)
|
||||
}
|
||||
|
||||
pub fn obj_len_opt(&self, obj: &PyObject) -> Option<PyResult<usize>> {
|
||||
self.get_special_method(obj.to_owned(), "__len__")
|
||||
.map(Result::ok)
|
||||
.transpose()
|
||||
.map(|meth| {
|
||||
let len = meth?.invoke((), self)?;
|
||||
let len = len
|
||||
.payload_if_subclass::<PyInt>(self)
|
||||
.ok_or_else(|| {
|
||||
self.new_type_error(format!(
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
len.class().name()
|
||||
))
|
||||
})?
|
||||
.as_bigint();
|
||||
if len.is_negative() {
|
||||
return Err(self.new_value_error("__len__() should return >= 0".to_owned()));
|
||||
}
|
||||
let len = len.to_isize().ok_or_else(|| {
|
||||
self.new_overflow_error(
|
||||
"cannot fit 'int' into an index-sized integer".to_owned(),
|
||||
)
|
||||
})?;
|
||||
Ok(len as usize)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn length_hint_opt(&self, iter: PyObjectRef) -> PyResult<Option<usize>> {
|
||||
if let Some(len) = self.obj_len_opt(&iter) {
|
||||
match len {
|
||||
Ok(len) => return Ok(Some(len)),
|
||||
Err(e) => {
|
||||
if !e.isinstance(&self.ctx.exceptions.type_error) {
|
||||
return Err(e);
|
||||
}
|
||||
match iter.length(self) {
|
||||
Ok(len) => return Ok(Some(len)),
|
||||
Err(e) => {
|
||||
if !e.isinstance(&self.ctx.exceptions.type_error) {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user