Skip to content

Commit 186990f

Browse files
authored
Refactor Sequence Protocol (RustPython#4137)
* Refactor Sequence Protocol * rebase * fixup * fix inherit slots * rebase * fix io slot_init * mark unsuccess test_xml_etree
1 parent ec46ae1 commit 186990f

File tree

22 files changed

+564
-492
lines changed

22 files changed

+564
-492
lines changed

Lib/test/test_xml_etree.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2187,6 +2187,8 @@ def test_bug_xmltoolkit62(self):
21872187
self.assertEqual(t.find('.//paragraph').text,
21882188
'A new cultivar of Begonia plant named \u2018BCT9801BEG\u2019.')
21892189

2190+
# TODO: RUSTPYTHON
2191+
@unittest.expectedFailure
21902192
@unittest.skipIf(sys.gettrace(), "Skips under coverage.")
21912193
def test_bug_xmltoolkit63(self):
21922194
# Check reference leak.

derive/src/pyclass.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ where
578578
let slot_name = slot_ident.to_string();
579579
let tokens = {
580580
const NON_ATOMIC_SLOTS: &[&str] = &["as_buffer"];
581-
const POINTER_SLOTS: &[&str] = &["as_number"];
581+
const POINTER_SLOTS: &[&str] = &["as_number", "as_sequence"];
582582
if NON_ATOMIC_SLOTS.contains(&slot_name.as_str()) {
583583
quote_spanned! { span =>
584584
slots.#slot_ident = Some(Self::#ident as _);

stdlib/src/mmap.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod mmap {
88
lock::{MapImmutable, PyMutex, PyMutexGuard},
99
};
1010
use crate::vm::{
11+
atomic_func,
1112
builtins::{PyBytes, PyBytesRef, PyInt, PyIntRef, PyTypeRef},
1213
byte::{bytes_from_object, value_from_object},
1314
function::{ArgBytesLike, FuncArgs, OptionalArg},
@@ -440,22 +441,26 @@ mod mmap {
440441
}
441442

442443
impl AsSequence for PyMmap {
443-
const AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
444-
length: Some(|seq, _vm| Ok(Self::sequence_downcast(seq).len())),
445-
item: Some(|seq, i, vm| {
446-
let zelf = Self::sequence_downcast(seq);
447-
zelf.getitem_by_index(i, vm)
448-
}),
449-
ass_item: Some(|seq, i, value, vm| {
450-
let zelf = Self::sequence_downcast(seq);
451-
if let Some(value) = value {
452-
Self::setitem_by_index(zelf.to_owned(), i, value, vm)
453-
} else {
454-
Err(vm.new_type_error("mmap object doesn't support item deletion".to_owned()))
455-
}
456-
}),
457-
..PySequenceMethods::NOT_IMPLEMENTED
458-
};
444+
fn as_sequence() -> &'static PySequenceMethods {
445+
static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
446+
length: atomic_func!(|seq, _vm| Ok(PyMmap::sequence_downcast(seq).len())),
447+
item: atomic_func!(|seq, i, vm| {
448+
let zelf = PyMmap::sequence_downcast(seq);
449+
zelf.getitem_by_index(i, vm)
450+
}),
451+
ass_item: atomic_func!(|seq, i, value, vm| {
452+
let zelf = PyMmap::sequence_downcast(seq);
453+
if let Some(value) = value {
454+
PyMmap::setitem_by_index(zelf.to_owned(), i, value, vm)
455+
} else {
456+
Err(vm
457+
.new_type_error("mmap object doesn't support item deletion".to_owned()))
458+
}
459+
}),
460+
..PySequenceMethods::NOT_IMPLEMENTED
461+
};
462+
&AS_SEQUENCE
463+
}
459464
}
460465

461466
#[pyclass(with(Constructor, AsMapping, AsSequence, AsBuffer), flags(BASETYPE))]

vm/src/builtins/bytearray.rs

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::{
55
};
66
use crate::{
77
anystr::{self, AnyStr},
8+
atomic_func,
89
byte::{bytes_from_object, value_from_object},
910
bytesinner::{
1011
bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
@@ -784,47 +785,51 @@ impl AsMapping for PyByteArray {
784785
}
785786

786787
impl AsSequence for PyByteArray {
787-
const AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
788-
length: Some(|seq, _vm| Ok(Self::sequence_downcast(seq).len())),
789-
concat: Some(|seq, other, vm| {
790-
Self::sequence_downcast(seq)
791-
.inner()
792-
.concat(other, vm)
793-
.map(|x| PyByteArray::from(x).into_pyobject(vm))
794-
}),
795-
repeat: Some(|seq, n, vm| {
796-
Self::sequence_downcast(seq)
797-
.mul(n as isize, vm)
798-
.map(|x| x.into_pyobject(vm))
799-
}),
800-
item: Some(|seq, i, vm| {
801-
Self::sequence_downcast(seq)
802-
.borrow_buf()
803-
.getitem_by_index(vm, i)
804-
.map(|x| vm.ctx.new_bytes(vec![x]).into())
805-
}),
806-
ass_item: Some(|seq, i, value, vm| {
807-
let zelf = Self::sequence_downcast(seq);
808-
if let Some(value) = value {
809-
zelf._setitem_by_index(i, value, vm)
810-
} else {
811-
zelf.borrow_buf_mut().del_item_by_index(vm, i)
812-
}
813-
}),
814-
contains: Some(|seq, other, vm| {
815-
let other = <Either<PyBytesInner, PyIntRef>>::try_from_object(vm, other.to_owned())?;
816-
Self::sequence_downcast(seq).contains(other, vm)
817-
}),
818-
inplace_concat: Some(|seq, other, vm| {
819-
let other = ArgBytesLike::try_from_object(vm, other.to_owned())?;
820-
let zelf = Self::sequence_downcast(seq).to_owned();
821-
Self::iadd(zelf, other, vm).map(|x| x.into())
822-
}),
823-
inplace_repeat: Some(|seq, n, vm| {
824-
let zelf = Self::sequence_downcast(seq).to_owned();
825-
Self::imul(zelf, n as isize, vm).map(|x| x.into())
826-
}),
827-
};
788+
fn as_sequence() -> &'static PySequenceMethods {
789+
static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
790+
length: atomic_func!(|seq, _vm| Ok(PyByteArray::sequence_downcast(seq).len())),
791+
concat: atomic_func!(|seq, other, vm| {
792+
PyByteArray::sequence_downcast(seq)
793+
.inner()
794+
.concat(other, vm)
795+
.map(|x| PyByteArray::from(x).into_pyobject(vm))
796+
}),
797+
repeat: atomic_func!(|seq, n, vm| {
798+
PyByteArray::sequence_downcast(seq)
799+
.mul(n as isize, vm)
800+
.map(|x| x.into_pyobject(vm))
801+
}),
802+
item: atomic_func!(|seq, i, vm| {
803+
PyByteArray::sequence_downcast(seq)
804+
.borrow_buf()
805+
.getitem_by_index(vm, i)
806+
.map(|x| vm.ctx.new_bytes(vec![x]).into())
807+
}),
808+
ass_item: atomic_func!(|seq, i, value, vm| {
809+
let zelf = PyByteArray::sequence_downcast(seq);
810+
if let Some(value) = value {
811+
zelf._setitem_by_index(i, value, vm)
812+
} else {
813+
zelf.borrow_buf_mut().del_item_by_index(vm, i)
814+
}
815+
}),
816+
contains: atomic_func!(|seq, other, vm| {
817+
let other =
818+
<Either<PyBytesInner, PyIntRef>>::try_from_object(vm, other.to_owned())?;
819+
PyByteArray::sequence_downcast(seq).contains(other, vm)
820+
}),
821+
inplace_concat: atomic_func!(|seq, other, vm| {
822+
let other = ArgBytesLike::try_from_object(vm, other.to_owned())?;
823+
let zelf = PyByteArray::sequence_downcast(seq).to_owned();
824+
PyByteArray::iadd(zelf, other, vm).map(|x| x.into())
825+
}),
826+
inplace_repeat: atomic_func!(|seq, n, vm| {
827+
let zelf = PyByteArray::sequence_downcast(seq).to_owned();
828+
PyByteArray::imul(zelf, n as isize, vm).map(|x| x.into())
829+
}),
830+
};
831+
&AS_SEQUENCE
832+
}
828833
}
829834

830835
impl Unhashable for PyByteArray {}

vm/src/builtins/bytes.rs

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -579,33 +579,37 @@ impl AsMapping for PyBytes {
579579
}
580580

581581
impl AsSequence for PyBytes {
582-
const AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
583-
length: Some(|seq, _vm| Ok(Self::sequence_downcast(seq).len())),
584-
concat: Some(|seq, other, vm| {
585-
Self::sequence_downcast(seq)
586-
.inner
587-
.concat(other, vm)
588-
.map(|x| vm.ctx.new_bytes(x).into())
589-
}),
590-
repeat: Some(|seq, n, vm| {
591-
Ok(vm
592-
.ctx
593-
.new_bytes(Self::sequence_downcast(seq).repeat(n))
594-
.into())
595-
}),
596-
item: Some(|seq, i, vm| {
597-
Self::sequence_downcast(seq)
598-
.inner
599-
.elements
600-
.getitem_by_index(vm, i)
601-
.map(|x| vm.ctx.new_bytes(vec![x]).into())
602-
}),
603-
contains: Some(|seq, other, vm| {
604-
let other = <Either<PyBytesInner, PyIntRef>>::try_from_object(vm, other.to_owned())?;
605-
Self::sequence_downcast(seq).contains(other, vm)
606-
}),
607-
..PySequenceMethods::NOT_IMPLEMENTED
608-
};
582+
fn as_sequence() -> &'static PySequenceMethods {
583+
static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
584+
length: atomic_func!(|seq, _vm| Ok(PyBytes::sequence_downcast(seq).len())),
585+
concat: atomic_func!(|seq, other, vm| {
586+
PyBytes::sequence_downcast(seq)
587+
.inner
588+
.concat(other, vm)
589+
.map(|x| vm.ctx.new_bytes(x).into())
590+
}),
591+
repeat: atomic_func!(|seq, n, vm| {
592+
Ok(vm
593+
.ctx
594+
.new_bytes(PyBytes::sequence_downcast(seq).repeat(n))
595+
.into())
596+
}),
597+
item: atomic_func!(|seq, i, vm| {
598+
PyBytes::sequence_downcast(seq)
599+
.inner
600+
.elements
601+
.getitem_by_index(vm, i)
602+
.map(|x| vm.ctx.new_bytes(vec![x]).into())
603+
}),
604+
contains: atomic_func!(|seq, other, vm| {
605+
let other =
606+
<Either<PyBytesInner, PyIntRef>>::try_from_object(vm, other.to_owned())?;
607+
PyBytes::sequence_downcast(seq).contains(other, vm)
608+
}),
609+
..PySequenceMethods::NOT_IMPLEMENTED
610+
};
611+
&AS_SEQUENCE
612+
}
609613
}
610614

611615
impl AsNumber for PyBytes {

vm/src/builtins/dict.rs

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::{
33
PyMappingProxy, PySet, PyStrRef, PyTupleRef, PyType, PyTypeRef,
44
};
55
use crate::{
6+
atomic_func,
67
builtins::{
78
iter::{builtins_iter, builtins_reversed},
89
type_::PyAttributes,
@@ -469,10 +470,15 @@ impl AsMapping for PyDict {
469470
}
470471

471472
impl AsSequence for PyDict {
472-
const AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
473-
contains: Some(|seq, target, vm| Self::sequence_downcast(seq).entries.contains(vm, target)),
474-
..PySequenceMethods::NOT_IMPLEMENTED
475-
};
473+
fn as_sequence() -> &'static PySequenceMethods {
474+
static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
475+
contains: atomic_func!(|seq, target, vm| PyDict::sequence_downcast(seq)
476+
.entries
477+
.contains(vm, target)),
478+
..PySequenceMethods::NOT_IMPLEMENTED
479+
};
480+
&AS_SEQUENCE
481+
}
476482
}
477483

478484
impl Comparable for PyDict {
@@ -1051,16 +1057,19 @@ impl Comparable for PyDictKeys {
10511057
}
10521058

10531059
impl AsSequence for PyDictKeys {
1054-
const AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
1055-
length: Some(|seq, _vm| Ok(Self::sequence_downcast(seq).len())),
1056-
contains: Some(|seq, target, vm| {
1057-
Self::sequence_downcast(seq)
1058-
.dict
1059-
.entries
1060-
.contains(vm, target)
1061-
}),
1062-
..PySequenceMethods::NOT_IMPLEMENTED
1063-
};
1060+
fn as_sequence() -> &'static PySequenceMethods {
1061+
static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
1062+
length: atomic_func!(|seq, _vm| Ok(PyDictKeys::sequence_downcast(seq).len())),
1063+
contains: atomic_func!(|seq, target, vm| {
1064+
PyDictKeys::sequence_downcast(seq)
1065+
.dict
1066+
.entries
1067+
.contains(vm, target)
1068+
}),
1069+
..PySequenceMethods::NOT_IMPLEMENTED
1070+
};
1071+
&AS_SEQUENCE
1072+
}
10641073
}
10651074

10661075
impl ViewSetOps for PyDictItems {}
@@ -1104,16 +1113,19 @@ impl Comparable for PyDictItems {
11041113
}
11051114

11061115
impl AsSequence for PyDictItems {
1107-
const AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
1108-
length: Some(|seq, _vm| Ok(Self::sequence_downcast(seq).len())),
1109-
contains: Some(|seq, target, vm| {
1110-
Self::sequence_downcast(seq)
1111-
.dict
1112-
.entries
1113-
.contains(vm, target)
1114-
}),
1115-
..PySequenceMethods::NOT_IMPLEMENTED
1116-
};
1116+
fn as_sequence() -> &'static PySequenceMethods {
1117+
static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
1118+
length: atomic_func!(|seq, _vm| Ok(PyDictItems::sequence_downcast(seq).len())),
1119+
contains: atomic_func!(|seq, target, vm| {
1120+
PyDictItems::sequence_downcast(seq)
1121+
.dict
1122+
.entries
1123+
.contains(vm, target)
1124+
}),
1125+
..PySequenceMethods::NOT_IMPLEMENTED
1126+
};
1127+
&AS_SEQUENCE
1128+
}
11171129
}
11181130

11191131
#[pyclass(with(DictView, Constructor, Iterable, AsSequence))]
@@ -1126,10 +1138,13 @@ impl PyDictValues {
11261138
impl Unconstructible for PyDictValues {}
11271139

11281140
impl AsSequence for PyDictValues {
1129-
const AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
1130-
length: Some(|seq, _vm| Ok(Self::sequence_downcast(seq).len())),
1131-
..PySequenceMethods::NOT_IMPLEMENTED
1132-
};
1141+
fn as_sequence() -> &'static PySequenceMethods {
1142+
static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
1143+
length: atomic_func!(|seq, _vm| Ok(PyDictValues::sequence_downcast(seq).len())),
1144+
..PySequenceMethods::NOT_IMPLEMENTED
1145+
};
1146+
&AS_SEQUENCE
1147+
}
11331148
}
11341149

11351150
pub(crate) fn init(context: &Context) {

vm/src/builtins/iter.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ impl PyPayload for PySequenceIterator {
175175
#[pyclass(with(IterNext))]
176176
impl PySequenceIterator {
177177
pub fn new(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<Self> {
178-
let seq = PySequence::try_protocol(obj.as_ref(), vm)?;
178+
let seq = PySequence::try_protocol(&obj, vm)?;
179179
Ok(Self {
180180
seq_methods: seq.methods,
181181
internal: PyMutex::new(PositionIterInternal::new(obj, 0)),
@@ -186,7 +186,10 @@ impl PySequenceIterator {
186186
fn length_hint(&self, vm: &VirtualMachine) -> PyObjectRef {
187187
let internal = self.internal.lock();
188188
if let IterStatus::Active(obj) = &internal.status {
189-
let seq = PySequence::with_methods(obj, self.seq_methods);
189+
let seq = PySequence {
190+
obj,
191+
methods: self.seq_methods,
192+
};
190193
seq.length(vm)
191194
.map(|x| PyInt::from(x).into_pyobject(vm))
192195
.unwrap_or_else(|_| vm.ctx.not_implemented())
@@ -210,7 +213,10 @@ impl IterNextIterable for PySequenceIterator {}
210213
impl IterNext for PySequenceIterator {
211214
fn next(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
212215
zelf.internal.lock().next(|obj, pos| {
213-
let seq = PySequence::with_methods(obj, zelf.seq_methods);
216+
let seq = PySequence {
217+
obj,
218+
methods: zelf.seq_methods,
219+
};
214220
PyIterReturn::from_getitem_result(seq.get_item(pos as isize, vm), vm)
215221
})
216222
}

0 commit comments

Comments
 (0)