Skip to content

Commit ff05200

Browse files
authored
Merge branch 'master' into dev3
2 parents 1150f50 + c465662 commit ff05200

File tree

6 files changed

+202
-25
lines changed

6 files changed

+202
-25
lines changed

Lib/test/test_array.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ class ArraySubclassWithKwargs(array.array):
2525
def __init__(self, typecode, newarg=None):
2626
array.array.__init__(self)
2727

28-
typecodes = 'ubBhHiIlLfdqQ'
28+
# TODO: RUSTPYTHON
29+
# We did not support typecode u for unicode yet
30+
# typecodes = 'ubBhHiIlLfdqQ'
31+
typecodes = 'bBhHiIlLfdqQ'
2932

3033
class MiscTest(unittest.TestCase):
3134

@@ -497,8 +500,6 @@ def test_fromarray(self):
497500
b = array.array(self.typecode, a)
498501
self.assertEqual(a, b)
499502

500-
# TODO: RUSTPYTHON
501-
@unittest.expectedFailure
502503
def test_repr(self):
503504
a = array.array(self.typecode, 2*self.example)
504505
self.assertEqual(a, eval(repr(a), {"array": array.array}))
@@ -801,8 +802,6 @@ def test_extended_getslice(self):
801802
self.assertEqual(list(a[start:stop:step]),
802803
list(a)[start:stop:step])
803804

804-
# TODO: RUSTPYTHON
805-
@unittest.expectedFailure
806805
def test_setslice(self):
807806
a = array.array(self.typecode, self.example)
808807
a[:1] = a
@@ -1235,8 +1234,6 @@ def test_delslice(self):
12351234
a = array.array(self.typecode, range(10))
12361235
del a[9::1<<333]
12371236

1238-
# TODO: RUSTPYTHON
1239-
@unittest.expectedFailure
12401237
def test_assignment(self):
12411238
a = array.array(self.typecode, range(10))
12421239
a[::2] = array.array(self.typecode, [42]*5)

tests/snippets/stdlib_array.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,17 @@ def test_float_with_integer_input():
3232
assert f == array("f", [-2, 0, 2, 3, 4])
3333

3434
test_float_with_integer_input()
35+
36+
# slice assignment step overflow behaviour test
37+
T = 'I'
38+
a = array(T, range(10))
39+
b = array(T, [100])
40+
a[::9999999999] = b
41+
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 9])
42+
a[::-9999999999] = b
43+
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])
44+
c = array(T)
45+
a[0:0:9999999999] = c
46+
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])
47+
a[0:0:-9999999999] = c
48+
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])

vm/src/bytesinner.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,13 +252,11 @@ impl PyBytesInner {
252252
let mut res = String::with_capacity(self.elements.len());
253253
for i in self.elements.iter() {
254254
match i {
255-
0..=8 => res.push_str(&format!("\\x0{}", i)),
256255
9 => res.push_str("\\t"),
257256
10 => res.push_str("\\n"),
258-
11 => res.push_str(&format!("\\x0{:x}", i)),
259257
13 => res.push_str("\\r"),
260258
32..=126 => res.push(*(i) as char),
261-
_ => res.push_str(&format!("\\x{:x}", i)),
259+
_ => res.push_str(&format!("\\x{:02x}", i)),
262260
}
263261
}
264262
res

vm/src/stdlib/array.rs

Lines changed: 157 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,21 @@ use crate::common::cell::{
55
use crate::function::OptionalArg;
66
use crate::obj::objbytes::PyBytesRef;
77
use crate::obj::objfloat::try_float;
8-
use crate::obj::objsequence::PySliceableSequence;
8+
use crate::obj::objsequence::{get_slice_range, PySliceableSequence};
99
use crate::obj::objslice::PySliceRef;
1010
use crate::obj::objstr::PyStringRef;
1111
use crate::obj::objtype::PyClassRef;
1212
use crate::obj::{objbool, objiter};
1313
use crate::pyobject::{
14-
BorrowValue, Either, IntoPyObject, PyArithmaticValue, PyClassImpl, PyComparisonValue,
15-
PyIterable, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
14+
BorrowValue, Either, IdProtocol, IntoPyObject, PyArithmaticValue, PyClassImpl,
15+
PyComparisonValue, PyIterable, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
16+
TypeProtocol,
1617
};
1718
use crate::VirtualMachine;
1819
use crossbeam_utils::atomic::AtomicCell;
1920
use itertools::Itertools;
21+
use num_bigint::BigInt;
22+
use num_traits::{One, Signed, ToPrimitive, Zero};
2023
use std::fmt;
2124

2225
struct ArrayTypeSpecifierError {
@@ -34,7 +37,7 @@ impl fmt::Display for ArrayTypeSpecifierError {
3437

3538
macro_rules! def_array_enum {
3639
($(($n:ident, $t:ident, $c:literal)),*$(,)?) => {
37-
#[derive(Debug)]
40+
#[derive(Debug, Clone)]
3841
enum ArrayContentType {
3942
$($n(Vec<$t>),)*
4043
}
@@ -230,20 +233,130 @@ macro_rules! def_array_enum {
230233
Either::B(slice) => self.getitem_by_slice(slice, vm),
231234
}
232235
}
236+
237+
fn setitem_by_slice(&mut self, slice: PySliceRef, items: &ArrayContentType, vm: &VirtualMachine) -> PyResult<()> {
238+
let start = slice.start_index(vm)?;
239+
let stop = slice.stop_index(vm)?;
240+
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
241+
242+
if step.is_zero() {
243+
return Err(vm.new_value_error("slice step cannot be zero".to_owned()));
244+
}
233245

234-
fn setitem(&mut self, needle: Either<isize, PySliceRef>, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
235-
match needle {
236-
Either::A(i) => {
237-
let i = self.idx(i, "array assignment", vm)?;
238-
match self {
239-
$(ArrayContentType::$n(v) => { v[i] = $t::try_into_from_object(vm, value)? },)*
246+
match self {
247+
$(ArrayContentType::$n(elements) => if let ArrayContentType::$n(items) = items {
248+
if step == BigInt::one() {
249+
let range = get_slice_range(&start, &stop, elements.len());
250+
let range = if range.end < range.start {
251+
range.start..range.start
252+
} else {
253+
range
254+
};
255+
elements.splice(range, items.iter().cloned());
256+
return Ok(());
240257
}
241-
Ok(())
242-
}
243-
Either::B(_slice) => Err(vm.new_not_implemented_error("array slice is not implemented".to_owned())),
258+
259+
let (start, stop, step, is_negative_step) = if step.is_negative() {
260+
(
261+
stop.map(|x| if x == -BigInt::one() {
262+
elements.len() + BigInt::one()
263+
} else {
264+
x + 1
265+
}),
266+
start.map(|x| if x == -BigInt::one() {
267+
BigInt::from(elements.len())
268+
} else {
269+
x + 1
270+
}),
271+
-step,
272+
true
273+
)
274+
} else {
275+
(start, stop, step, false)
276+
};
277+
278+
let range = get_slice_range(&start, &stop, elements.len());
279+
let range = if range.end < range.start {
280+
range.start..range.start
281+
} else {
282+
range
283+
};
284+
285+
// step is not negative here
286+
if let Some(step) = step.to_usize() {
287+
let slicelen = if range.end > range.start {
288+
(range.end - range.start - 1) / step + 1
289+
} else {
290+
0
291+
};
292+
293+
if slicelen == items.len() {
294+
if is_negative_step {
295+
for (i, &item) in range.rev().step_by(step).zip(items) {
296+
elements[i] = item;
297+
}
298+
} else {
299+
for (i, &item) in range.step_by(step).zip(items) {
300+
elements[i] = item;
301+
}
302+
}
303+
Ok(())
304+
} else {
305+
Err(vm.new_value_error(format!(
306+
"attempt to assign sequence of size {} to extended slice of size {}",
307+
items.len(), slicelen
308+
)))
309+
}
310+
} else {
311+
// edge case, step is too big for usize
312+
// same behaviour as CPython
313+
let slicelen = if range.start < range.end { 1 } else { 0 };
314+
if match items.len() {
315+
0 => slicelen == 0,
316+
1 => {
317+
elements[
318+
if is_negative_step { range.end - 1 } else { range.start }
319+
] = items[0];
320+
true
321+
},
322+
_ => false,
323+
} {
324+
Ok(())
325+
} else {
326+
Err(vm.new_value_error(format!(
327+
"attempt to assign sequence of size {} to extended slice of size {}",
328+
items.len(), slicelen
329+
)))
330+
}
331+
}
332+
} else {
333+
Err(vm.new_type_error("bad argument type for built-in operation".to_owned()))
334+
},)*
244335
}
245336
}
246337

338+
fn setitem_by_idx(&mut self, i: isize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
339+
let i = self.idx(i, "array assignment", vm)?;
340+
match self {
341+
$(ArrayContentType::$n(v) => { v[i] = TryFromObject::try_from_object(vm, value)? },)*
342+
}
343+
Ok(())
344+
}
345+
346+
fn repr(&self, _vm: &VirtualMachine) -> PyResult<String> {
347+
// we don't need ReprGuard here
348+
let s = match self {
349+
$(ArrayContentType::$n(v) => {
350+
if v.is_empty() {
351+
format!("array('{}')", $c)
352+
} else {
353+
format!("array('{}', [{}])", $c, v.iter().format(", "))
354+
}
355+
})*
356+
};
357+
Ok(s)
358+
}
359+
247360
fn iter<'a>(&'a self, vm: &'a VirtualMachine) -> impl Iterator<Item = PyObjectRef> + 'a {
248361
let mut i = 0;
249362
std::iter::from_fn(move || {
@@ -479,12 +592,41 @@ impl PyArray {
479592

480593
#[pymethod(magic)]
481594
fn setitem(
482-
&self,
595+
zelf: PyRef<Self>,
483596
needle: Either<isize, PySliceRef>,
484597
obj: PyObjectRef,
485598
vm: &VirtualMachine,
486599
) -> PyResult<()> {
487-
self.borrow_value_mut().setitem(needle, obj, vm)
600+
match needle {
601+
Either::A(i) => zelf.borrow_value_mut().setitem_by_idx(i, obj, vm),
602+
Either::B(slice) => {
603+
let cloned;
604+
let guard;
605+
let items = if zelf.is(&obj) {
606+
cloned = zelf.borrow_value().clone();
607+
&cloned
608+
} else {
609+
match obj.payload::<PyArray>() {
610+
Some(array) => {
611+
guard = array.borrow_value();
612+
&*guard
613+
}
614+
None => {
615+
return Err(vm.new_type_error(format!(
616+
"can only assign array (not \"{}\") to array slice",
617+
obj.class().name
618+
)));
619+
}
620+
}
621+
};
622+
zelf.borrow_value_mut().setitem_by_slice(slice, items, vm)
623+
}
624+
}
625+
}
626+
627+
#[pymethod(name = "__repr__")]
628+
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<String> {
629+
zelf.borrow_value().repr(vm)
488630
}
489631

490632
#[pymethod(name = "__eq__")]

vm/src/stdlib/os.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,14 @@ mod _os {
719719
std::process::exit(code)
720720
}
721721

722+
#[pyfunction]
723+
fn abort() {
724+
extern "C" {
725+
fn abort();
726+
}
727+
unsafe { abort() }
728+
}
729+
722730
#[pyfunction]
723731
fn urandom(size: usize, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
724732
let mut buf = vec![0u8; size];

vm/src/stdlib/socket.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,23 @@ fn socket_gethostbyaddr(
579579
))
580580
}
581581

582+
#[cfg(not(target_os = "redox"))]
583+
fn socket_gethostbyname(name: PyStringRef, vm: &VirtualMachine) -> PyResult<String> {
584+
match socket_gethostbyaddr(name, vm) {
585+
Ok((_, _, hosts)) => {
586+
let lst = vm.extract_elements::<PyStringRef>(&hosts)?;
587+
Ok(lst.get(0).unwrap().to_string())
588+
}
589+
Err(_) => {
590+
let error_type = vm.class("_socket", "gaierror");
591+
Err(vm.new_exception_msg(
592+
error_type,
593+
"nodename nor servname provided, or not known".to_owned(),
594+
))
595+
}
596+
}
597+
}
598+
582599
fn get_addr<T, I>(vm: &VirtualMachine, addr: T) -> PyResult<socket2::SockAddr>
583600
where
584601
T: ToSocketAddrs<Iter = I>,
@@ -707,6 +724,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
707724
extend_module!(vm, module, {
708725
"getaddrinfo" => ctx.new_function(socket_getaddrinfo),
709726
"gethostbyaddr" => ctx.new_function(socket_gethostbyaddr),
727+
"gethostbyname" => ctx.new_function(socket_gethostbyname),
710728
});
711729

712730
extend_module_platform_specific(vm, &module);

0 commit comments

Comments
 (0)