Skip to content

Commit eb19eaa

Browse files
Merge pull request RustPython#646 from RustPython/joey/memoryview-slice
Convert memoryview and slice to Any payload
2 parents eb14ada + f6765cf commit eb19eaa

File tree

7 files changed

+136
-119
lines changed

7 files changed

+136
-119
lines changed

vm/src/frame.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::obj::objdict::PyDict;
1818
use crate::obj::objint::PyInt;
1919
use crate::obj::objiter;
2020
use crate::obj::objlist;
21+
use crate::obj::objslice::PySlice;
2122
use crate::obj::objstr;
2223
use crate::obj::objtype;
2324
use crate::pyobject::{
@@ -303,7 +304,9 @@ impl Frame {
303304
let step = if out.len() == 3 { out[2].take() } else { None };
304305

305306
let obj = PyObject::new(
306-
PyObjectPayload::Slice { start, stop, step },
307+
PyObjectPayload::AnyRustValue {
308+
value: Box::new(PySlice { start, stop, step }),
309+
},
307310
vm.ctx.slice_type(),
308311
);
309312
self.push_value(obj);

vm/src/obj/objmemory.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
1-
use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol};
1+
use crate::pyobject::{
2+
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult,
3+
TypeProtocol,
4+
};
25
use crate::vm::VirtualMachine;
36

7+
#[derive(Debug)]
8+
pub struct PyMemoryView {
9+
obj: PyObjectRef,
10+
}
11+
12+
impl PyObjectPayload2 for PyMemoryView {
13+
fn required_type(ctx: &PyContext) -> PyObjectRef {
14+
ctx.memoryview_type()
15+
}
16+
}
17+
418
pub fn new_memory_view(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
519
arg_check!(vm, args, required = [(cls, None), (bytes_object, None)]);
620
vm.ctx.set_attr(&cls, "obj", bytes_object.clone());
721
Ok(PyObject::new(
8-
PyObjectPayload::MemoryView {
9-
obj: bytes_object.clone(),
22+
PyObjectPayload::AnyRustValue {
23+
value: Box::new(PyMemoryView {
24+
obj: bytes_object.clone(),
25+
}),
1026
},
1127
cls.clone(),
1228
))

vm/src/obj/objrange.rs

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::pyobject::{
1212
use crate::vm::VirtualMachine;
1313

1414
use super::objint::{self, PyInt};
15+
use super::objslice::PySlice;
1516
use super::objtype;
1617

1718
#[derive(Debug, Clone)]
@@ -291,58 +292,55 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
291292
let range = get_value(zelf);
292293

293294
if let Some(i) = subscript.payload::<PyInt>() {
294-
return if let Some(int) = range.get(i.value.clone()) {
295+
if let Some(int) = range.get(i.value.clone()) {
295296
Ok(vm.ctx.new_int(int))
296297
} else {
297298
Err(vm.new_index_error("range object index out of range".to_string()))
298-
};
299-
}
300-
301-
match subscript.payload {
302-
PyObjectPayload::Slice {
303-
ref start,
304-
ref stop,
305-
ref step,
306-
} => {
307-
let new_start = if let Some(int) = start {
308-
if let Some(i) = range.get(int) {
309-
i
310-
} else {
311-
range.start.clone()
312-
}
299+
}
300+
} else if let Some(PySlice {
301+
ref start,
302+
ref stop,
303+
ref step,
304+
}) = subscript.payload()
305+
{
306+
let new_start = if let Some(int) = start {
307+
if let Some(i) = range.get(int) {
308+
i
313309
} else {
314310
range.start.clone()
315-
};
316-
317-
let new_end = if let Some(int) = stop {
318-
if let Some(i) = range.get(int) {
319-
i
320-
} else {
321-
range.end
322-
}
311+
}
312+
} else {
313+
range.start.clone()
314+
};
315+
316+
let new_end = if let Some(int) = stop {
317+
if let Some(i) = range.get(int) {
318+
i
323319
} else {
324320
range.end
325-
};
321+
}
322+
} else {
323+
range.end
324+
};
326325

327-
let new_step = if let Some(int) = step {
328-
int * range.step
329-
} else {
330-
range.step
331-
};
332-
333-
Ok(PyObject::new(
334-
PyObjectPayload::AnyRustValue {
335-
value: Box::new(PyRange {
336-
start: new_start,
337-
end: new_end,
338-
step: new_step,
339-
}),
340-
},
341-
vm.ctx.range_type(),
342-
))
343-
}
326+
let new_step = if let Some(int) = step {
327+
int * range.step
328+
} else {
329+
range.step
330+
};
344331

345-
_ => Err(vm.new_type_error("range indices must be integer or slice".to_string())),
332+
Ok(PyObject::new(
333+
PyObjectPayload::AnyRustValue {
334+
value: Box::new(PyRange {
335+
start: new_start,
336+
end: new_end,
337+
step: new_step,
338+
}),
339+
},
340+
vm.ctx.range_type(),
341+
))
342+
} else {
343+
Err(vm.new_type_error("range indices must be integer or slice".to_string()))
346344
}
347345
}
348346

vm/src/obj/objsequence.rs

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::vm::VirtualMachine;
1111
use super::objbool;
1212
use super::objint::PyInt;
1313
use super::objlist::PyList;
14+
use super::objslice::PySlice;
1415
use super::objtuple::PyTuple;
1516

1617
pub trait PySliceableSequence {
@@ -69,8 +70,8 @@ pub trait PySliceableSequence {
6970
Self: Sized,
7071
{
7172
// TODO: we could potentially avoid this copy and use slice
72-
match &slice.payload {
73-
PyObjectPayload::Slice { start, stop, step } => {
73+
match slice.payload() {
74+
Some(PySlice { start, stop, step }) => {
7475
let step = step.clone().unwrap_or_else(BigInt::one);
7576
if step.is_zero() {
7677
Err(vm.new_value_error("slice step cannot be zero".to_string()))
@@ -161,31 +162,30 @@ pub fn get_item(
161162
};
162163
}
163164

164-
match &subscript.payload {
165-
PyObjectPayload::Slice { .. } => {
166-
let payload = if sequence.payload::<PyList>().is_some() {
167-
PyObjectPayload::AnyRustValue {
168-
value: Box::new(PyList::from(
169-
elements.to_vec().get_slice_items(vm, &subscript)?,
170-
)),
171-
}
172-
} else if sequence.payload::<PyTuple>().is_some() {
173-
PyObjectPayload::AnyRustValue {
174-
value: Box::new(PyTuple::from(
175-
elements.to_vec().get_slice_items(vm, &subscript)?,
176-
)),
177-
}
178-
} else {
179-
panic!("sequence get_item called for non-sequence")
180-
};
165+
if subscript.payload::<PySlice>().is_some() {
166+
let payload = if sequence.payload::<PyList>().is_some() {
167+
PyObjectPayload::AnyRustValue {
168+
value: Box::new(PyList::from(
169+
elements.to_vec().get_slice_items(vm, &subscript)?,
170+
)),
171+
}
172+
} else if sequence.payload::<PyTuple>().is_some() {
173+
PyObjectPayload::AnyRustValue {
174+
value: Box::new(PyTuple::from(
175+
elements.to_vec().get_slice_items(vm, &subscript)?,
176+
)),
177+
}
178+
} else {
179+
panic!("sequence get_item called for non-sequence")
180+
};
181181

182-
Ok(PyObject::new(payload, sequence.typ()))
183-
}
184-
_ => Err(vm.new_type_error(format!(
185-
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",
186-
sequence, subscript
187-
))),
182+
return Ok(PyObject::new(payload, sequence.typ()));
188183
}
184+
185+
Err(vm.new_type_error(format!(
186+
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",
187+
sequence, subscript
188+
)))
189189
}
190190

191191
pub fn seq_equal(

vm/src/obj/objslice.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11
use super::objint;
22
use crate::pyobject::{
3-
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
3+
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult,
4+
TypeProtocol,
45
};
56
use crate::vm::VirtualMachine;
67
use num_bigint::BigInt;
78

9+
#[derive(Debug)]
10+
pub struct PySlice {
11+
// TODO: should be private
12+
pub start: Option<BigInt>,
13+
pub stop: Option<BigInt>,
14+
pub step: Option<BigInt>,
15+
}
16+
17+
impl PyObjectPayload2 for PySlice {
18+
fn required_type(ctx: &PyContext) -> PyObjectRef {
19+
ctx.slice_type()
20+
}
21+
}
22+
823
fn slice_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
924
no_kwargs!(vm, args);
1025
let (cls, start, stop, step): (
@@ -40,10 +55,12 @@ fn slice_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4055
}
4156
}?;
4257
Ok(PyObject::new(
43-
PyObjectPayload::Slice {
44-
start: start.map(|x| objint::get_value(x)),
45-
stop: stop.map(|x| objint::get_value(x)),
46-
step: step.map(|x| objint::get_value(x)),
58+
PyObjectPayload::AnyRustValue {
59+
value: Box::new(PySlice {
60+
start: start.map(|x| objint::get_value(x)),
61+
stop: stop.map(|x| objint::get_value(x)),
62+
step: step.map(|x| objint::get_value(x)),
63+
}),
4764
},
4865
cls.clone(),
4966
))
@@ -59,7 +76,7 @@ fn get_property_value(vm: &mut VirtualMachine, value: &Option<BigInt>) -> PyResu
5976

6077
fn slice_start(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6178
arg_check!(vm, args, required = [(slice, Some(vm.ctx.slice_type()))]);
62-
if let PyObjectPayload::Slice { start, .. } = &slice.payload {
79+
if let Some(PySlice { start, .. }) = &slice.payload() {
6380
get_property_value(vm, start)
6481
} else {
6582
panic!("Slice has incorrect payload.");
@@ -68,7 +85,7 @@ fn slice_start(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6885

6986
fn slice_stop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7087
arg_check!(vm, args, required = [(slice, Some(vm.ctx.slice_type()))]);
71-
if let PyObjectPayload::Slice { stop, .. } = &slice.payload {
88+
if let Some(PySlice { stop, .. }) = &slice.payload() {
7289
get_property_value(vm, stop)
7390
} else {
7491
panic!("Slice has incorrect payload.");
@@ -77,7 +94,7 @@ fn slice_stop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7794

7895
fn slice_step(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7996
arg_check!(vm, args, required = [(slice, Some(vm.ctx.slice_type()))]);
80-
if let PyObjectPayload::Slice { step, .. } = &slice.payload {
97+
if let Some(PySlice { step, .. }) = &slice.payload() {
8198
get_property_value(vm, step)
8299
} else {
83100
panic!("Slice has incorrect payload.");

vm/src/obj/objstr.rs

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
use super::objint;
2-
use super::objsequence::PySliceableSequence;
3-
use super::objtype;
1+
use std::hash::{Hash, Hasher};
2+
use std::ops::Range;
3+
use std::str::FromStr;
4+
5+
use num_traits::ToPrimitive;
6+
use unicode_segmentation::UnicodeSegmentation;
7+
48
use crate::format::{FormatParseError, FormatPart, FormatString};
59
use crate::function::PyRef;
610
use crate::pyobject::{
7-
IntoPyObject, OptionalArg, PyContext, PyFuncArgs, PyIterable, PyObjectPayload,
8-
PyObjectPayload2, PyObjectRef, PyResult, TypeProtocol,
11+
IntoPyObject, OptionalArg, PyContext, PyFuncArgs, PyIterable, PyObjectPayload2, PyObjectRef,
12+
PyResult, TypeProtocol,
913
};
1014
use crate::vm::VirtualMachine;
11-
use num_traits::ToPrimitive;
12-
use std::hash::{Hash, Hasher};
13-
use std::ops::Range;
14-
use std::str::FromStr;
15-
// rust's builtin to_lowercase isn't sufficient for casefold
16-
extern crate caseless;
17-
extern crate unicode_segmentation;
1815

19-
use self::unicode_segmentation::UnicodeSegmentation;
16+
use super::objint;
17+
use super::objsequence::PySliceableSequence;
18+
use super::objslice::PySlice;
19+
use super::objtype;
2020

2121
#[derive(Clone, Debug)]
2222
pub struct PyString {
@@ -867,17 +867,14 @@ pub fn subscript(vm: &mut VirtualMachine, value: &str, b: PyObjectRef) -> PyResu
867867
Err(vm.new_index_error("cannot fit 'int' into an index-sized integer".to_string()))
868868
}
869869
}
870+
} else if b.payload::<PySlice>().is_some() {
871+
let string = value.to_string().get_slice_items(vm, &b)?;
872+
Ok(vm.new_str(string))
870873
} else {
871-
match b.payload {
872-
PyObjectPayload::Slice { .. } => {
873-
let string = value.to_string().get_slice_items(vm, &b)?;
874-
Ok(vm.new_str(string))
875-
}
876-
_ => panic!(
877-
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",
878-
value, b
879-
),
880-
}
874+
panic!(
875+
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",
876+
value, b
877+
)
881878
}
882879
}
883880

vm/src/pyobject.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,20 +1500,8 @@ into_py_native_func_tuple!((a, A), (b, B), (c, C), (d, D), (e, E));
15001500
/// of rust data for a particular python object. Determine the python type
15011501
/// by using for example the `.typ()` method on a python object.
15021502
pub enum PyObjectPayload {
1503-
Slice {
1504-
start: Option<BigInt>,
1505-
stop: Option<BigInt>,
1506-
step: Option<BigInt>,
1507-
},
1508-
MemoryView {
1509-
obj: PyObjectRef,
1510-
},
1511-
WeakRef {
1512-
referent: PyObjectWeakRef,
1513-
},
1514-
AnyRustValue {
1515-
value: Box<dyn std::any::Any>,
1516-
},
1503+
WeakRef { referent: PyObjectWeakRef },
1504+
AnyRustValue { value: Box<dyn std::any::Any> },
15171505
}
15181506

15191507
impl Default for PyObjectPayload {
@@ -1541,9 +1529,7 @@ impl PyObjectPayload2 for PyIteratorValue {
15411529
impl fmt::Debug for PyObjectPayload {
15421530
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15431531
match self {
1544-
PyObjectPayload::MemoryView { ref obj } => write!(f, "bytes/bytearray {:?}", obj),
15451532
PyObjectPayload::WeakRef { .. } => write!(f, "weakref"),
1546-
PyObjectPayload::Slice { .. } => write!(f, "slice"),
15471533
PyObjectPayload::AnyRustValue { value } => value.fmt(f),
15481534
}
15491535
}

0 commit comments

Comments
 (0)