Merge pull request #1655 from youknowone/refactor-tuple

Refactor list, tuple and collections.deque
This commit is contained in:
Jeong YunWon authored and GitHub committed 2020-01-08 11:45:45 +09:00
commit 2473f8a1fe
17 files changed
+520 -513

No files matched your search

+2 -2
View File
@@ -52,9 +52,9 @@ fn main() {
if let Err(err) = res {
if objtype::isinstance(&err, &vm.ctx.exceptions.system_exit) {
let args = err.args();
match args.elements.len() {
match args.as_slice().len() {
0 => return,
1 => match_class!(match args.elements[0].clone() {
1 => match_class!(match args.as_slice()[0].clone() {
i @ PyInt => {
use num_traits::cast::ToPrimitive;
process::exit(i.as_bigint().to_i32().unwrap());
+7
View File
@@ -37,3 +37,10 @@ assert deque(maxlen=3) == deque()
assert deque([1, 2, 3, 4], maxlen=2) == deque([3, 4])
assert len(deque([1, 2, 3, 4])) == 4
assert d >= d
assert not (d > d)
assert d <= d
assert not (d < d)
assert d == d
assert not (d != d)
+7 -7
View File
@@ -275,20 +275,20 @@ fn exception_args_as_string(
varargs: PyTupleRef,
str_single: bool,
) -> Vec<PyStringRef> {
match varargs.elements.len() {
let varargs = varargs.as_slice();
match varargs.len() {
0 => vec![],
1 => {
let args0_repr = if str_single {
vm.to_str(&varargs.elements[0])
vm.to_str(&varargs[0])
.unwrap_or_else(|_| PyString::from("<element str() failed>").into_ref(vm))
} else {
vm.to_repr(&varargs.elements[0])
vm.to_repr(&varargs[0])
.unwrap_or_else(|_| PyString::from("<element repr() failed>").into_ref(vm))
};
vec![args0_repr]
}
_ => varargs
.elements
.iter()
.map(|vararg| {
vm.to_repr(vararg)
@@ -362,8 +362,8 @@ impl ExceptionCtor {
(Self::Class(cls), _) => {
let args = match_class!(match value {
PyNone => vec![],
tup @ PyTuple => tup.elements.clone(),
exc @ PyBaseException => exc.args().elements.clone(),
tup @ PyTuple => tup.as_slice().to_vec(),
exc @ PyBaseException => exc.args().as_slice().to_vec(),
obj => vec![obj],
});
invoke(cls, args, vm)
@@ -609,7 +609,7 @@ fn make_arg_getter(idx: usize) -> impl Fn(PyBaseExceptionRef, &VirtualMachine) -
move |exc, vm| {
exc.args
.borrow()
.elements
.as_slice()
.get(idx)
.cloned()
.unwrap_or_else(|| vm.get_none())
+1 -1
View File
@@ -583,7 +583,7 @@ pub fn single_or_tuple_any<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>>(
match_class!(match obj {
obj @ T => (self.predicate)(obj),
tuple @ PyTuple => {
for obj in tuple.elements.iter() {
for obj in tuple.as_slice().iter() {
if self.check(obj.clone())? {
return Ok(true);
}
+1
View File
@@ -64,6 +64,7 @@ pub mod py_serde;
mod pyhash;
pub mod pyobject;
pub mod scope;
mod sequence;
pub mod stdlib;
mod sysmodule;
pub mod types;
+3 -3
View File
@@ -11,7 +11,7 @@ use super::objint::{self, PyInt, PyIntRef};
use super::objlist::PyList;
use super::objmemory::PyMemoryView;
use super::objnone::PyNoneRef;
use super::objsequence::{self, is_valid_slice_arg, PySliceableSequence};
use super::objsequence::{is_valid_slice_arg, PySliceableSequence};
use super::objslice::PySliceRef;
use super::objstr::{self, PyString, PyStringRef};
use super::objtuple::PyTupleRef;
@@ -859,8 +859,8 @@ impl PyByteInner {
Either::A(byte) => byte.elements,
Either::B(tuple) => {
let mut flatten = vec![];
for v in objsequence::get_elements_tuple(tuple.as_object()).to_vec() {
flatten.extend(PyByteInner::try_from_object(vm, v)?.elements)
for v in tuple.as_slice() {
flatten.extend(PyByteInner::try_from_object(vm, v.clone())?.elements)
}
flatten
}
+1 -1
View File
@@ -76,7 +76,7 @@ pub fn new_stop_iteration(vm: &VirtualMachine) -> PyBaseExceptionRef {
pub fn stop_iter_value(vm: &VirtualMachine, exc: &PyBaseExceptionRef) -> PyResult {
let args = exc.args();
let val = args
.elements
.as_slice()
.first()
.cloned()
.unwrap_or_else(|| vm.get_none());
+174 -183
View File
@@ -10,22 +10,25 @@ use super::objbool;
use super::objbyteinner;
use super::objint::PyIntRef;
use super::objiter;
use super::objsequence::{
get_elements_list, get_item, seq_equal, seq_ge, seq_gt, seq_le, seq_lt, seq_mul, SequenceIndex,
};
use super::objsequence::{get_item, SequenceIndex};
use super::objslice::PySliceRef;
use super::objtype::{self, PyClassRef};
use super::objtype::PyClassRef;
use crate::function::OptionalArg;
use crate::pyobject::{
IdProtocol, PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue,
TryFromObject, TypeProtocol,
IdProtocol, PyArithmaticValue::*, PyClassImpl, PyComparisonValue, PyContext, PyIterable,
PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
};
use crate::sequence::{self, SimpleSeq};
use crate::vm::{ReprGuard, VirtualMachine};
/// Built-in mutable sequence.
///
/// If no argument is given, the constructor creates a new empty list.
/// The argument must be an iterable if specified.
#[pyclass]
#[derive(Default)]
pub struct PyList {
// TODO: shouldn't be public
pub elements: RefCell<Vec<PyObjectRef>>,
elements: RefCell<Vec<PyObjectRef>>,
}
impl fmt::Debug for PyList {
@@ -50,11 +53,21 @@ impl PyValue for PyList {
}
impl PyList {
pub fn get_len(&self) -> usize {
pub fn borrow_sequence<'a>(&'a self) -> impl SimpleSeq + 'a {
self.elements.borrow()
}
pub fn borrow_elements<'a>(&'a self) -> impl std::ops::Deref<Target = Vec<PyObjectRef>> + 'a {
self.elements.borrow()
}
}
impl PyList {
fn get_len(&self) -> usize {
self.elements.borrow().len()
}
pub fn get_pos(&self, p: i32) -> Option<usize> {
fn get_pos(&self, p: i32) -> Option<usize> {
// convert a (potentially negative) positon into a real index
if p < 0 {
if -p as usize > self.get_len() {
@@ -69,7 +82,7 @@ impl PyList {
}
}
pub fn get_slice_pos(&self, slice_pos: &BigInt) -> usize {
fn get_slice_pos(&self, slice_pos: &BigInt) -> usize {
if let Some(pos) = slice_pos.to_i32() {
if let Some(index) = self.get_pos(pos) {
// within bounds
@@ -86,7 +99,7 @@ impl PyList {
}
}
pub fn get_slice_range(&self, start: &Option<BigInt>, stop: &Option<BigInt>) -> Range<usize> {
fn get_slice_range(&self, start: &Option<BigInt>, stop: &Option<BigInt>) -> Range<usize> {
let start = start.as_ref().map(|x| self.get_slice_pos(x)).unwrap_or(0);
let stop = stop
.as_ref()
@@ -96,7 +109,10 @@ impl PyList {
start..stop
}
pub fn get_byte_inner(&self, vm: &VirtualMachine) -> PyResult<objbyteinner::PyByteInner> {
pub(crate) fn get_byte_inner(
&self,
vm: &VirtualMachine,
) -> PyResult<objbyteinner::PyByteInner> {
let mut elements = Vec::<u8>::with_capacity(self.get_len());
for elem in self.elements.borrow().iter() {
match PyIntRef::try_from_object(vm, elem.clone()) {
@@ -130,18 +146,22 @@ struct SortOptions {
pub type PyListRef = PyRef<PyList>;
impl PyListRef {
pub fn append(self, x: PyObjectRef, _vm: &VirtualMachine) {
#[pyimpl]
impl PyList {
#[pymethod]
pub(crate) fn append(&self, x: PyObjectRef, _vm: &VirtualMachine) {
self.elements.borrow_mut().push(x);
}
fn extend(self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
#[pymethod]
fn extend(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let mut new_elements = vm.extract_elements(&x)?;
self.elements.borrow_mut().append(&mut new_elements);
Ok(())
}
fn insert(self, position: isize, element: PyObjectRef, _vm: &VirtualMachine) {
#[pymethod]
fn insert(&self, position: isize, element: PyObjectRef, _vm: &VirtualMachine) {
let mut vec = self.elements.borrow_mut();
let vec_len = vec.len().to_isize().unwrap();
// This unbounded position can be < 0 or > vec.len()
@@ -155,76 +175,93 @@ impl PyListRef {
vec.insert(position, element.clone());
}
fn add(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.list_type()) {
let e1 = self.elements.borrow();
let e2 = get_elements_list(&other);
#[pymethod(name = "__add__")]
fn add(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if let Some(other) = other.payload_if_subclass::<PyList>(vm) {
let e1 = self.borrow_sequence();
let e2 = other.borrow_sequence();
let elements = e1.iter().chain(e2.iter()).cloned().collect();
Ok(vm.ctx.new_list(elements))
} else {
Err(vm.new_type_error(format!("Cannot add {} and {}", self.as_object(), other)))
Err(vm.new_type_error(format!(
"Cannot add {} and {}",
Self::class(vm).name,
other.class().name
)))
}
}
fn iadd(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
#[pymethod(name = "__iadd__")]
fn iadd(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if let Ok(new_elements) = vm.extract_elements(&other) {
let mut e = new_elements;
self.elements.borrow_mut().append(&mut e);
Ok(self.into_object())
zelf.elements.borrow_mut().append(&mut e);
Ok(zelf.into_object())
} else {
Ok(vm.ctx.not_implemented())
}
}
fn bool(self, _vm: &VirtualMachine) -> bool {
#[pymethod(name = "__bool__")]
fn bool(&self, _vm: &VirtualMachine) -> bool {
!self.elements.borrow().is_empty()
}
fn clear(self, _vm: &VirtualMachine) {
#[pymethod]
fn clear(&self, _vm: &VirtualMachine) {
self.elements.borrow_mut().clear();
}
fn copy(self, vm: &VirtualMachine) -> PyObjectRef {
#[pymethod]
fn copy(&self, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.new_list(self.elements.borrow().clone())
}
fn len(self, _vm: &VirtualMachine) -> usize {
#[pymethod(name = "__len__")]
fn len(&self, _vm: &VirtualMachine) -> usize {
self.elements.borrow().len()
}
fn sizeof(self, _vm: &VirtualMachine) -> usize {
#[pymethod(name = "__sizeof__")]
fn sizeof(&self, _vm: &VirtualMachine) -> usize {
size_of::<Self>() + self.elements.borrow().capacity() * size_of::<PyObjectRef>()
}
fn reverse(self, _vm: &VirtualMachine) {
#[pymethod]
fn reverse(&self, _vm: &VirtualMachine) {
self.elements.borrow_mut().reverse();
}
fn reversed(self, _vm: &VirtualMachine) -> PyListReverseIterator {
let final_position = self.elements.borrow().len();
#[pymethod(name = "__reversed__")]
fn reversed(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyListReverseIterator {
let final_position = zelf.elements.borrow().len();
PyListReverseIterator {
position: Cell::new(final_position),
list: self,
list: zelf,
}
}
fn getitem(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
#[pymethod(name = "__getitem__")]
fn getitem(zelf: PyRef<Self>, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
get_item(
vm,
self.as_object(),
&self.elements.borrow(),
zelf.as_object(),
&zelf.elements.borrow(),
needle.clone(),
)
}
fn iter(self, _vm: &VirtualMachine) -> PyListIterator {
#[pymethod(name = "__iter__")]
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyListIterator {
PyListIterator {
position: Cell::new(0),
list: self,
list: zelf,
}
}
#[pymethod(name = "__setitem__")]
fn setitem(
self,
&self,
subscript: SequenceIndex,
value: PyObjectRef,
vm: &VirtualMachine,
@@ -240,7 +277,7 @@ impl PyListRef {
}
}
fn setindex(self, index: i32, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn setindex(&self, index: i32, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if let Some(pos_index) = self.get_pos(index) {
self.elements.borrow_mut()[pos_index] = value;
Ok(vm.get_none())
@@ -249,7 +286,7 @@ impl PyListRef {
}
}
fn setslice(self, slice: PySliceRef, sec: PyIterable, vm: &VirtualMachine) -> PyResult {
fn setslice(&self, slice: PySliceRef, sec: PyIterable, vm: &VirtualMachine) -> PyResult {
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
if step.is_zero() {
@@ -303,7 +340,7 @@ impl PyListRef {
}
}
fn _set_slice(self, range: Range<usize>, sec: PyIterable, vm: &VirtualMachine) -> PyResult {
fn _set_slice(&self, range: Range<usize>, sec: PyIterable, vm: &VirtualMachine) -> PyResult {
// consume the iter, we need it's size
// and if it's going to fail we want that to happen *before* we start modifing
let items: Result<Vec<PyObjectRef>, _> = sec.iter(vm)?.collect();
@@ -316,7 +353,7 @@ impl PyListRef {
}
fn _set_stepped_slice(
self,
&self,
range: Range<usize>,
step: usize,
sec: PyIterable,
@@ -358,7 +395,7 @@ impl PyListRef {
}
fn _set_stepped_slice_reverse(
self,
&self,
range: Range<usize>,
step: usize,
sec: PyIterable,
@@ -400,7 +437,7 @@ impl PyListRef {
}
}
fn _replace_indexes<I>(self, indexes: I, items: &[PyObjectRef])
fn _replace_indexes<I>(&self, indexes: I, items: &[PyObjectRef])
where
I: Iterator<Item = usize>,
{
@@ -412,10 +449,11 @@ impl PyListRef {
}
}
fn repr(self, vm: &VirtualMachine) -> PyResult<String> {
let s = if let Some(_guard) = ReprGuard::enter(self.as_object()) {
let mut str_parts = Vec::with_capacity(self.elements.borrow().len());
for elem in self.elements.borrow().iter() {
#[pymethod(name = "__repr__")]
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<String> {
let s = if let Some(_guard) = ReprGuard::enter(zelf.as_object()) {
let mut str_parts = Vec::with_capacity(zelf.elements.borrow().len());
for elem in zelf.elements.borrow().iter() {
let s = vm.to_repr(elem)?;
str_parts.push(s.as_str().to_string());
}
@@ -426,30 +464,35 @@ impl PyListRef {
Ok(s)
}
fn hash(self, vm: &VirtualMachine) -> PyResult<()> {
#[pymethod(name = "__hash__")]
fn hash(&self, vm: &VirtualMachine) -> PyResult<()> {
Err(vm.new_type_error("unhashable type".to_string()))
}
fn mul(self, counter: isize, vm: &VirtualMachine) -> PyObjectRef {
let new_elements = seq_mul(&self.elements.borrow().as_slice(), counter)
#[pymethod(name = "__mul__")]
fn mul(&self, counter: isize, vm: &VirtualMachine) -> PyObjectRef {
let new_elements = sequence::seq_mul(&self.borrow_sequence(), counter)
.cloned()
.collect();
vm.ctx.new_list(new_elements)
}
fn rmul(self, counter: isize, vm: &VirtualMachine) -> PyObjectRef {
#[pymethod(name = "__rmul__")]
fn rmul(&self, counter: isize, vm: &VirtualMachine) -> PyObjectRef {
self.mul(counter, &vm)
}
fn imul(self, counter: isize, _vm: &VirtualMachine) -> Self {
let new_elements = seq_mul(&self.elements.borrow().as_slice(), counter)
#[pymethod(name = "__imul__")]
fn imul(zelf: PyRef<Self>, counter: isize, _vm: &VirtualMachine) -> PyRef<Self> {
let new_elements = sequence::seq_mul(&zelf.borrow_sequence(), counter)
.cloned()
.collect();
self.elements.replace(new_elements);
self
zelf.elements.replace(new_elements);
zelf
}
fn count(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
#[pymethod]
fn count(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
let mut count: usize = 0;
for element in self.elements.borrow().iter() {
if vm.identical_or_equal(element, &needle)? {
@@ -459,7 +502,8 @@ impl PyListRef {
Ok(count)
}
fn contains(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
#[pymethod(name = "__contains__")]
fn contains(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
for element in self.elements.borrow().iter() {
if vm.identical_or_equal(element, &needle)? {
return Ok(true);
@@ -469,7 +513,8 @@ impl PyListRef {
Ok(false)
}
fn index(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
#[pymethod]
fn index(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
for (index, element) in self.elements.borrow().iter().enumerate() {
if vm.identical_or_equal(element, &needle)? {
return Ok(index);
@@ -479,7 +524,8 @@ impl PyListRef {
Err(vm.new_value_error(format!("'{}' is not in list", needle_str.as_str())))
}
fn pop(self, i: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
#[pymethod]
fn pop(&self, i: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
let mut i = i.into_option().unwrap_or(-1);
let mut elements = self.elements.borrow_mut();
if i < 0 {
@@ -494,7 +540,8 @@ impl PyListRef {
}
}
fn remove(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
#[pymethod]
fn remove(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let mut ri: Option<usize> = None;
for (index, element) in self.elements.borrow().iter().enumerate() {
if vm.identical_or_equal(element, &needle)? {
@@ -512,86 +559,70 @@ impl PyListRef {
}
}
fn eq(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let value = if self.as_object().is(&other) {
vm.new_bool(true)
} else if objtype::isinstance(&other, &vm.ctx.list_type()) {
vm.new_bool(self.inner_eq(&other, vm)?)
#[inline]
fn cmp<F>(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyResult<PyComparisonValue>
where
F: Fn(&Vec<PyObjectRef>, &Vec<PyObjectRef>) -> PyResult<bool>,
{
let r = if let Some(other) = other.payload_if_subclass::<PyList>(vm) {
Implemented(op(&*self.borrow_elements(), &*other.borrow_elements())?)
} else {
vm.ctx.not_implemented()
NotImplemented
};
Ok(value)
Ok(r)
}
fn ne(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let value = if self.as_object().is(&other) {
vm.new_bool(false)
} else if objtype::isinstance(&other, &vm.ctx.list_type()) {
vm.new_bool(!self.inner_eq(&other, vm)?)
#[pymethod(name = "__eq__")]
fn eq(
zelf: PyRef<Self>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
if zelf.as_object().is(&other) {
Ok(Implemented(true))
} else {
vm.ctx.not_implemented()
};
Ok(value)
}
fn inner_eq(self, other: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
let zelf = self.elements.borrow();
let other = get_elements_list(other);
seq_equal(vm, &zelf.as_slice(), &other.as_slice())
}
fn lt(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.list_type()) {
let zelf = self.elements.borrow();
let other = get_elements_list(&other);
let res = seq_lt(vm, &zelf.as_slice(), &other.as_slice())?;
Ok(vm.new_bool(res))
} else {
Ok(vm.ctx.not_implemented())
zelf.cmp(other, |a, b| sequence::eq(vm, a, b), vm)
}
}
fn gt(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.list_type()) {
let zelf = self.elements.borrow();
let other = get_elements_list(&other);
let res = seq_gt(vm, &zelf.as_slice(), &other.as_slice())?;
Ok(vm.new_bool(res))
} else {
Ok(vm.ctx.not_implemented())
}
#[pymethod(name = "__ne__")]
fn ne(
zelf: PyRef<Self>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
Ok(PyList::eq(zelf, other, vm)?.map(|v| !v))
}
fn ge(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.list_type()) {
let zelf = self.elements.borrow();
let other = get_elements_list(&other);
let res = seq_ge(vm, &zelf.as_slice(), &other.as_slice())?;
Ok(vm.new_bool(res))
} else {
Ok(vm.ctx.not_implemented())
}
#[pymethod(name = "__lt__")]
fn lt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
self.cmp(other, |a, b| sequence::lt(vm, a, b), vm)
}
fn le(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.list_type()) {
let zelf = self.elements.borrow();
let other = get_elements_list(&other);
let res = seq_le(vm, &zelf.as_slice(), &other.as_slice())?;
Ok(vm.new_bool(res))
} else {
Ok(vm.ctx.not_implemented())
}
#[pymethod(name = "__gt__")]
fn gt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
self.cmp(other, |a, b| sequence::gt(vm, a, b), vm)
}
fn delitem(self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult<()> {
#[pymethod(name = "__ge__")]
fn ge(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
self.cmp(other, |a, b| sequence::ge(vm, a, b), vm)
}
#[pymethod(name = "__le__")]
fn le(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
self.cmp(other, |a, b| sequence::le(vm, a, b), vm)
}
#[pymethod(name = "__delitem__")]
fn delitem(&self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult<()> {
match subscript {
SequenceIndex::Int(index) => self.delindex(index, vm),
SequenceIndex::Slice(slice) => self.delslice(slice, vm),
}
}
fn delindex(self, index: i32, vm: &VirtualMachine) -> PyResult<()> {
fn delindex(&self, index: i32, vm: &VirtualMachine) -> PyResult<()> {
if let Some(pos_index) = self.get_pos(index) {
self.elements.borrow_mut().remove(pos_index);
Ok(())
@@ -600,7 +631,7 @@ impl PyListRef {
}
}
fn delslice(self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
fn delslice(&self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
let start = slice.start_index(vm)?;
let stop = slice.stop_index(vm)?;
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
@@ -669,11 +700,11 @@ impl PyListRef {
}
}
fn _del_slice(self, range: Range<usize>) {
fn _del_slice(&self, range: Range<usize>) {
self.elements.borrow_mut().drain(range);
}
fn _del_stepped_slice(self, range: Range<usize>, step: usize) {
fn _del_stepped_slice(&self, range: Range<usize>, step: usize) {
// no easy way to delete stepped indexes so here is what we'll do
let mut deleted = 0;
let mut elements = self.elements.borrow_mut();
@@ -694,7 +725,7 @@ impl PyListRef {
elements.drain((range.end - deleted)..range.end);
}
fn _del_stepped_slice_reverse(self, range: Range<usize>, step: usize) {
fn _del_stepped_slice_reverse(&self, range: Range<usize>, step: usize) {
// no easy way to delete stepped indexes so here is what we'll do
let mut deleted = 0;
let mut elements = self.elements.borrow_mut();
@@ -715,7 +746,8 @@ impl PyListRef {
elements.drain(range.start..(range.start + deleted));
}
fn sort(self, options: SortOptions, vm: &VirtualMachine) -> PyResult<()> {
#[pymethod]
fn sort(&self, options: SortOptions, vm: &VirtualMachine) -> PyResult<()> {
// replace list contents with [] for duration of sort.
// this prevents keyfunc from messing with the list and makes it easy to
// check if it tries to append elements to it.
@@ -729,20 +761,21 @@ impl PyListRef {
Ok(())
}
}
fn list_new(
cls: PyClassRef,
iterable: OptionalArg<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<PyListRef> {
let elements = if let OptionalArg::Present(iterable) = iterable {
vm.extract_elements(&iterable)?
} else {
vec![]
};
#[pyslot(new)]
fn list_new(
cls: PyClassRef,
iterable: OptionalArg<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<PyListRef> {
let elements = if let OptionalArg::Present(iterable) = iterable {
vm.extract_elements(&iterable)?
} else {
vec![]
};
PyList::from(elements).into_ref_with_type(vm, cls)
PyList::from(elements).into_ref_with_type(vm, cls)
}
}
fn quicksort(
@@ -875,51 +908,9 @@ impl PyListReverseIterator {
}
}
#[rustfmt::skip] // to avoid line splitting
pub fn init(context: &PyContext) {
let list_type = &context.types.list_type;
let list_doc = "Built-in mutable sequence.\n\n\
If no argument is given, the constructor creates a new empty list.\n\
The argument must be an iterable if specified.";
extend_class!(context, list_type, {
"__sizeof__" => context.new_rustfunc(PyListRef::sizeof),
"__add__" => context.new_rustfunc(PyListRef::add),
"__iadd__" => context.new_rustfunc(PyListRef::iadd),
"__bool__" => context.new_rustfunc(PyListRef::bool),
"__contains__" => context.new_rustfunc(PyListRef::contains),
"__delitem__" => context.new_rustfunc(PyListRef::delitem),
"__eq__" => context.new_rustfunc(PyListRef::eq),
"__ne__" => context.new_rustfunc(PyListRef::ne),
"__lt__" => context.new_rustfunc(PyListRef::lt),
"__gt__" => context.new_rustfunc(PyListRef::gt),
"__le__" => context.new_rustfunc(PyListRef::le),
"__ge__" => context.new_rustfunc(PyListRef::ge),
"__getitem__" => context.new_rustfunc(PyListRef::getitem),
"__iter__" => context.new_rustfunc(PyListRef::iter),
"__setitem__" => context.new_rustfunc(PyListRef::setitem),
"__reversed__" => context.new_rustfunc(PyListRef::reversed),
"__mul__" => context.new_rustfunc(PyListRef::mul),
"__rmul__" => context.new_rustfunc(PyListRef::rmul),
"__imul__" => context.new_rustfunc(PyListRef::imul),
"__len__" => context.new_rustfunc(PyListRef::len),
(slot new) => list_new,
"__repr__" => context.new_rustfunc(PyListRef::repr),
"__hash__" => context.new_rustfunc(PyListRef::hash),
"__doc__" => context.new_str(list_doc.to_string()),
"append" => context.new_rustfunc(PyListRef::append),
"clear" => context.new_rustfunc(PyListRef::clear),
"copy" => context.new_rustfunc(PyListRef::copy),
"count" => context.new_rustfunc(PyListRef::count),
"extend" => context.new_rustfunc(PyListRef::extend),
"index" => context.new_rustfunc(PyListRef::index),
"insert" => context.new_rustfunc(PyListRef::insert),
"reverse" => context.new_rustfunc(PyListRef::reverse),
"sort" => context.new_rustfunc(PyListRef::sort),
"pop" => context.new_rustfunc(PyListRef::pop),
"remove" => context.new_rustfunc(PyListRef::remove)
});
PyList::extend_class(context, list_type);
PyListIterator::extend_class(context, &context.types.listiterator_type);
PyListReverseIterator::extend_class(context, &context.types.listreverseiterator_type);
+2 -157
View File
@@ -1,6 +1,5 @@
use std::cell::RefCell;
use std::marker::Sized;
use std::ops::{Deref, DerefMut, Range};
use std::ops::Range;
use num_bigint::{BigInt, ToBigInt};
use num_traits::{One, Signed, ToPrimitive, Zero};
@@ -11,7 +10,7 @@ use super::objnone::PyNone;
use super::objslice::{PySlice, PySliceRef};
use super::objtuple::PyTuple;
use crate::function::OptionalArg;
use crate::pyobject::{IdProtocol, PyObject, PyObjectRef, PyResult, TryFromObject, TypeProtocol};
use crate::pyobject::{PyObject, PyObjectRef, PyResult, TryFromObject, TypeProtocol};
use crate::vm::VirtualMachine;
pub trait PySliceableSequence {
@@ -247,160 +246,6 @@ pub fn get_item(
}
}
type DynPyIter<'a> = Box<dyn ExactSizeIterator<Item = &'a PyObjectRef> + 'a>;
#[allow(clippy::len_without_is_empty)]
pub trait SimpleSeq {
fn len(&self) -> usize;
fn iter(&self) -> DynPyIter;
}
impl SimpleSeq for &[PyObjectRef] {
fn len(&self) -> usize {
(&**self).len()
}
fn iter(&self) -> DynPyIter {
Box::new((&**self).iter())
}
}
impl SimpleSeq for std::collections::VecDeque<PyObjectRef> {
fn len(&self) -> usize {
self.len()
}
fn iter(&self) -> DynPyIter {
Box::new(self.iter())
}
}
// impl<'a, I>
pub fn seq_equal(
vm: &VirtualMachine,
zelf: &dyn SimpleSeq,
other: &dyn SimpleSeq,
) -> PyResult<bool> {
if zelf.len() == other.len() {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if a.is(b) {
continue;
}
if !vm.bool_eq(a.clone(), b.clone())? {
return Ok(false);
}
}
Ok(true)
} else {
Ok(false)
}
}
pub fn seq_lt(vm: &VirtualMachine, zelf: &dyn SimpleSeq, other: &dyn SimpleSeq) -> PyResult<bool> {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if let Some(v) = vm.bool_seq_lt(a.clone(), b.clone())? {
return Ok(v);
}
}
Ok(zelf.len() < other.len())
}
pub fn seq_gt(vm: &VirtualMachine, zelf: &dyn SimpleSeq, other: &dyn SimpleSeq) -> PyResult<bool> {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if let Some(v) = vm.bool_seq_gt(a.clone(), b.clone())? {
return Ok(v);
}
}
Ok(zelf.len() > other.len())
}
pub fn seq_ge(vm: &VirtualMachine, zelf: &dyn SimpleSeq, other: &dyn SimpleSeq) -> PyResult<bool> {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if let Some(v) = vm.bool_seq_gt(a.clone(), b.clone())? {
return Ok(v);
}
}
Ok(zelf.len() >= other.len())
}
pub fn seq_le(vm: &VirtualMachine, zelf: &dyn SimpleSeq, other: &dyn SimpleSeq) -> PyResult<bool> {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if let Some(v) = vm.bool_seq_lt(a.clone(), b.clone())? {
return Ok(v);
}
}
Ok(zelf.len() <= other.len())
}
pub struct SeqMul<'a> {
seq: &'a dyn SimpleSeq,
repetitions: usize,
iter: Option<DynPyIter<'a>>,
}
impl<'a> Iterator for SeqMul<'a> {
type Item = &'a PyObjectRef;
fn next(&mut self) -> Option<Self::Item> {
if self.seq.len() == 0 {
return None;
}
match self.iter.as_mut().and_then(Iterator::next) {
Some(item) => Some(item),
None => {
if self.repetitions == 0 {
None
} else {
self.repetitions -= 1;
self.iter = Some(self.seq.iter());
self.next()
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.iter.as_ref().map_or(0, ExactSizeIterator::len)
+ (self.repetitions * self.seq.len());
(size, Some(size))
}
}
impl ExactSizeIterator for SeqMul<'_> {}
pub fn seq_mul(seq: &dyn SimpleSeq, repetitions: isize) -> SeqMul {
SeqMul {
seq,
repetitions: repetitions.max(0) as usize,
iter: None,
}
}
pub fn get_elements_cell<'a>(obj: &'a PyObjectRef) -> &'a RefCell<Vec<PyObjectRef>> {
if let Some(list) = obj.payload::<PyList>() {
return &list.elements;
}
panic!("Cannot extract elements from non-sequence");
}
pub fn get_elements_list<'a>(obj: &'a PyObjectRef) -> impl Deref<Target = Vec<PyObjectRef>> + 'a {
if let Some(list) = obj.payload::<PyList>() {
return list.elements.borrow();
}
panic!("Cannot extract elements from non-sequence");
}
pub fn get_elements_tuple<'a>(obj: &'a PyObjectRef) -> impl Deref<Target = Vec<PyObjectRef>> + 'a {
if let Some(tuple) = obj.payload::<PyTuple>() {
return &tuple.elements;
}
panic!("Cannot extract elements from non-sequence");
}
pub fn get_mut_elements<'a>(obj: &'a PyObjectRef) -> impl DerefMut<Target = Vec<PyObjectRef>> + 'a {
if let Some(list) = obj.payload::<PyList>() {
return list.elements.borrow_mut();
}
panic!("Cannot extract elements from non-sequence");
}
//Check if given arg could be used with PySliceableSequence.get_slice_range()
pub fn is_valid_slice_arg(
arg: OptionalArg<PyObjectRef>,
+5 -7
View File
@@ -1472,8 +1472,10 @@ pub fn do_cformat_string(
call_getitem(vm, &values, &vm.ctx.new_str(key.to_string()))?
}
None => {
let mut elements =
objtuple::get_value(&values).into_iter().skip(tuple_index);
let mut elements = objtuple::get_value(&values)
.to_vec()
.into_iter()
.skip(tuple_index);
tuple_index = try_update_quantity_from_tuple(
vm,
@@ -1507,11 +1509,7 @@ pub fn do_cformat_string(
}
// check that all arguments were converted
if (!mapping_required
&& objtuple::get_value(&values)
.into_iter()
.nth(tuple_index)
.is_some())
if (!mapping_required && objtuple::get_value(&values).get(tuple_index).is_some())
&& !objtype::isinstance(&values_obj, &vm.ctx.types.dict_type)
{
return Err(
+48 -66
View File
@@ -2,15 +2,15 @@ use std::cell::Cell;
use std::fmt;
use super::objiter;
use super::objsequence::{
get_elements_tuple, get_item, seq_equal, seq_ge, seq_gt, seq_le, seq_lt, seq_mul,
};
use super::objtype::{self, PyClassRef};
use super::objsequence::get_item;
use super::objtype::PyClassRef;
use crate::function::OptionalArg;
use crate::pyhash;
use crate::pyobject::{
IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
IntoPyObject, PyArithmaticValue::*, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef,
PyRef, PyResult, PyValue,
};
use crate::sequence::{self, SimpleSeq};
use crate::vm::{ReprGuard, VirtualMachine};
/// tuple() -> empty tuple
@@ -19,8 +19,7 @@ use crate::vm::{ReprGuard, VirtualMachine};
/// If the argument is a tuple, the return value is the same object.
#[pyclass]
pub struct PyTuple {
// TODO: shouldn't be public
pub elements: Vec<PyObjectRef>,
elements: Vec<PyObjectRef>,
}
impl fmt::Debug for PyTuple {
@@ -61,68 +60,65 @@ impl_intopyobj_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5));
impl_intopyobj_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6));
impl PyTuple {
pub fn fast_getitem(&self, idx: usize) -> PyObjectRef {
pub(crate) fn fast_getitem(&self, idx: usize) -> PyObjectRef {
self.elements[idx].clone()
}
pub fn as_slice(&self) -> &[PyObjectRef] {
&self.elements
}
}
pub type PyTupleRef = PyRef<PyTuple>;
pub fn get_value(obj: &PyObjectRef) -> Vec<PyObjectRef> {
obj.payload::<PyTuple>().unwrap().elements.clone()
pub(crate) fn get_value(obj: &PyObjectRef) -> &[PyObjectRef] {
obj.payload::<PyTuple>().unwrap().as_slice()
}
#[pyimpl]
impl PyTuple {
#[pymethod(name = "__lt__")]
fn lt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.tuple_type()) {
let other = get_elements_tuple(&other);
let res = seq_lt(vm, &self.elements.as_slice(), &other.as_slice())?;
Ok(vm.new_bool(res))
#[inline]
fn cmp<F>(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyResult<PyComparisonValue>
where
F: Fn(&Vec<PyObjectRef>, &Vec<PyObjectRef>) -> PyResult<bool>,
{
let r = if let Some(other) = other.payload_if_subclass::<PyTuple>(vm) {
Implemented(op(&self.elements, &other.elements)?)
} else {
Ok(vm.ctx.not_implemented())
}
NotImplemented
};
Ok(r)
}
#[pymethod(name = "__lt__")]
fn lt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
self.cmp(other, |a, b| sequence::lt(vm, a, b), vm)
}
#[pymethod(name = "__gt__")]
fn gt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.tuple_type()) {
let other = get_elements_tuple(&other);
let res = seq_gt(vm, &self.elements.as_slice(), &other.as_slice())?;
Ok(vm.new_bool(res))
} else {
Ok(vm.ctx.not_implemented())
}
fn gt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
self.cmp(other, |a, b| sequence::gt(vm, a, b), vm)
}
#[pymethod(name = "__ge__")]
fn ge(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.tuple_type()) {
let other = get_elements_tuple(&other);
let res = seq_ge(vm, &self.elements.as_slice(), &other.as_slice())?;
Ok(vm.new_bool(res))
} else {
Ok(vm.ctx.not_implemented())
}
fn ge(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
self.cmp(other, |a, b| sequence::ge(vm, a, b), vm)
}
#[pymethod(name = "__le__")]
fn le(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.tuple_type()) {
let other = get_elements_tuple(&other);
let res = seq_le(vm, &self.elements.as_slice(), &other.as_slice())?;
Ok(vm.new_bool(res))
} else {
Ok(vm.ctx.not_implemented())
}
fn le(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
self.cmp(other, |a, b| sequence::le(vm, a, b), vm)
}
#[pymethod(name = "__add__")]
fn add(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.tuple_type()) {
let e2 = get_elements_tuple(&other);
let elements = self.elements.iter().chain(e2.iter()).cloned().collect();
if let Some(other) = other.payload_if_subclass::<PyTuple>(vm) {
let elements = self
.elements
.iter()
.chain(other.as_slice().iter())
.cloned()
.collect();
Ok(vm.ctx.new_tuple(elements))
} else {
Ok(vm.ctx.not_implemented())
@@ -146,26 +142,13 @@ impl PyTuple {
}
#[pymethod(name = "__eq__")]
fn eq(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.tuple_type()) {
Ok(vm.new_bool(self.inner_eq(&other, vm)?))
} else {
Ok(vm.ctx.not_implemented())
}
fn eq(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
self.cmp(other, |a, b| sequence::eq(vm, a, b), vm)
}
#[pymethod(name = "__ne__")]
fn ne(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.tuple_type()) {
Ok(vm.new_bool(!self.inner_eq(&other, vm)?))
} else {
Ok(vm.ctx.not_implemented())
}
}
fn inner_eq(&self, other: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
let other = get_elements_tuple(other);
seq_equal(vm, &self.elements.as_slice(), &other.as_slice())
fn ne(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
Ok(self.eq(other, vm)?.map(|v| !v))
}
#[pymethod(name = "__hash__")]
@@ -208,7 +191,7 @@ impl PyTuple {
#[pymethod(name = "__mul__")]
fn mul(&self, counter: isize, vm: &VirtualMachine) -> PyObjectRef {
let new_elements = seq_mul(&self.elements.as_slice(), counter)
let new_elements = sequence::seq_mul(&self.elements, counter)
.cloned()
.collect();
vm.ctx.new_tuple(new_elements)
@@ -277,8 +260,8 @@ impl PyValue for PyTupleIterator {
impl PyTupleIterator {
#[pymethod(name = "__next__")]
fn next(&self, vm: &VirtualMachine) -> PyResult {
if self.position.get() < self.tuple.elements.len() {
let ret = self.tuple.elements[self.position.get()].clone();
if self.position.get() < self.tuple.as_slice().len() {
let ret = self.tuple.as_slice()[self.position.get()].clone();
self.position.set(self.position.get() + 1);
Ok(ret)
} else {
@@ -292,7 +275,6 @@ impl PyTupleIterator {
}
}
#[rustfmt::skip] // to avoid line splitting
pub fn init(context: &PyContext) {
let tuple_type = &context.types.tuple_type;
PyTuple::extend_class(context, tuple_type);
+9 -8
View File
@@ -4,7 +4,10 @@ use serde;
use serde::de::{DeserializeSeed, Visitor};
use serde::ser::{Serialize, SerializeMap, SerializeSeq};
use crate::obj::{objbool, objdict::PyDictRef, objfloat, objint, objsequence, objstr, objtype};
use crate::obj::{
objbool, objdict::PyDictRef, objfloat, objint, objlist::PyList, objstr, objtuple::PyTuple,
objtype,
};
use crate::pyobject::{IdProtocol, ItemProtocol, PyObjectRef, TypeProtocol};
use crate::VirtualMachine;
use num_traits::cast::ToPrimitive;
@@ -59,7 +62,7 @@ impl<'s> serde::Serialize for PyObjectSerializer<'s> {
S: serde::Serializer,
{
let serialize_seq_elements =
|serializer: S, elements: &Vec<PyObjectRef>| -> Result<S::Ok, S::Error> {
|serializer: S, elements: &[PyObjectRef]| -> Result<S::Ok, S::Error> {
let mut seq = serializer.serialize_seq(Some(elements.len()))?;
for e in elements.iter() {
seq.serialize_element(&self.clone_with_object(e))?;
@@ -84,12 +87,10 @@ impl<'s> serde::Serialize for PyObjectSerializer<'s> {
} else {
serializer.serialize_i64(v.to_i64().ok_or_else(int_too_large)?)
}
} else if objtype::isinstance(self.pyobject, &self.vm.ctx.list_type()) {
let elements = objsequence::get_elements_list(self.pyobject);
serialize_seq_elements(serializer, &elements)
} else if objtype::isinstance(self.pyobject, &self.vm.ctx.tuple_type()) {
let elements = objsequence::get_elements_tuple(self.pyobject);
serialize_seq_elements(serializer, &elements)
} else if let Some(list) = self.pyobject.payload_if_subclass::<PyList>(self.vm) {
serialize_seq_elements(serializer, &list.borrow_elements())
} else if let Some(tuple) = self.pyobject.payload_if_subclass::<PyTuple>(self.vm) {
serialize_seq_elements(serializer, tuple.as_slice())
} else if objtype::isinstance(self.pyobject, &self.vm.ctx.dict_type()) {
let dict: PyDictRef = self.pyobject.clone().downcast().unwrap();
let pairs: Vec<_> = dict.into_iter().collect();
+168
View File
@@ -0,0 +1,168 @@
use crate::pyobject::{IdProtocol, PyObjectRef, PyResult};
use crate::vm::VirtualMachine;
use std::ops::Deref;
type DynPyIter<'a> = Box<dyn ExactSizeIterator<Item = &'a PyObjectRef> + 'a>;
#[allow(clippy::len_without_is_empty)]
pub trait SimpleSeq {
fn len(&self) -> usize;
fn iter(&self) -> DynPyIter;
}
// impl SimpleSeq for &[PyObjectRef] {
// fn len(&self) -> usize {
// (&**self).len()
// }
// fn iter(&self) -> DynPyIter {
// Box::new((&**self).iter())
// }
// }
impl SimpleSeq for Vec<PyObjectRef> {
fn len(&self) -> usize {
self.len()
}
fn iter(&self) -> DynPyIter {
Box::new(self.as_slice().iter())
}
}
impl SimpleSeq for std::collections::VecDeque<PyObjectRef> {
fn len(&self) -> usize {
self.len()
}
fn iter(&self) -> DynPyIter {
Box::new(self.iter())
}
}
impl<T> SimpleSeq for std::cell::Ref<'_, T>
where
T: SimpleSeq,
{
fn len(&self) -> usize {
self.deref().len()
}
fn iter(&self) -> DynPyIter {
self.deref().iter()
}
}
// impl<'a, I>
pub(crate) fn eq(
vm: &VirtualMachine,
zelf: &impl SimpleSeq,
other: &impl SimpleSeq,
) -> PyResult<bool> {
if zelf.len() == other.len() {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if a.is(b) {
continue;
}
if !vm.bool_eq(a.clone(), b.clone())? {
return Ok(false);
}
}
Ok(true)
} else {
Ok(false)
}
}
pub(crate) fn lt(
vm: &VirtualMachine,
zelf: &impl SimpleSeq,
other: &impl SimpleSeq,
) -> PyResult<bool> {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if let Some(v) = vm.bool_seq_lt(a.clone(), b.clone())? {
return Ok(v);
}
}
Ok(zelf.len() < other.len())
}
pub(crate) fn gt(
vm: &VirtualMachine,
zelf: &impl SimpleSeq,
other: &impl SimpleSeq,
) -> PyResult<bool> {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if let Some(v) = vm.bool_seq_gt(a.clone(), b.clone())? {
return Ok(v);
}
}
Ok(zelf.len() > other.len())
}
pub(crate) fn ge(
vm: &VirtualMachine,
zelf: &impl SimpleSeq,
other: &impl SimpleSeq,
) -> PyResult<bool> {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if let Some(v) = vm.bool_seq_gt(a.clone(), b.clone())? {
return Ok(v);
}
}
Ok(zelf.len() >= other.len())
}
pub(crate) fn le(
vm: &VirtualMachine,
zelf: &impl SimpleSeq,
other: &impl SimpleSeq,
) -> PyResult<bool> {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
if let Some(v) = vm.bool_seq_lt(a.clone(), b.clone())? {
return Ok(v);
}
}
Ok(zelf.len() <= other.len())
}
pub(crate) struct SeqMul<'a> {
seq: &'a dyn SimpleSeq,
repetitions: usize,
iter: Option<DynPyIter<'a>>,
}
impl ExactSizeIterator for SeqMul<'_> {}
impl<'a> Iterator for SeqMul<'a> {
type Item = &'a PyObjectRef;
fn next(&mut self) -> Option<Self::Item> {
if self.seq.len() == 0 {
return None;
}
match self.iter.as_mut().and_then(Iterator::next) {
Some(item) => Some(item),
None => {
if self.repetitions == 0 {
None
} else {
self.repetitions -= 1;
self.iter = Some(self.seq.iter());
self.next()
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.iter.as_ref().map_or(0, ExactSizeIterator::len)
+ (self.repetitions * self.seq.len());
(size, Some(size))
}
}
pub(crate) fn seq_mul(seq: &impl SimpleSeq, repetitions: isize) -> SeqMul {
SeqMul {
seq,
repetitions: repetitions.max(0) as usize,
iter: None,
}
}
+75 -67
View File
@@ -1,6 +1,10 @@
use crate::function::OptionalArg;
use crate::obj::{objiter, objsequence, objtype::PyClassRef};
use crate::pyobject::{IdProtocol, PyClassImpl, PyIterable, PyObjectRef, PyRef, PyResult, PyValue};
use crate::obj::{objiter, objtype::PyClassRef};
use crate::pyobject::{
IdProtocol, PyArithmaticValue::*, PyClassImpl, PyComparisonValue, PyIterable, PyObjectRef,
PyRef, PyResult, PyValue,
};
use crate::sequence::{self, SimpleSeq};
use crate::vm::ReprGuard;
use crate::VirtualMachine;
use itertools::Itertools;
@@ -27,6 +31,12 @@ struct PyDequeOptions {
maxlen: Option<usize>,
}
impl PyDeque {
fn borrow_deque<'a>(&'a self) -> impl std::ops::Deref<Target = VecDeque<PyObjectRef>> + 'a {
self.deque.borrow()
}
}
#[pyimpl]
impl PyDeque {
#[pyslot(new)]
@@ -201,6 +211,7 @@ impl PyDeque {
fn maxlen(&self, _vm: &VirtualMachine) -> Option<usize> {
self.maxlen.get()
}
#[pyproperty(setter)]
fn set_maxlen(&self, maxlen: Option<usize>, _vm: &VirtualMachine) {
self.maxlen.set(maxlen);
@@ -227,100 +238,97 @@ impl PyDeque {
Ok(repr)
}
#[inline]
fn cmp<F>(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyResult<PyComparisonValue>
where
F: Fn(&VecDeque<PyObjectRef>, &VecDeque<PyObjectRef>) -> PyResult<bool>,
{
let r = if let Some(other) = other.payload_if_subclass::<PyDeque>(vm) {
Implemented(op(&*self.borrow_deque(), &*other.borrow_deque())?)
} else {
NotImplemented
};
Ok(r)
}
#[pymethod(name = "__eq__")]
fn eq(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn eq(
zelf: PyRef<Self>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
if zelf.as_object().is(&other) {
return Ok(vm.new_bool(true));
Ok(Implemented(true))
} else {
zelf.cmp(other, |a, b| sequence::eq(vm, a, b), vm)
}
}
let other = match_class!(match other {
other @ Self => other,
_ => return Ok(vm.ctx.not_implemented()),
});
let lhs: &VecDeque<_> = &zelf.deque.borrow();
let rhs: &VecDeque<_> = &other.deque.borrow();
let eq = objsequence::seq_equal(vm, lhs, rhs)?;
Ok(vm.new_bool(eq))
#[pymethod(name = "__ne__")]
fn ne(
zelf: PyRef<Self>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
Ok(PyDeque::eq(zelf, other, vm)?.map(|v| !v))
}
#[pymethod(name = "__lt__")]
fn lt(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn lt(
zelf: PyRef<Self>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
if zelf.as_object().is(&other) {
return Ok(vm.new_bool(true));
Ok(Implemented(false))
} else {
zelf.cmp(other, |a, b| sequence::lt(vm, a, b), vm)
}
let other = match_class!(match other {
other @ Self => other,
_ => return Ok(vm.ctx.not_implemented()),
});
let lhs: &VecDeque<_> = &zelf.deque.borrow();
let rhs: &VecDeque<_> = &other.deque.borrow();
let eq = objsequence::seq_lt(vm, lhs, rhs)?;
Ok(vm.new_bool(eq))
}
#[pymethod(name = "__gt__")]
fn gt(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn gt(
zelf: PyRef<Self>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
if zelf.as_object().is(&other) {
return Ok(vm.new_bool(true));
Ok(Implemented(false))
} else {
zelf.cmp(other, |a, b| sequence::gt(vm, a, b), vm)
}
let other = match_class!(match other {
other @ Self => other,
_ => return Ok(vm.ctx.not_implemented()),
});
let lhs: &VecDeque<_> = &zelf.deque.borrow();
let rhs: &VecDeque<_> = &other.deque.borrow();
let eq = objsequence::seq_gt(vm, lhs, rhs)?;
Ok(vm.new_bool(eq))
}
#[pymethod(name = "__le__")]
fn le(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn le(
zelf: PyRef<Self>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
if zelf.as_object().is(&other) {
return Ok(vm.new_bool(true));
Ok(Implemented(true))
} else {
zelf.cmp(other, |a, b| sequence::le(vm, a, b), vm)
}
let other = match_class!(match other {
other @ Self => other,
_ => return Ok(vm.ctx.not_implemented()),
});
let lhs: &VecDeque<_> = &zelf.deque.borrow();
let rhs: &VecDeque<_> = &other.deque.borrow();
let eq = objsequence::seq_le(vm, lhs, rhs)?;
Ok(vm.new_bool(eq))
}
#[pymethod(name = "__ge__")]
fn ge(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn ge(
zelf: PyRef<Self>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
if zelf.as_object().is(&other) {
return Ok(vm.new_bool(true));
Ok(Implemented(true))
} else {
zelf.cmp(other, |a, b| sequence::ge(vm, a, b), vm)
}
let other = match_class!(match other {
other @ Self => other,
_ => return Ok(vm.ctx.not_implemented()),
});
let lhs: &VecDeque<_> = &zelf.deque.borrow();
let rhs: &VecDeque<_> = &other.deque.borrow();
let eq = objsequence::seq_ge(vm, lhs, rhs)?;
Ok(vm.new_bool(eq))
}
#[pymethod(name = "__mul__")]
fn mul(&self, n: isize, _vm: &VirtualMachine) -> Self {
let deque: &VecDeque<_> = &self.deque.borrow();
let mul = objsequence::seq_mul(deque, n);
let mul = sequence::seq_mul(deque, n);
let skipped = if let Some(maxlen) = self.maxlen.get() {
mul.len() - maxlen
} else {
+3 -3
View File
@@ -389,16 +389,16 @@ impl ToSocketAddrs for Address {
impl TryFromObject for Address {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let tuple = PyTupleRef::try_from_object(vm, obj)?;
if tuple.elements.len() != 2 {
if tuple.as_slice().len() != 2 {
Err(vm.new_type_error("Address tuple should have only 2 values".to_string()))
} else {
let host = PyStringRef::try_from_object(vm, tuple.elements[0].clone())?;
let host = PyStringRef::try_from_object(vm, tuple.as_slice()[0].clone())?;
let host = if host.as_str().is_empty() {
PyString::from("0.0.0.0").into_ref(vm)
} else {
host
};
let port = u16::try_from_object(vm, tuple.elements[1].clone())?;
let port = u16::try_from_object(vm, tuple.as_slice()[1].clone())?;
Ok(Address { host, port })
}
}
+2 -2
View File
@@ -8,7 +8,6 @@ use subprocess;
use crate::function::OptionalArg;
use crate::obj::objbytes::PyBytesRef;
use crate::obj::objlist::PyListRef;
use crate::obj::objsequence;
use crate::obj::objstr::{self, PyStringRef};
use crate::obj::objtype::PyClassRef;
use crate::pyobject::{Either, IntoPyObject, PyObjectRef, PyRef, PyResult, PyValue};
@@ -107,7 +106,8 @@ impl PopenRef {
let stderr = convert_redirection(args.stderr, vm)?;
let command_list = match &args.args {
Either::A(command) => vec![command.as_str().to_string()],
Either::B(command_list) => objsequence::get_elements_list(command_list.as_object())
Either::B(command_list) => command_list
.borrow_elements()
.iter()
.map(|x| objstr::get_value(x))
.collect(),
+12 -6
View File
@@ -33,10 +33,10 @@ use crate::obj::objfunction::{PyFunction, PyMethod};
use crate::obj::objgenerator::PyGenerator;
use crate::obj::objint::PyInt;
use crate::obj::objiter;
use crate::obj::objlist::PyList;
use crate::obj::objmodule::{self, PyModule};
use crate::obj::objsequence;
use crate::obj::objstr::{PyString, PyStringRef};
use crate::obj::objtuple::PyTupleRef;
use crate::obj::objtuple::{PyTuple, PyTupleRef};
use crate::obj::objtype::{self, PyClassRef};
use crate::pyhash;
use crate::pyobject::{
@@ -850,7 +850,7 @@ impl VirtualMachine {
// Add missing positional arguments, if we have fewer positional arguments than the
// function definition calls for
if nargs < nexpected_args {
let num_defaults_available = defaults.as_ref().map_or(0, |d| d.elements.len());
let num_defaults_available = defaults.as_ref().map_or(0, |d| d.as_slice().len());
// Given the number of defaults available, check all the arguments for which we
// _don't_ have defaults; if any are missing, raise an exception
@@ -870,7 +870,7 @@ impl VirtualMachine {
)));
}
if let Some(defaults) = defaults {
let defaults = &defaults.elements;
let defaults = defaults.as_slice();
// We have sufficient defaults, so iterate over the corresponding names and use
// the default if we don't already have a value
for (default_index, i) in (required_args..nexpected_args).enumerate() {
@@ -905,12 +905,18 @@ impl VirtualMachine {
// Extract elements from item, if possible:
let cls = value.class();
if cls.is(&self.ctx.tuple_type()) {
objsequence::get_elements_tuple(value)
value
.payload::<PyTuple>()
.unwrap()
.as_slice()
.iter()
.map(|obj| T::try_from_object(self, obj.clone()))
.collect()
} else if cls.is(&self.ctx.list_type()) {
objsequence::get_elements_list(value)
value
.payload::<PyList>()
.unwrap()
.borrow_elements()
.iter()
.map(|obj| T::try_from_object(self, obj.clone()))
.collect()