Skip to content

Commit 2d3ea4c

Browse files
committed
generic and efficiency way to consume iterable object
1 parent 9142bfb commit 2d3ea4c

File tree

2 files changed

+47
-27
lines changed

2 files changed

+47
-27
lines changed

vm/src/bytesinner.rs

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@ use crate::function::{OptionalArg, OptionalOption};
99
use crate::obj::objbytearray::PyByteArray;
1010
use crate::obj::objbytes::{PyBytes, PyBytesRef};
1111
use crate::obj::objint::{self, PyInt, PyIntRef};
12-
use crate::obj::objlist::PyList;
1312
use crate::obj::objmemory::PyMemoryView;
1413
use crate::obj::objsingletons::PyNoneRef;
1514
use crate::obj::objslice::PySliceRef;
1615
use crate::obj::objstr::{self, PyStr, PyStrRef};
17-
use crate::obj::objtuple::PyTuple;
1816
use crate::pyobject::{
19-
BorrowValue, Either, PyComparisonValue, PyIterable, PyIterator, PyObjectRef, PyResult,
20-
TryFromObject, TypeProtocol,
17+
try_iterable_map, BorrowValue, Either, PyComparisonValue, PyIterable, PyIterator, PyObjectRef,
18+
PyResult, TryFromObject, TypeProtocol,
2119
};
2220
use crate::sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex};
2321
use crate::slots::PyComparisonOp;
@@ -41,23 +39,18 @@ impl TryFromObject for PyBytesInner {
4139
return Ok(zelf);
4240
}
4341

44-
match_class!(match obj {
45-
// TODO: generic way from &[PyObjectRef]
46-
l @ PyList => l.to_byte_inner(vm),
47-
t @ PyTuple => t.to_bytes_inner(vm),
48-
obj => {
49-
let iter = vm.get_method_or_type_error(obj.clone(), "__iter__", || {
50-
format!(
51-
"a bytes-like object is required, not '{}'",
52-
obj.class().name
53-
)
54-
})?;
55-
let iter = PyIterable::from_method(iter);
56-
Ok(PyBytesInner {
57-
elements: iter.iter(vm)?.collect::<PyResult<_>>()?,
58-
})
59-
}
60-
})
42+
if let Ok(elements) = try_iterable_map(vm, &obj, |elem: PyIntRef| {
43+
elem.borrow_value()
44+
.to_u8()
45+
.ok_or_else(|| vm.new_value_error("bytes must be in range (0, 256)".to_owned()))
46+
}) {
47+
return Ok(Self::from(elements));
48+
}
49+
50+
Err(vm.new_type_error(format!(
51+
"a bytes-like object is required, not '{}'",
52+
obj.class().name
53+
)))
6154
}
6255
}
6356

vm/src/pyobject.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,20 @@ use std::fmt;
44
use std::marker::PhantomData;
55
use std::ops::Deref;
66

7+
use itertools::Itertools;
78
use num_bigint::BigInt;
89
use num_complex::Complex64;
910
use num_traits::ToPrimitive;
1011

1112
use crate::bytecode;
13+
use crate::common::lock::{PyRwLock, PyRwLockReadGuard};
14+
use crate::common::rc::PyRc;
1215
use crate::exceptions::{self, PyBaseExceptionRef};
1316
use crate::function::{IntoFuncArgs, IntoPyNativeFunc};
1417
use crate::obj::objbuiltinfunc::PyFuncDef;
1518
use crate::obj::objbytearray;
1619
use crate::obj::objbytes;
17-
use crate::obj::objcode;
18-
use crate::obj::objcode::PyCodeRef;
20+
use crate::obj::objcode::{self, PyCodeRef};
1921
use crate::obj::objcomplex::PyComplex;
2022
use crate::obj::objdict::{PyDict, PyDictRef};
2123
use crate::obj::objfloat::PyFloat;
@@ -33,16 +35,13 @@ use crate::obj::objstaticmethod::PyStaticMethod;
3335
use crate::obj::objstr;
3436
use crate::obj::objtuple::{PyTuple, PyTupleRef};
3537
use crate::obj::objtype::{self, PyType, PyTypeRef};
36-
pub use crate::pyobjectrc::{PyObjectRc, PyObjectWeak};
3738
use crate::scope::Scope;
3839
use crate::slots::{PyTpFlags, PyTypeSlots};
3940
use crate::types::{create_type_with_slots, initialize_types, TypeZoo};
4041
use crate::vm::VirtualMachine;
41-
use rustpython_common::lock::{PyRwLock, PyRwLockReadGuard};
42-
use rustpython_common::rc::PyRc;
4342

4443
pub use crate::common::borrow::BorrowValue;
45-
44+
pub use crate::pyobjectrc::{PyObjectRc, PyObjectWeak};
4645
/* Python objects and references.
4746
4847
Okay, so each python object itself is an class itself (PyObject). Each
@@ -900,6 +899,34 @@ where
900899
}
901900
}
902901

902+
pub fn try_iterable_map<F, T, R>(
903+
vm: &VirtualMachine,
904+
obj: &PyObjectRef,
905+
mut f: F,
906+
) -> PyResult<Vec<R>>
907+
where
908+
T: TryFromObject,
909+
F: FnMut(T) -> PyResult<R>,
910+
{
911+
match_class!(match obj {
912+
ref l @ PyList => l
913+
.borrow_value()
914+
.iter()
915+
.map(|x| f(T::try_from_object(vm, x.clone())?))
916+
.try_collect(),
917+
ref t @ PyTuple => t
918+
.borrow_value()
919+
.iter()
920+
.map(|x| f(T::try_from_object(vm, x.clone())?))
921+
.try_collect(),
922+
// TODO: put internal iterable typ
923+
obj => {
924+
let iter = PyIterable::<T>::try_from_object(vm, obj.clone())?;
925+
iter.iter(vm)?.map(|x| f(x?)).try_collect()
926+
}
927+
})
928+
}
929+
903930
impl TryFromObject for PyObjectRef {
904931
#[inline]
905932
fn try_from_object(_vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {

0 commit comments

Comments
 (0)