diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 3ba95683b..faa8dc5ac 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -602,7 +602,7 @@ impl AsSequence for PyBytes { let other = >::try_from_object(vm, other.to_owned())?; Self::sequence_downcast(seq).contains(other, vm) }), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 9d88d1918..8be379ee1 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -480,7 +480,7 @@ impl AsMapping for PyDict { impl AsSequence for PyDict { const AS_SEQUENCE: PySequenceMethods = PySequenceMethods { contains: Some(|seq, target, vm| Self::sequence_downcast(seq).entries.contains(vm, target)), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } @@ -1056,7 +1056,7 @@ impl AsSequence for PyDictKeys { .entries .contains(vm, target) }), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } @@ -1105,7 +1105,7 @@ impl AsSequence for PyDictItems { .entries .contains(vm, target) }), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } @@ -1116,7 +1116,7 @@ impl Unconstructible for PyDictValues {} impl AsSequence for PyDictValues { const AS_SEQUENCE: PySequenceMethods = PySequenceMethods { length: Some(|seq, _vm| Ok(Self::sequence_downcast(seq).len())), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index d9760c798..18495155b 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -158,7 +158,7 @@ impl AsMapping for PyMappingProxy { impl AsSequence for PyMappingProxy { const AS_SEQUENCE: PySequenceMethods = PySequenceMethods { contains: Some(|seq, target, vm| Self::sequence_downcast(seq)._contains(target, vm)), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index cd5ba4ec9..61b28e3bc 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -987,7 +987,7 @@ impl AsSequence for PyMemoryView { zelf.try_not_released(vm)?; zelf.getitem_by_idx(i, vm) }), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index 04fa9a213..312a46efe 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -413,7 +413,7 @@ impl AsSequence for PyRange { contains: Some(|seq, needle, vm| { Ok(Self::sequence_downcast(seq).contains(needle.to_owned(), vm)) }), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } diff --git a/vm/src/builtins/set.rs b/vm/src/builtins/set.rs index 3c9ec107a..a637b3b6e 100644 --- a/vm/src/builtins/set.rs +++ b/vm/src/builtins/set.rs @@ -665,7 +665,7 @@ impl AsSequence for PySet { const AS_SEQUENCE: PySequenceMethods = PySequenceMethods { length: Some(|seq, _vm| Ok(Self::sequence_downcast(seq).len())), contains: Some(|seq, needle, vm| Self::sequence_downcast(seq).inner.contains(needle, vm)), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } @@ -897,7 +897,7 @@ impl AsSequence for PyFrozenSet { const AS_SEQUENCE: PySequenceMethods = PySequenceMethods { length: Some(|seq, _vm| Ok(Self::sequence_downcast(seq).len())), contains: Some(|seq, needle, vm| Self::sequence_downcast(seq).inner.contains(needle, vm)), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index a6da111a7..1700795d6 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -1325,7 +1325,7 @@ impl AsSequence for PyStr { .map(|x| zelf.new_substr(x.to_string()).into_ref(vm).into()) }), contains: Some(|seq, needle, vm| Self::sequence_downcast(seq)._contains(needle, vm)), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index acf7a692e..59ea9a644 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -378,7 +378,7 @@ impl AsSequence for PyTuple { let zelf = Self::sequence_downcast(seq); zelf._contains(needle, vm) }), - ..*PySequenceMethods::not_implemented() + ..PySequenceMethods::NOT_IMPLEMENTED }; } diff --git a/vm/src/protocol/sequence.rs b/vm/src/protocol/sequence.rs index 3af7a0bf9..331d78869 100644 --- a/vm/src/protocol/sequence.rs +++ b/vm/src/protocol/sequence.rs @@ -30,9 +30,16 @@ pub struct PySequenceMethods { } impl PySequenceMethods { - pub const fn not_implemented() -> &'static Self { - &NOT_IMPLEMENTED - } + pub const NOT_IMPLEMENTED: PySequenceMethods = PySequenceMethods { + length: None, + concat: None, + repeat: None, + item: None, + ass_item: None, + contains: None, + inplace_concat: None, + inplace_repeat: None, + }; } impl Debug for PySequenceMethods { @@ -101,7 +108,7 @@ impl PySequence<'_> { return f(self.obj, vm); } } - Cow::Borrowed(PySequenceMethods::not_implemented()) + Cow::Borrowed(&PySequenceMethods::NOT_IMPLEMENTED) }) } @@ -393,14 +400,3 @@ impl PySequence<'_> { } } } - -const NOT_IMPLEMENTED: PySequenceMethods = PySequenceMethods { - length: None, - concat: None, - repeat: None, - item: None, - ass_item: None, - contains: None, - inplace_concat: None, - inplace_repeat: None, -}; diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 287f0d6b6..d8b5bd67c 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -164,16 +164,6 @@ pub(crate) type InitFunc = fn(PyObjectRef, FuncArgs, &VirtualMachine) -> PyResul pub(crate) type DelFunc = fn(&PyObject, &VirtualMachine) -> PyResult<()>; pub(crate) type AsSequenceFunc = fn(&PyObject, &VirtualMachine) -> Cow<'static, PySequenceMethods>; -macro_rules! then_some_closure { - ($cond:expr, $closure:expr) => { - if $cond { - Some($closure) - } else { - None - } - }; -} - fn length_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult { let ret = vm.call_special_method(obj.to_owned(), identifier!(vm, __len__), ())?; let len = ret.payload::().ok_or_else(|| { @@ -282,45 +272,73 @@ fn as_mapping_generic(zelf: &PyObject, vm: &VirtualMachine) -> &'static PyMappin static_as_mapping_generic(has_length, has_subscript, has_ass_subscript) } -fn as_sequence_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> Cow<'static, PySequenceMethods> { - if !zelf.class().has_attr(identifier!(vm, __getitem__)) { - return Cow::Borrowed(PySequenceMethods::not_implemented()); +pub(crate) fn static_as_sequence_generic( + has_length: bool, + has_ass_item: bool, +) -> &'static PySequenceMethods { + static METHODS: &[PySequenceMethods] = &[ + new_generic(false, false), + new_generic(true, false), + new_generic(false, true), + new_generic(true, true), + ]; + + fn length(seq: &PySequence, vm: &VirtualMachine) -> PyResult { + length_wrapper(seq.obj, vm) + } + fn item(seq: &PySequence, i: isize, vm: &VirtualMachine) -> PyResult { + vm.call_special_method(seq.obj.to_owned(), identifier!(vm, __getitem__), (i,)) + } + fn ass_item( + seq: &PySequence, + i: isize, + value: Option, + vm: &VirtualMachine, + ) -> PyResult<()> { + match value { + Some(value) => vm + .call_special_method( + seq.obj.to_owned(), + identifier!(vm, __setitem__), + (i.to_pyobject(vm), value), + ) + .map(|_| Ok(()))?, + None => vm + .call_special_method( + seq.obj.to_owned(), + identifier!(vm, __delitem__), + (i.to_pyobject(vm),), + ) + .map(|_| Ok(()))?, + } } - Cow::Owned(PySequenceMethods { - length: then_some_closure!( - zelf.class().has_attr(identifier!(vm, __len__)), - |seq, vm| { length_wrapper(seq.obj, vm) } - ), - item: Some(|seq, i, vm| { - vm.call_special_method( - seq.obj.to_owned(), - identifier!(vm, __getitem__), - (i.to_pyobject(vm),), - ) - }), - ass_item: then_some_closure!( - zelf.class().has_attr(identifier!(vm, __setitem__)) - | zelf.class().has_attr(identifier!(vm, __delitem__)), - |seq, i, value, vm| match value { - Some(value) => vm - .call_special_method( - seq.obj.to_owned(), - identifier!(vm, __setitem__), - (i.to_pyobject(vm), value), - ) - .map(|_| Ok(()))?, - None => vm - .call_special_method( - seq.obj.to_owned(), - identifier!(vm, __delitem__), - (i.to_pyobject(vm),) - ) - .map(|_| Ok(()))?, - } - ), - ..Default::default() - }) + const fn new_generic(has_length: bool, has_ass_item: bool) -> PySequenceMethods { + PySequenceMethods { + length: if has_length { Some(length) } else { None }, + item: Some(item), + ass_item: if has_ass_item { Some(ass_item) } else { None }, + ..PySequenceMethods::NOT_IMPLEMENTED + } + } + + let key = bool_int(has_length) | (bool_int(has_ass_item) << 1); + + &METHODS[key] +} + +fn as_sequence_generic(zelf: &PyObject, vm: &VirtualMachine) -> Cow<'static, PySequenceMethods> { + if !zelf.class().has_attr(identifier!(vm, __getitem__)) { + return Cow::Borrowed(&PySequenceMethods::NOT_IMPLEMENTED); + } + + let (has_length, has_ass_item) = ( + zelf.class().has_attr(identifier!(vm, __len__)), + zelf.class().has_attr(identifier!(vm, __setitem__)) + | zelf.class().has_attr(identifier!(vm, __delitem__)), + ); + + Cow::Borrowed(static_as_sequence_generic(has_length, has_ass_item)) } fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { @@ -436,7 +454,7 @@ impl PyType { match name.as_str() { "__len__" | "__getitem__" | "__setitem__" | "__delitem__" => { update_slot!(as_mapping, as_mapping_generic); - update_slot!(as_sequence, as_sequence_wrapper); + update_slot!(as_sequence, as_sequence_generic); } "__hash__" => { update_slot!(hash, hash_wrapper);