Skip to content

Commit e4cdb14

Browse files
authored
Merge pull request RustPython#2194 from RustPython/coolreader18/deque-seq
Mini changes pulled from RustPython#2146
2 parents 3d88545 + 0b801cc commit e4cdb14

File tree

5 files changed

+117
-76
lines changed

5 files changed

+117
-76
lines changed

vm/src/cformat.rs

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ enum CFormatErrorType {
2020
UnescapedModuloSignInLiteral,
2121
UnsupportedFormatChar(char),
2222
IncompleteFormat,
23+
IntTooBig,
2324
// Unimplemented,
2425
}
2526

@@ -43,6 +44,7 @@ impl fmt::Display for CFormatError {
4344
"unsupported format character '{}' ({:#x}) at index {}",
4445
c, c as u32, self.index
4546
),
47+
IntTooBig => write!(f, "width/precision too big"),
4648
_ => write!(f, "unexpected error parsing format string"),
4749
}
4850
}
@@ -300,19 +302,32 @@ impl CFormatSpec {
300302
self.format_string(result.borrow_value().to_owned())
301303
}
302304
CFormatType::Number(number_type) => {
303-
if !objtype::isinstance(&obj, &vm.ctx.types.int_type) {
305+
let err = || {
304306
let required_type_string = match number_type {
305307
CNumberType::Decimal => "a number",
306308
_ => "an integer",
307309
};
308-
return Err(vm.new_type_error(format!(
310+
vm.new_type_error(format!(
309311
"%{} format: {} is required, not {}",
310312
self.format_char,
311313
required_type_string,
312314
obj.lease_class()
313-
)));
314-
}
315-
self.format_number(objint::get_value(&obj))
315+
))
316+
};
317+
match_class!(match &obj {
318+
ref i @ objint::PyInt => {
319+
self.format_number(i.borrow_value())
320+
}
321+
// TODO: if guards for match_class
322+
ref f @ objfloat::PyFloat => {
323+
if let CNumberType::Decimal = number_type {
324+
self.format_number(&objfloat::try_bigint(f.to_f64(), vm)?)
325+
} else {
326+
return Err(err());
327+
}
328+
}
329+
_ => return Err(err()),
330+
})
316331
}
317332
CFormatType::Float(_) => {
318333
let value = objfloat::try_float(&obj, vm)?.ok_or_else(|| {
@@ -420,25 +435,22 @@ impl CFormatString {
420435
mut tuple_index: usize,
421436
) -> PyResult<usize> {
422437
match q {
423-
Some(CFormatQuantity::FromValuesTuple) => {
424-
match elements.next() {
425-
Some(width_obj) => {
426-
tuple_index += 1;
427-
if !objtype::isinstance(&width_obj, &vm.ctx.types.int_type) {
428-
Err(vm.new_type_error("* wants int".to_owned()))
429-
} else {
430-
// TODO: handle errors when truncating BigInt to usize
431-
*q = Some(CFormatQuantity::Amount(
432-
objint::get_value(&width_obj).to_usize().unwrap(),
433-
));
434-
Ok(tuple_index)
435-
}
438+
Some(CFormatQuantity::FromValuesTuple) => match elements.next() {
439+
Some(width_obj) => {
440+
tuple_index += 1;
441+
if !objtype::isinstance(&width_obj, &vm.ctx.types.int_type) {
442+
Err(vm.new_type_error("* wants int".to_owned()))
443+
} else {
444+
let i = objint::get_value(&width_obj);
445+
let i = objint::try_to_primitive::<isize>(i, vm)? as usize;
446+
*q = Some(CFormatQuantity::Amount(i));
447+
Ok(tuple_index)
436448
}
437-
None => Err(
438-
vm.new_type_error("not enough arguments for format string".to_owned())
439-
),
440449
}
441-
}
450+
None => {
451+
Err(vm.new_type_error("not enough arguments for format string".to_owned()))
452+
}
453+
},
442454
_ => Ok(tuple_index),
443455
}
444456
}
@@ -543,30 +555,30 @@ impl CFormatString {
543555
}
544556
}
545557

546-
fn parse_quantity(text: &str) -> (Option<CFormatQuantity>, &str) {
558+
fn parse_quantity(text: &str) -> Result<(Option<CFormatQuantity>, &str), CFormatErrorType> {
547559
let num_digits: usize = get_num_digits(text);
548-
if num_digits == 0 {
560+
let ret = if num_digits == 0 {
549561
let mut chars = text.chars();
550-
return match chars.next() {
562+
match chars.next() {
551563
Some('*') => (Some(CFormatQuantity::FromValuesTuple), chars.as_str()),
552564
_ => (None, text),
553-
};
554-
}
555-
// This should never fail
556-
(
557-
Some(CFormatQuantity::Amount(
558-
text[..num_digits].parse::<usize>().unwrap(),
559-
)),
560-
&text[num_digits..],
561-
)
565+
}
566+
} else {
567+
let q = text[..num_digits]
568+
.parse::<isize>()
569+
.map_err(|_| CFormatErrorType::IntTooBig)? as usize;
570+
(Some(CFormatQuantity::Amount(q)), &text[num_digits..])
571+
};
572+
Ok(ret)
562573
}
563574

564-
fn parse_precision(text: &str) -> (Option<CFormatQuantity>, &str) {
575+
fn parse_precision(text: &str) -> Result<(Option<CFormatQuantity>, &str), CFormatErrorType> {
565576
let mut chars = text.chars();
566-
match chars.next() {
567-
Some('.') => parse_quantity(&chars.as_str()),
577+
let ret = match chars.next() {
578+
Some('.') => parse_quantity(&chars.as_str())?,
568579
_ => (None, text),
569-
}
580+
};
581+
Ok(ret)
570582
}
571583

572584
fn parse_literal_single(text: &str) -> Result<(char, &str), CFormatErrorType> {
@@ -794,8 +806,10 @@ impl FromStr for CFormatSpec {
794806
let (mapping_key, after_mapping_key) = parse_spec_mapping_key(after_modulo_sign)
795807
.map_err(|err| (err, calc_consumed(text, after_modulo_sign)))?;
796808
let (flags, after_flags) = parse_flags(after_mapping_key);
797-
let (width, after_width) = parse_quantity(after_flags);
798-
let (precision, after_precision) = parse_precision(after_width);
809+
let (width, after_width) =
810+
parse_quantity(after_flags).map_err(|err| (err, calc_consumed(text, after_flags)))?;
811+
let (precision, after_precision) =
812+
parse_precision(after_width).map_err(|err| (err, calc_consumed(text, after_width)))?;
799813
// A length modifier (h, l, or L) may be present,
800814
// but is ignored as it is not necessary for Python – so e.g. %ld is identical to %d.
801815
let after_length = consume_length(after_precision);

vm/src/obj/objint.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
use std::convert::TryFrom;
12
use std::fmt;
23
use std::mem::size_of;
34

45
use bstr::ByteSlice;
56
use num_bigint::{BigInt, BigUint, Sign};
67
use num_integer::Integer;
7-
use num_traits::{One, Pow, Signed, ToPrimitive, Zero};
8+
use num_traits::{One, Pow, PrimInt, Signed, ToPrimitive, Zero};
89

910
use super::objbool::IntoPyBool;
1011
use super::objbytearray::PyByteArray;
@@ -93,20 +94,24 @@ macro_rules! impl_into_pyobject_int {
9394

9495
impl_into_pyobject_int!(isize i8 i16 i32 i64 usize u8 u16 u32 u64 BigInt);
9596

97+
pub fn try_to_primitive<'a, I>(i: &'a BigInt, vm: &VirtualMachine) -> PyResult<I>
98+
where
99+
I: PrimInt + TryFrom<&'a BigInt>,
100+
{
101+
I::try_from(i).map_err(|_| {
102+
vm.new_overflow_error(format!(
103+
"Python int too large to convert to Rust {}",
104+
std::any::type_name::<I>()
105+
))
106+
})
107+
}
108+
96109
macro_rules! impl_try_from_object_int {
97110
($(($t:ty, $to_prim:ident),)*) => {$(
98111
impl TryFromObject for $t {
99112
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
100113
let int = PyIntRef::try_from_object(vm, obj)?;
101-
match int.value.$to_prim() {
102-
Some(value) => Ok(value),
103-
None => Err(
104-
vm.new_overflow_error(concat!(
105-
"Int value cannot fit into Rust ",
106-
stringify!($t)
107-
).to_owned())
108-
),
109-
}
114+
try_to_primitive(&int.value, vm)
110115
}
111116
}
112117
)*};

vm/src/obj/objiter.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
*/
44

55
use crossbeam_utils::atomic::AtomicCell;
6-
use num_traits::{Signed, ToPrimitive};
6+
use num_traits::Signed;
77

8-
use super::objint::PyInt;
8+
use super::objint::{self, PyInt};
99
use super::objsequence;
1010
use super::objtype::{self, PyClassRef};
1111
use crate::exceptions::PyBaseExceptionRef;
@@ -143,9 +143,7 @@ pub fn length_hint(vm: &VirtualMachine, iter: PyObjectRef) -> PyResult<Option<us
143143
if result.is_negative() {
144144
return Err(vm.new_value_error("__length_hint__() should return >= 0".to_owned()));
145145
}
146-
let hint = result.to_usize().ok_or_else(|| {
147-
vm.new_value_error("Python int too large to convert to Rust usize".to_owned())
148-
})?;
146+
let hint = objint::try_to_primitive(result, vm)?;
149147
Ok(Some(hint))
150148
}
151149

vm/src/stdlib/collections.rs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub(crate) use _collections::make_module;
44
mod _collections {
55
use crate::common::cell::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard};
66
use crate::function::OptionalArg;
7-
use crate::obj::{objiter, objtype::PyClassRef};
7+
use crate::obj::{objiter, objsequence, objtype::PyClassRef};
88
use crate::pyobject::{
99
IdProtocol, PyArithmaticValue::*, PyClassImpl, PyComparisonValue, PyIterable, PyObjectRef,
1010
PyRef, PyResult, PyValue,
@@ -247,7 +247,32 @@ mod _collections {
247247
self.maxlen.store(maxlen);
248248
}
249249

250-
#[pymethod(name = "__repr__")]
250+
#[pymethod(magic)]
251+
fn getitem(&self, idx: isize, vm: &VirtualMachine) -> PyResult {
252+
let deque = self.borrow_deque();
253+
objsequence::get_pos(idx, deque.len())
254+
.and_then(|i| deque.get(i).cloned())
255+
.ok_or_else(|| vm.new_index_error("deque index out of range".to_owned()))
256+
}
257+
258+
#[pymethod(magic)]
259+
fn setitem(&self, idx: isize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
260+
let mut deque = self.borrow_deque_mut();
261+
objsequence::get_pos(idx, deque.len())
262+
.and_then(|i| deque.get_mut(i))
263+
.map(|x| *x = value)
264+
.ok_or_else(|| vm.new_index_error("deque index out of range".to_owned()))
265+
}
266+
267+
#[pymethod(magic)]
268+
fn delitem(&self, idx: isize, vm: &VirtualMachine) -> PyResult<()> {
269+
let mut deque = self.borrow_deque_mut();
270+
objsequence::get_pos(idx, deque.len())
271+
.and_then(|i| deque.remove(i).map(drop))
272+
.ok_or_else(|| vm.new_index_error("deque index out of range".to_owned()))
273+
}
274+
275+
#[pymethod(magic)]
251276
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<String> {
252277
let repr = if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
253278
let elements = zelf
@@ -299,7 +324,7 @@ mod _collections {
299324
Ok(r)
300325
}
301326

302-
#[pymethod(name = "__eq__")]
327+
#[pymethod(magic)]
303328
fn eq(
304329
zelf: PyRef<Self>,
305330
other: PyObjectRef,
@@ -312,7 +337,7 @@ mod _collections {
312337
}
313338
}
314339

315-
#[pymethod(name = "__ne__")]
340+
#[pymethod(magic)]
316341
fn ne(
317342
zelf: PyRef<Self>,
318343
other: PyObjectRef,
@@ -321,7 +346,7 @@ mod _collections {
321346
Ok(PyDeque::eq(zelf, other, vm)?.map(|v| !v))
322347
}
323348

324-
#[pymethod(name = "__lt__")]
349+
#[pymethod(magic)]
325350
fn lt(
326351
zelf: PyRef<Self>,
327352
other: PyObjectRef,
@@ -334,7 +359,7 @@ mod _collections {
334359
}
335360
}
336361

337-
#[pymethod(name = "__gt__")]
362+
#[pymethod(magic)]
338363
fn gt(
339364
zelf: PyRef<Self>,
340365
other: PyObjectRef,
@@ -347,7 +372,7 @@ mod _collections {
347372
}
348373
}
349374

350-
#[pymethod(name = "__le__")]
375+
#[pymethod(magic)]
351376
fn le(
352377
zelf: PyRef<Self>,
353378
other: PyObjectRef,
@@ -360,7 +385,7 @@ mod _collections {
360385
}
361386
}
362387

363-
#[pymethod(name = "__ge__")]
388+
#[pymethod(magic)]
364389
fn ge(
365390
zelf: PyRef<Self>,
366391
other: PyObjectRef,
@@ -373,7 +398,7 @@ mod _collections {
373398
}
374399
}
375400

376-
#[pymethod(name = "__mul__")]
401+
#[pymethod(magic)]
377402
fn mul(&self, n: isize) -> Self {
378403
let deque: SimpleSeqDeque = self.borrow_deque().into();
379404
let mul = sequence::seq_mul(&deque, n);
@@ -389,12 +414,12 @@ mod _collections {
389414
}
390415
}
391416

392-
#[pymethod(name = "__len__")]
417+
#[pymethod(magic)]
393418
fn len(&self) -> usize {
394419
self.borrow_deque().len()
395420
}
396421

397-
#[pymethod(name = "__iter__")]
422+
#[pymethod(magic)]
398423
fn iter(zelf: PyRef<Self>) -> PyDequeIterator {
399424
PyDequeIterator {
400425
position: AtomicCell::new(0),
@@ -419,7 +444,7 @@ mod _collections {
419444

420445
#[pyimpl]
421446
impl PyDequeIterator {
422-
#[pymethod(name = "__next__")]
447+
#[pymethod(magic)]
423448
fn next(&self, vm: &VirtualMachine) -> PyResult {
424449
let pos = self.position.fetch_add(1);
425450
let deque = self.deque.borrow_deque();
@@ -431,7 +456,7 @@ mod _collections {
431456
}
432457
}
433458

434-
#[pymethod(name = "__iter__")]
459+
#[pymethod(magic)]
435460
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
436461
zelf
437462
}

vm/src/stdlib/io.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,12 @@ impl PyBytesIORef {
341341
//Takes an integer k (bytes) and returns them from the underlying buffer
342342
//If k is undefined || k == -1, then we read all bytes until the end of the file.
343343
//This also increments the stream position by the value of k
344-
fn read(self, size: OptionalSize, vm: &VirtualMachine) -> PyResult {
345-
match self.buffer(vm)?.read(size.to_usize()) {
346-
Some(value) => Ok(vm.ctx.new_bytes(value)),
347-
None => Err(vm.new_value_error("Error Retrieving Value".to_owned())),
348-
}
344+
fn read(self, size: OptionalSize, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
345+
let buf = self
346+
.buffer(vm)?
347+
.read(size.to_usize())
348+
.unwrap_or_else(Vec::new);
349+
Ok(buf)
349350
}
350351

351352
//skip to the jth position
@@ -1051,9 +1052,7 @@ fn text_io_wrapper_write(
10511052
let bytes = obj.borrow_value().to_owned().into_bytes();
10521053

10531054
let len = vm.call_method(&raw, "write", vec![vm.ctx.new_bytes(bytes.clone())])?;
1054-
let len = objint::get_value(&len)
1055-
.to_usize()
1056-
.ok_or_else(|| vm.new_overflow_error("int to large to convert to Rust usize".to_owned()))?;
1055+
let len = objint::try_to_primitive(objint::get_value(&len), vm)?;
10571056

10581057
// returns the count of unicode code points written
10591058
let len = from_utf8(&bytes[..len])

0 commit comments

Comments
 (0)