From 15fa08b9a8bf896da7bf3939bc9307841900c247 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:44:06 +0300 Subject: [PATCH 01/13] General cleanups --- stdlib/src/mmap.rs | 26 ++++++++++++-------------- stdlib/src/pystruct.rs | 2 +- stdlib/src/socket.rs | 17 +++++++++++++---- stdlib/src/zlib.rs | 8 +++++++- vm/src/ospath.rs | 4 +++- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/stdlib/src/mmap.rs b/stdlib/src/mmap.rs index 6589699d3f..0a263555fb 100644 --- a/stdlib/src/mmap.rs +++ b/stdlib/src/mmap.rs @@ -213,25 +213,22 @@ mod mmap { impl FlushOptions { fn values(self, len: usize) -> Option<(usize, usize)> { - let offset = if let Some(offset) = self.offset { - if offset < 0 { - return None; - } - offset as usize - } else { - 0 + let offset = match self.offset { + Some(o) if o < 0 => return None, + Some(o) => o as usize, + None => 0, }; - let size = if let Some(size) = self.size { - if size < 0 { - return None; - } - size as usize - } else { - len + + let size = match self.size { + Some(s) if s < 0 => return None, + Some(s) => s as usize, + None => len, }; + if len.checked_sub(offset)? < size { return None; } + Some((offset, size)) } } @@ -565,6 +562,7 @@ mod mmap { if self.exports.load() > 0 { return Err(vm.new_buffer_error("cannot close exported pointers exist.")); } + let mut mmap = self.mmap.lock(); self.closed.store(true); *mmap = None; diff --git a/stdlib/src/pystruct.rs b/stdlib/src/pystruct.rs index 0243b56e03..0fba16794a 100644 --- a/stdlib/src/pystruct.rs +++ b/stdlib/src/pystruct.rs @@ -259,7 +259,7 @@ pub(crate) mod _struct { #[pygetset] #[inline] - fn size(&self) -> usize { + const fn size(&self) -> usize { self.spec.size } diff --git a/stdlib/src/socket.rs b/stdlib/src/socket.rs index 1f6442a157..b57f05c967 100644 --- a/stdlib/src/socket.rs +++ b/stdlib/src/socket.rs @@ -726,19 +726,22 @@ mod _socket { } #[pyfunction] - fn htonl(x: u32) -> u32 { + const fn htonl(x: u32) -> u32 { u32::to_be(x) } + #[pyfunction] - fn htons(x: u16) -> u16 { + const fn htons(x: u16) -> u16 { u16::to_be(x) } + #[pyfunction] - fn ntohl(x: u32) -> u32 { + const fn ntohl(x: u32) -> u32 { u32::from_be(x) } + #[pyfunction] - fn ntohs(x: u16) -> u16 { + const fn ntohs(x: u16) -> u16 { u16::from_be(x) } @@ -816,6 +819,7 @@ mod _socket { (&mut &*self.sock()?).read(buf) } } + impl Write for &PySocket { fn write(&mut self, buf: &[u8]) -> std::io::Result { (&mut &*self.sock()?).write(buf) @@ -1450,6 +1454,7 @@ mod _socket { } Ok(()) } + #[pymethod] #[inline] fn detach(&self) -> RawSocket { @@ -1471,6 +1476,7 @@ mod _socket { Ok(get_addr_tuple(&addr, vm)) } + #[pymethod] fn getpeername(&self, vm: &VirtualMachine) -> std::io::Result { let addr = self.sock()?.peer_addr()?; @@ -1615,10 +1621,12 @@ mod _socket { fn kind(&self) -> i32 { self.kind.load() } + #[pygetset] fn family(&self) -> i32 { self.family.load() } + #[pygetset] fn proto(&self) -> i32 { self.proto.load() @@ -1657,6 +1665,7 @@ mod _socket { .ok_or_else(|| vm.new_overflow_error("port must be 0-65535."))?; Ok(Address { host, port }) } + fn from_tuple_ipv6( tuple: &[PyObjectRef], vm: &VirtualMachine, diff --git a/stdlib/src/zlib.rs b/stdlib/src/zlib.rs index 8a86582a59..1927d2a198 100644 --- a/stdlib/src/zlib.rs +++ b/stdlib/src/zlib.rs @@ -231,10 +231,12 @@ mod zlib { fn eof(&self) -> bool { self.inner.lock().eof } + #[pygetset] fn unused_data(&self) -> PyBytesRef { self.inner.lock().unused_data.clone() } + #[pygetset] fn unconsumed_tail(&self) -> PyBytesRef { self.inner.lock().unconsumed_tail.clone() @@ -414,7 +416,7 @@ mod zlib { const CHUNKSIZE: usize = u32::MAX as usize; impl CompressInner { - fn new(compress: Compress) -> Self { + const fn new(compress: Compress) -> Self { Self { compress } } } @@ -481,6 +483,7 @@ mod zlib { }; Self(Some(compression)) } + fn ok_or_else( self, f: impl FnOnce() -> PyBaseExceptionRef, @@ -527,6 +530,7 @@ mod zlib { fn total_in(&self) -> u64 { self.total_in() } + fn decompress_vec( &mut self, input: &[u8], @@ -545,6 +549,7 @@ mod zlib { fn total_in(&self) -> u64 { self.decompress.total_in() } + fn decompress_vec( &mut self, input: &[u8], @@ -553,6 +558,7 @@ mod zlib { ) -> Result { self.decompress.decompress_vec(input, output, flush) } + fn maybe_set_dict(&mut self, err: Self::Error) -> Result<(), Self::Error> { let zdict = err.needs_dictionary().and(self.zdict.as_ref()).ok_or(err)?; self.decompress.set_dictionary(&zdict.borrow_buf())?; diff --git a/vm/src/ospath.rs b/vm/src/ospath.rs index 26d1582825..3351d821ae 100644 --- a/vm/src/ospath.rs +++ b/vm/src/ospath.rs @@ -133,18 +133,20 @@ pub struct IOErrorBuilder<'a> { } impl<'a> IOErrorBuilder<'a> { - pub fn new(error: &'a std::io::Error) -> Self { + pub const fn new(error: &'a std::io::Error) -> Self { Self { error, filename: None, filename2: None, } } + pub(crate) fn filename(mut self, filename: impl Into) -> Self { let filename = filename.into(); self.filename.replace(filename); self } + pub(crate) fn filename2(mut self, filename: impl Into) -> Self { let filename = filename.into(); self.filename2.replace(filename); From 49b56afce4491650dfd0f5cfe927706cb741604c Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:17:56 +0300 Subject: [PATCH 02/13] Add some newlines --- vm/src/function/method.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vm/src/function/method.rs b/vm/src/function/method.rs index d3d0b85fae..e24bf43170 100644 --- a/vm/src/function/method.rs +++ b/vm/src/function/method.rs @@ -117,6 +117,7 @@ impl PyMethodDef { unreachable!(); } } + pub fn to_function(&'static self) -> PyNativeFunction { PyNativeFunction { zelf: None, @@ -124,6 +125,7 @@ impl PyMethodDef { module: None, } } + pub fn to_method( &'static self, class: &'static Py, @@ -131,6 +133,7 @@ impl PyMethodDef { ) -> PyMethodDescriptor { PyMethodDescriptor::new(self, class, ctx) } + pub fn to_bound_method( &'static self, obj: PyObjectRef, @@ -145,9 +148,11 @@ impl PyMethodDef { class, } } + pub fn build_function(&'static self, ctx: &Context) -> PyRef { self.to_function().into_ref(ctx) } + pub fn build_bound_function( &'static self, ctx: &Context, @@ -164,6 +169,7 @@ impl PyMethodDef { None, ) } + pub fn build_method( &'static self, ctx: &Context, @@ -173,6 +179,7 @@ impl PyMethodDef { let method = self.to_method(class, ctx); PyRef::new_ref(method, ctx.types.method_descriptor_type.to_owned(), None) } + pub fn build_bound_method( &'static self, ctx: &Context, @@ -185,6 +192,7 @@ impl PyMethodDef { None, ) } + pub fn build_classmethod( &'static self, ctx: &Context, @@ -196,6 +204,7 @@ impl PyMethodDef { None, ) } + pub fn build_staticmethod( &'static self, ctx: &Context, From 80b8072aa8ba71aa98ace9813acdd22708ee183d Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:32:28 +0300 Subject: [PATCH 03/13] Use bitlag match --- vm/src/function/method.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/vm/src/function/method.rs b/vm/src/function/method.rs index e24bf43170..6d9b84d10c 100644 --- a/vm/src/function/method.rs +++ b/vm/src/function/method.rs @@ -107,15 +107,12 @@ impl PyMethodDef { class: &'static Py, ctx: &Context, ) -> PyObjectRef { - if self.flags.contains(PyMethodFlags::METHOD) { - self.build_method(ctx, class).into() - } else if self.flags.contains(PyMethodFlags::CLASS) { - self.build_classmethod(ctx, class).into() - } else if self.flags.contains(PyMethodFlags::STATIC) { - self.build_staticmethod(ctx, class).into() - } else { - unreachable!(); - } + bitflags::bitflags_match!(self.flags, { + PyMethodFlags::METHOD => self.build_method(ctx, class).into(), + PyMethodFlags::CLASS => self.build_classmethod(ctx, class).into(), + PyMethodFlags::STATIC => self.build_staticmethod(ctx, class).into(), + _ => unreachable!(), + }) } pub fn to_function(&'static self) -> PyNativeFunction { From 41adf9027399f0625b351698c8b83498d7cb283a Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:09:07 +0300 Subject: [PATCH 04/13] More constify --- vm/src/builtins/descriptor.rs | 9 ++++++-- vm/src/dict_inner.rs | 42 ++++++++++++++++++++++++++++++----- vm/src/function/method.rs | 6 ++--- vm/src/object/core.rs | 6 ++--- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/vm/src/builtins/descriptor.rs b/vm/src/builtins/descriptor.rs index 9e8ef982d1..2f4d2169bd 100644 --- a/vm/src/builtins/descriptor.rs +++ b/vm/src/builtins/descriptor.rs @@ -110,17 +110,20 @@ impl PyMethodDescriptor { )] impl PyMethodDescriptor { #[pygetset] - fn __name__(&self) -> &'static PyStrInterned { + const fn __name__(&self) -> &'static PyStrInterned { self.common.name } + #[pygetset] fn __qualname__(&self) -> String { format!("{}.{}", self.common.typ.name(), &self.common.name) } + #[pygetset] - fn __doc__(&self) -> Option<&'static str> { + const fn __doc__(&self) -> Option<&'static str> { self.method.doc } + #[pygetset] fn __text_signature__(&self) -> Option { self.method.doc.and_then(|doc| { @@ -128,10 +131,12 @@ impl PyMethodDescriptor { .map(|signature| signature.to_string()) }) } + #[pygetset] fn __objclass__(&self) -> PyTypeRef { self.objclass.to_owned() } + #[pymethod] fn __reduce__( &self, diff --git a/vm/src/dict_inner.rs b/vm/src/dict_inner.rs index 3938fe7c93..02d882106c 100644 --- a/vm/src/dict_inner.rs +++ b/vm/src/dict_inner.rs @@ -57,12 +57,12 @@ impl IndexEntry { /// # Safety /// idx must not be one of FREE or DUMMY - unsafe fn from_index_unchecked(idx: usize) -> Self { + const unsafe fn from_index_unchecked(idx: usize) -> Self { debug_assert!((idx as isize) >= 0); Self(idx as i64) } - fn index(self) -> Option { + const fn index(self) -> Option { if self.0 >= 0 { Some(self.0 as usize) } else { @@ -138,7 +138,7 @@ struct GenIndexes { } impl GenIndexes { - fn new(hash: HashValue, mask: HashIndex) -> Self { + const fn new(hash: HashValue, mask: HashIndex) -> Self { let hash = hash.abs(); Self { idx: hash, @@ -147,7 +147,7 @@ impl GenIndexes { } } - fn next(&mut self) -> usize { + const fn next(&mut self) -> usize { let prev = self.idx; self.idx = prev .wrapping_mul(5) @@ -223,7 +223,7 @@ impl DictInner { } } - fn size(&self) -> DictSize { + const fn size(&self) -> DictSize { DictSize { indices_size: self.indices.len(), entries_size: self.entries.len(), @@ -233,7 +233,7 @@ impl DictInner { } #[inline] - fn should_resize(&self) -> Option { + const fn should_resize(&self) -> Option { if self.filled * 3 > self.indices.len() * 2 { Some(self.used * 2) } else { @@ -735,18 +735,22 @@ impl DictKey for PyObject { fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.to_owned() } + #[inline(always)] fn key_hash(&self, vm: &VirtualMachine) -> PyResult { self.hash(vm) } + #[inline(always)] fn key_is(&self, other: &PyObject) -> bool { self.is(other) } + #[inline(always)] fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult { vm.identical_or_equal(self, other_key) } + #[inline] fn key_as_isize(&self, vm: &VirtualMachine) -> PyResult { self.try_index(vm)?.try_to_primitive(vm) @@ -759,10 +763,12 @@ impl DictKey for Py { fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.to_owned() } + #[inline] fn key_hash(&self, vm: &VirtualMachine) -> PyResult { Ok(self.hash(vm)) } + #[inline(always)] fn key_is(&self, other: &PyObject) -> bool { self.is(other) @@ -777,6 +783,7 @@ impl DictKey for Py { vm.bool_eq(self.as_object(), other_key) } } + #[inline(always)] fn key_as_isize(&self, vm: &VirtualMachine) -> PyResult { self.as_object().key_as_isize(vm) @@ -785,23 +792,28 @@ impl DictKey for Py { impl DictKey for PyStrInterned { type Owned = PyRefExact; + #[inline] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { let zelf: &'static PyStrInterned = unsafe { &*(self as *const _) }; zelf.to_exact() } + #[inline] fn key_hash(&self, vm: &VirtualMachine) -> PyResult { (**self).key_hash(vm) } + #[inline] fn key_is(&self, other: &PyObject) -> bool { (**self).key_is(other) } + #[inline] fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult { (**self).key_eq(vm, other_key) } + #[inline] fn key_as_isize(&self, vm: &VirtualMachine) -> PyResult { (**self).key_as_isize(vm) @@ -810,22 +822,27 @@ impl DictKey for PyStrInterned { impl DictKey for PyExact { type Owned = PyRefExact; + #[inline] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.to_owned() } + #[inline(always)] fn key_hash(&self, vm: &VirtualMachine) -> PyResult { (**self).key_hash(vm) } + #[inline(always)] fn key_is(&self, other: &PyObject) -> bool { (**self).key_is(other) } + #[inline(always)] fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult { (**self).key_eq(vm, other_key) } + #[inline(always)] fn key_as_isize(&self, vm: &VirtualMachine) -> PyResult { (**self).key_as_isize(vm) @@ -838,15 +855,18 @@ impl DictKey for PyExact { /// to index dictionaries. impl DictKey for str { type Owned = String; + #[inline(always)] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.to_owned() } + #[inline] fn key_hash(&self, vm: &VirtualMachine) -> PyResult { // follow a similar route as the hashing of PyStrRef Ok(vm.state.hash_secret.hash_str(self)) } + #[inline(always)] fn key_is(&self, _other: &PyObject) -> bool { // No matter who the other pyobject is, we are never the same thing, since @@ -871,6 +891,7 @@ impl DictKey for str { impl DictKey for String { type Owned = String; + #[inline] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.clone() @@ -895,15 +916,18 @@ impl DictKey for String { impl DictKey for Wtf8 { type Owned = Wtf8Buf; + #[inline(always)] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.to_owned() } + #[inline] fn key_hash(&self, vm: &VirtualMachine) -> PyResult { // follow a similar route as the hashing of PyStrRef Ok(vm.state.hash_secret.hash_bytes(self.as_bytes())) } + #[inline(always)] fn key_is(&self, _other: &PyObject) -> bool { // No matter who the other pyobject is, we are never the same thing, since @@ -928,6 +952,7 @@ impl DictKey for Wtf8 { impl DictKey for Wtf8Buf { type Owned = Wtf8Buf; + #[inline] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.clone() @@ -952,15 +977,18 @@ impl DictKey for Wtf8Buf { impl DictKey for [u8] { type Owned = Vec; + #[inline(always)] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.to_owned() } + #[inline] fn key_hash(&self, vm: &VirtualMachine) -> PyResult { // follow a similar route as the hashing of PyStrRef Ok(vm.state.hash_secret.hash_bytes(self)) } + #[inline(always)] fn key_is(&self, _other: &PyObject) -> bool { // No matter who the other pyobject is, we are never the same thing, since @@ -985,6 +1013,7 @@ impl DictKey for [u8] { impl DictKey for Vec { type Owned = Vec; + #[inline] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.clone() @@ -1009,6 +1038,7 @@ impl DictKey for Vec { impl DictKey for usize { type Owned = usize; + #[inline] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { *self diff --git a/vm/src/function/method.rs b/vm/src/function/method.rs index 6d9b84d10c..ce236b0467 100644 --- a/vm/src/function/method.rs +++ b/vm/src/function/method.rs @@ -115,7 +115,7 @@ impl PyMethodDef { }) } - pub fn to_function(&'static self) -> PyNativeFunction { + pub const fn to_function(&'static self) -> PyNativeFunction { PyNativeFunction { zelf: None, value: self, @@ -131,7 +131,7 @@ impl PyMethodDef { PyMethodDescriptor::new(self, class, ctx) } - pub fn to_bound_method( + pub const fn to_bound_method( &'static self, obj: PyObjectRef, class: &'static Py, @@ -273,7 +273,7 @@ pub struct HeapMethodDef { } impl HeapMethodDef { - pub fn new(method: PyMethodDef) -> Self { + pub const fn new(method: PyMethodDef) -> Self { Self { method } } } diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index cc314cce69..253d8fda63 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -602,7 +602,7 @@ impl PyObjectRef { impl PyObject { #[inline(always)] - fn weak_ref_list(&self) -> Option<&WeakRefList> { + const fn weak_ref_list(&self) -> Option<&WeakRefList> { Some(&self.0.weak_list) } @@ -701,7 +701,7 @@ impl PyObject { } #[inline(always)] - fn instance_dict(&self) -> Option<&InstanceDict> { + const fn instance_dict(&self) -> Option<&InstanceDict> { self.0.dict.as_ref() } @@ -772,7 +772,7 @@ impl PyObject { } #[inline(always)] - pub fn as_raw(&self) -> *const PyObject { + pub const fn as_raw(&self) -> *const PyObject { self } From e38111a18fead8eb089702f1d1166dddc49b4c55 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 28 Jun 2025 11:43:46 +0300 Subject: [PATCH 05/13] Don't convert to str twice --- vm/src/frame.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/src/frame.rs b/vm/src/frame.rs index e32a9e0546..7f10a348f2 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -275,8 +275,8 @@ impl Py { pub fn is_internal_frame(&self) -> bool { let code = self.f_code(); let filename = code.co_filename(); - - filename.as_str().contains("importlib") && filename.as_str().contains("_bootstrap") + let filename_s = filename.as_str(); + filename_s.contains("importlib") && filename_s.contains("_bootstrap") } pub fn next_external_frame(&self, vm: &VirtualMachine) -> Option { @@ -2266,7 +2266,7 @@ impl ExecutingFrame<'_> { #[track_caller] fn fatal(&self, msg: &'static str) -> ! { dbg!(self); - panic!("{}", msg) + panic!("{msg}") } } From 48ecb7faed8356f88c3a740c58dd6ece88be4b9b Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 28 Jun 2025 11:44:06 +0300 Subject: [PATCH 06/13] constify more --- vm/src/bytes_inner.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/src/bytes_inner.rs b/vm/src/bytes_inner.rs index eb62899df7..0aeeb7e54c 100644 --- a/vm/src/bytes_inner.rs +++ b/vm/src/bytes_inner.rs @@ -305,17 +305,17 @@ impl PyBytesInner { } #[inline] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.elements.len() } #[inline] - pub fn capacity(&self) -> usize { + pub const fn capacity(&self) -> usize { self.elements.capacity() } #[inline] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.elements.is_empty() } From 5f59d4c680e4d7c0bd5932b80573ecfae761e106 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 28 Jun 2025 12:26:37 +0300 Subject: [PATCH 07/13] Use match directly instead of if & match! --- vm/src/builtins/set.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/vm/src/builtins/set.rs b/vm/src/builtins/set.rs index 88bbb60a04..e10c2b2d82 100644 --- a/vm/src/builtins/set.rs +++ b/vm/src/builtins/set.rs @@ -233,11 +233,12 @@ impl PySetInner { if !op.eval_ord(self.len().cmp(&other.len())) { return Ok(false); } - let (superset, subset) = if matches!(op, PyComparisonOp::Lt | PyComparisonOp::Le) { - (other, self) - } else { - (self, other) + + let (superset, subset) = match op { + PyComparisonOp::Lt | PyComparisonOp::Le => (other, self), + _ => (self, other), }; + for key in subset.elements() { if !superset.contains(&key, vm)? { return Ok(false); From 62f97aaa00c891c73f8d94e7bdbdbd469b8ca55e Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 28 Jun 2025 12:27:47 +0300 Subject: [PATCH 08/13] Constify more --- vm/src/builtins/float.rs | 20 ++++++++++---------- vm/src/builtins/generator.rs | 5 ++++- vm/src/builtins/int.rs | 10 ++++------ vm/src/builtins/module.rs | 7 +++++-- vm/src/builtins/tuple.rs | 13 ++++++++----- vm/src/coroutine.rs | 6 ++++++ 6 files changed, 37 insertions(+), 24 deletions(-) diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 8a27522045..6c0ba28e55 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -27,7 +27,7 @@ pub struct PyFloat { } impl PyFloat { - pub fn to_f64(&self) -> f64 { + pub const fn to_f64(&self) -> f64 { self.value } } @@ -285,7 +285,7 @@ impl PyFloat { } #[pymethod] - fn __bool__(&self) -> bool { + const fn __bool__(&self) -> bool { self.value != 0.0 } @@ -340,12 +340,12 @@ impl PyFloat { } #[pymethod] - fn __pos__(&self) -> f64 { + const fn __pos__(&self) -> f64 { self.value } #[pymethod] - fn __neg__(&self) -> f64 { + const fn __neg__(&self) -> f64 { -self.value } @@ -457,22 +457,22 @@ impl PyFloat { } #[pymethod] - fn __float__(zelf: PyRef) -> PyRef { + const fn __float__(zelf: PyRef) -> PyRef { zelf } #[pygetset] - fn real(zelf: PyRef) -> PyRef { + const fn real(zelf: PyRef) -> PyRef { zelf } #[pygetset] - fn imag(&self) -> f64 { + const fn imag(&self) -> f64 { 0.0f64 } #[pymethod] - fn conjugate(zelf: PyRef) -> PyRef { + const fn conjugate(zelf: PyRef) -> PyRef { zelf } @@ -576,9 +576,9 @@ impl AsNumber for PyFloat { if vm.is_none(c) { PyFloat::number_op(a, b, float_pow, vm) } else { - Err(vm.new_type_error(String::from( + Err(vm.new_type_error( "pow() 3rd argument not allowed unless all arguments are integers", - ))) + )) } }), negative: Some(|num, vm| { diff --git a/vm/src/builtins/generator.rs b/vm/src/builtins/generator.rs index b46d2cbf04..c362b3d527 100644 --- a/vm/src/builtins/generator.rs +++ b/vm/src/builtins/generator.rs @@ -28,7 +28,7 @@ impl PyPayload for PyGenerator { #[pyclass(with(Py, Unconstructible, IterNext, Iterable))] impl PyGenerator { - pub fn as_coro(&self) -> &Coro { + pub const fn as_coro(&self) -> &Coro { &self.inner } @@ -52,14 +52,17 @@ impl PyGenerator { fn gi_frame(&self, _vm: &VirtualMachine) -> FrameRef { self.inner.frame() } + #[pygetset] fn gi_running(&self, _vm: &VirtualMachine) -> bool { self.inner.running() } + #[pygetset] fn gi_code(&self, _vm: &VirtualMachine) -> PyRef { self.inner.frame().code.clone() } + #[pygetset] fn gi_yieldfrom(&self, _vm: &VirtualMachine) -> Option { self.inner.frame().yield_from_target() diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index c984a6e913..30249fac88 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -259,7 +259,7 @@ impl PyInt { } } - pub fn as_bigint(&self) -> &BigInt { + pub const fn as_bigint(&self) -> &BigInt { &self.value } @@ -671,7 +671,7 @@ impl PyInt { } #[pygetset] - fn imag(&self) -> usize { + const fn imag(&self) -> usize { 0 } @@ -681,7 +681,7 @@ impl PyInt { } #[pygetset] - fn denominator(&self) -> usize { + const fn denominator(&self) -> usize { 1 } @@ -852,9 +852,7 @@ fn try_int_radix(obj: &PyObject, base: u32, vm: &VirtualMachine) -> PyResult { - return Err( - vm.new_type_error("int() can't convert non-string with explicit base".to_owned()) - ); + return Err(vm.new_type_error("int() can't convert non-string with explicit base")); } }); match opt { diff --git a/vm/src/builtins/module.rs b/vm/src/builtins/module.rs index 2912ccc22a..dac98f8d1b 100644 --- a/vm/src/builtins/module.rs +++ b/vm/src/builtins/module.rs @@ -69,18 +69,20 @@ pub struct ModuleInitArgs { impl PyModule { #[allow(clippy::new_without_default)] - pub fn new() -> Self { + pub const fn new() -> Self { Self { def: None, name: None, } } - pub fn from_def(def: &'static PyModuleDef) -> Self { + + pub const fn from_def(def: &'static PyModuleDef) -> Self { Self { def: Some(def), name: Some(def.name), } } + pub fn __init_dict_from_def(vm: &VirtualMachine, module: &Py) { let doc = module.def.unwrap().doc.map(|doc| doc.to_owned()); module.init_dict(module.name.unwrap(), doc, vm); @@ -127,6 +129,7 @@ impl Py { pub fn dict(&self) -> PyDictRef { self.as_object().dict().unwrap() } + // TODO: should be on PyModule, not Py pub(crate) fn init_dict( &self, diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index 8103230b05..e0d66f7fd8 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -154,6 +154,7 @@ impl AsRef<[PyObjectRef]> for PyTuple { impl std::ops::Deref for PyTuple { type Target = [PyObjectRef]; + fn deref(&self) -> &[PyObjectRef] { self.as_slice() } @@ -190,11 +191,11 @@ impl PyTuple { /// Creating a new tuple with given boxed slice. /// NOTE: for usual case, you probably want to use PyTuple::new_ref. /// Calling this function implies trying micro optimization for non-zero-sized tuple. - pub fn new_unchecked(elements: Box<[PyObjectRef]>) -> Self { + pub const fn new_unchecked(elements: Box<[PyObjectRef]>) -> Self { Self { elements } } - pub fn as_slice(&self) -> &[PyObjectRef] { + pub const fn as_slice(&self) -> &[PyObjectRef] { &self.elements } @@ -256,7 +257,7 @@ impl PyTuple { } #[pymethod] - fn __bool__(&self) -> bool { + const fn __bool__(&self) -> bool { !self.elements.is_empty() } @@ -273,12 +274,12 @@ impl PyTuple { #[inline] #[pymethod] - pub fn __len__(&self) -> usize { + pub const fn __len__(&self) -> usize { self.elements.len() } #[inline] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.elements.is_empty() } @@ -553,10 +554,12 @@ impl PyTupleTyped { pub fn as_slice(&self) -> &[T] { unsafe { &*(self.tuple.as_slice() as *const [PyObjectRef] as *const [T]) } } + #[inline] pub fn len(&self) -> usize { self.tuple.len() } + #[inline] pub fn is_empty(&self) -> bool { self.tuple.is_empty() diff --git a/vm/src/coroutine.rs b/vm/src/coroutine.rs index 5ff4202db6..82a31ef80c 100644 --- a/vm/src/coroutine.rs +++ b/vm/src/coroutine.rs @@ -129,6 +129,7 @@ impl Coro { } } } + pub fn throw( &self, jen: &PyObject, @@ -170,18 +171,23 @@ impl Coro { pub fn running(&self) -> bool { self.running.load() } + pub fn closed(&self) -> bool { self.closed.load() } + pub fn frame(&self) -> FrameRef { self.frame.clone() } + pub fn name(&self) -> PyStrRef { self.name.lock().clone() } + pub fn set_name(&self, name: PyStrRef) { *self.name.lock() = name; } + pub fn repr(&self, jen: &PyObject, id: usize, vm: &VirtualMachine) -> String { format!( "<{} object {} at {:#x}>", From 4e6540ff8d0488c15d155aed10c12092547b3504 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 28 Jun 2025 13:59:54 +0300 Subject: [PATCH 09/13] Constify more --- vm/src/builtins/dict.rs | 22 +++++++++++++--------- vm/src/builtins/mappingproxy.rs | 5 ++++- vm/src/builtins/object.rs | 5 +---- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 108b05d27c..7b7df81842 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -691,7 +691,7 @@ pub struct DictIntoIter { } impl DictIntoIter { - pub fn new(dict: PyDictRef) -> DictIntoIter { + pub const fn new(dict: PyDictRef) -> DictIntoIter { DictIntoIter { dict, position: 0 } } } @@ -722,7 +722,7 @@ pub struct DictIter<'a> { } impl<'a> DictIter<'a> { - pub fn new(dict: &'a PyDict) -> Self { + pub const fn new(dict: &'a PyDict) -> Self { DictIter { dict, position: 0 } } } @@ -775,20 +775,23 @@ macro_rules! dict_view { } impl $name { - pub fn new(dict: PyDictRef) -> Self { + pub const fn new(dict: PyDictRef) -> Self { $name { dict } } } impl DictView for $name { type ReverseIter = $reverse_iter_name; + fn dict(&self) -> &PyDictRef { &self.dict } + fn item(vm: &VirtualMachine, key: PyObjectRef, value: PyObjectRef) -> PyObjectRef { #[allow(clippy::redundant_closure_call)] $result_fn(vm, key, value) } + fn __reversed__(&self) -> Self::ReverseIter { $reverse_iter_name::new(self.dict.clone()) } @@ -872,6 +875,7 @@ macro_rules! dict_view { vm.new_tuple((iter, (vm.ctx.new_list(entries),))) } } + impl Unconstructible for $iter_name {} impl SelfIter for $iter_name {} @@ -882,9 +886,9 @@ macro_rules! dict_view { let next = if let IterStatus::Active(dict) = &internal.status { if dict.entries.has_changed_size(&zelf.size) { internal.status = IterStatus::Exhausted; - return Err(vm.new_runtime_error( - "dictionary changed size during iteration".to_owned(), - )); + return Err( + vm.new_runtime_error("dictionary changed size during iteration") + ); } match dict.entries.next_entry(internal.position) { Some((position, key, value)) => { @@ -961,9 +965,9 @@ macro_rules! dict_view { let next = if let IterStatus::Active(dict) = &internal.status { if dict.entries.has_changed_size(&zelf.size) { internal.status = IterStatus::Exhausted; - return Err(vm.new_runtime_error( - "dictionary changed size during iteration".to_owned(), - )); + return Err( + vm.new_runtime_error("dictionary changed size during iteration") + ); } match dict.entries.prev_entry(internal.position) { Some((position, key, value)) => { diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 7ec423965c..24aca1e274 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -151,16 +151,19 @@ impl PyMappingProxy { let obj = self.to_object(vm)?; vm.call_method(&obj, identifier!(vm, items).as_str(), ()) } + #[pymethod] pub fn keys(&self, vm: &VirtualMachine) -> PyResult { let obj = self.to_object(vm)?; vm.call_method(&obj, identifier!(vm, keys).as_str(), ()) } + #[pymethod] pub fn values(&self, vm: &VirtualMachine) -> PyResult { let obj = self.to_object(vm)?; vm.call_method(&obj, identifier!(vm, values).as_str(), ()) } + #[pymethod] pub fn copy(&self, vm: &VirtualMachine) -> PyResult { match &self.mapping { @@ -194,7 +197,7 @@ impl PyMappingProxy { #[pymethod] fn __ior__(&self, _args: PyObjectRef, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error(format!( - "\"'|=' is not supported by {}; use '|' instead\"", + r#""'|=' is not supported by {}; use '|' instead""#, Self::class(&vm.ctx) ))) } diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 1951bbb694..b83d22b34c 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -94,10 +94,7 @@ fn type_slot_names(typ: &Py, vm: &VirtualMachine) -> PyResult Some(l), _n @ super::PyNone => None, - _ => - return Err( - vm.new_type_error("copyreg._slotnames didn't return a list or None".to_owned()) - ), + _ => return Err(vm.new_type_error("copyreg._slotnames didn't return a list or None")), }); Ok(result) } From 43e104ed6b2d4e979dbc20f045c017baacb6f1c0 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 28 Jun 2025 14:10:22 +0300 Subject: [PATCH 10/13] more consts --- vm/src/builtins/builtin_func.rs | 10 +++++++++- vm/src/builtins/genericalias.rs | 2 +- vm/src/builtins/range.rs | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/vm/src/builtins/builtin_func.rs b/vm/src/builtins/builtin_func.rs index 4b3dd47b76..5e276b8976 100644 --- a/vm/src/builtins/builtin_func.rs +++ b/vm/src/builtins/builtin_func.rs @@ -57,7 +57,7 @@ impl PyNativeFunction { self.zelf.as_ref() } - pub fn as_func(&self) -> &'static dyn PyNativeFn { + pub const fn as_func(&self) -> &'static dyn PyNativeFn { self.value.func } } @@ -79,10 +79,12 @@ impl PyNativeFunction { fn __module__(zelf: NativeFunctionOrMethod) -> Option<&'static PyStrInterned> { zelf.0.module } + #[pygetset] fn __name__(zelf: NativeFunctionOrMethod) -> &'static str { zelf.0.value.name } + #[pygetset] fn __qualname__(zelf: NativeFunctionOrMethod, vm: &VirtualMachine) -> PyResult { let zelf = zelf.0; @@ -105,23 +107,28 @@ impl PyNativeFunction { }; Ok(qualname) } + #[pygetset] fn __doc__(zelf: NativeFunctionOrMethod) -> Option<&'static str> { zelf.0.value.doc } + #[pygetset(name = "__self__")] fn __self__(_zelf: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { vm.ctx.none() } + #[pymethod] fn __reduce__(&self) -> &'static str { // TODO: return (getattr, (self.object, self.name)) if this is a method self.value.name } + #[pymethod] fn __reduce_ex__(zelf: PyObjectRef, _ver: PyObjectRef, vm: &VirtualMachine) -> PyResult { vm.call_special_method(&zelf, identifier!(vm, __reduce__), ()) } + #[pygetset] fn __text_signature__(zelf: NativeFunctionOrMethod) -> Option<&'static str> { let doc = zelf.0.value.doc?; @@ -223,6 +230,7 @@ impl Comparable for PyNativeMethod { impl Callable for PyNativeMethod { type Args = FuncArgs; + #[inline] fn call(zelf: &Py, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult { if let Some(zelf) = &zelf.func.zelf { diff --git a/vm/src/builtins/genericalias.rs b/vm/src/builtins/genericalias.rs index fa3877169a..bf10dcdc24 100644 --- a/vm/src/builtins/genericalias.rs +++ b/vm/src/builtins/genericalias.rs @@ -161,7 +161,7 @@ impl PyGenericAlias { } #[pygetset] - fn __unpacked__(&self) -> bool { + const fn __unpacked__(&self) -> bool { self.starred } diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index c9ab63bab4..073f6c7659 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -407,7 +407,7 @@ impl AsSequence for PyRange { PyRange::sequence_downcast(seq) .get(&i.into()) .map(|x| PyInt::from(x).into_ref(&vm.ctx).into()) - .ok_or_else(|| vm.new_index_error("index out of range".to_owned())) + .ok_or_else(|| vm.new_index_error("index out of range")) }), contains: atomic_func!(|seq, needle, vm| { Ok(PyRange::sequence_downcast(seq).contains_inner(needle, vm)) From bd09e55c66eb0f16a24f4e9298773bed55778023 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 28 Jun 2025 14:40:22 +0300 Subject: [PATCH 11/13] Constify more --- common/src/borrow.rs | 3 +++ common/src/boxvec.rs | 16 ++++++++++------ common/src/cformat.rs | 5 +++-- common/src/format.rs | 5 +++-- common/src/hash.rs | 9 +++++---- common/src/int.rs | 2 +- common/src/str.rs | 12 +++++++----- vm/src/builtins/str.rs | 2 ++ 8 files changed, 34 insertions(+), 20 deletions(-) diff --git a/common/src/borrow.rs b/common/src/borrow.rs index ce86d71e27..610084006e 100644 --- a/common/src/borrow.rs +++ b/common/src/borrow.rs @@ -56,6 +56,7 @@ impl<'a, T: ?Sized> BorrowedValue<'a, T> { impl Deref for BorrowedValue<'_, T> { type Target = T; + fn deref(&self) -> &T { match self { Self::Ref(r) => r, @@ -81,6 +82,7 @@ pub enum BorrowedValueMut<'a, T: ?Sized> { WriteLock(PyRwLockWriteGuard<'a, T>), MappedWriteLock(PyMappedRwLockWriteGuard<'a, T>), } + impl_from!('a, T, BorrowedValueMut<'a, T>, RefMut(&'a mut T), MuLock(PyMutexGuard<'a, T>), @@ -108,6 +110,7 @@ impl<'a, T: ?Sized> BorrowedValueMut<'a, T> { impl Deref for BorrowedValueMut<'_, T> { type Target = T; + fn deref(&self) -> &T { match self { Self::RefMut(r) => r, diff --git a/common/src/boxvec.rs b/common/src/boxvec.rs index f5dd622f58..d0cad013db 100644 --- a/common/src/boxvec.rs +++ b/common/src/boxvec.rs @@ -46,25 +46,25 @@ impl BoxVec { } #[inline] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.len } #[inline] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.len() == 0 } #[inline] - pub fn capacity(&self) -> usize { + pub const fn capacity(&self) -> usize { self.xs.len() } - pub fn is_full(&self) -> bool { + pub const fn is_full(&self) -> bool { self.len() == self.capacity() } - pub fn remaining_capacity(&self) -> usize { + pub const fn remaining_capacity(&self) -> usize { self.capacity() - self.len() } @@ -336,6 +336,7 @@ impl BoxVec { impl Deref for BoxVec { type Target = [T]; + #[inline] fn deref(&self) -> &[T] { unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) } @@ -354,6 +355,7 @@ impl DerefMut for BoxVec { impl<'a, T> IntoIterator for &'a BoxVec { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { self.iter() } @@ -363,6 +365,7 @@ impl<'a, T> IntoIterator for &'a BoxVec { impl<'a, T> IntoIterator for &'a mut BoxVec { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; + fn into_iter(self) -> Self::IntoIter { self.iter_mut() } @@ -374,6 +377,7 @@ impl<'a, T> IntoIterator for &'a mut BoxVec { impl IntoIterator for BoxVec { type Item = T; type IntoIter = IntoIter; + fn into_iter(self) -> IntoIter { IntoIter { index: 0, v: self } } @@ -672,7 +676,7 @@ pub struct CapacityError { impl CapacityError { /// Create a new `CapacityError` from `element`. - pub fn new(element: T) -> CapacityError { + pub const fn new(element: T) -> CapacityError { CapacityError { element } } diff --git a/common/src/cformat.rs b/common/src/cformat.rs index e62ffca65e..345f8205fc 100644 --- a/common/src/cformat.rs +++ b/common/src/cformat.rs @@ -76,8 +76,9 @@ pub enum CFloatType { } impl CFloatType { - fn case(self) -> Case { + const fn case(self) -> Case { use CFloatType::*; + match self { ExponentLower | PointDecimalLower | GeneralLower => Case::Lower, ExponentUpper | PointDecimalUpper | GeneralUpper => Case::Upper, @@ -100,7 +101,7 @@ pub enum CFormatType { } impl CFormatType { - pub fn to_char(self) -> char { + pub const fn to_char(self) -> char { match self { CFormatType::Number(x) => x as u8 as char, CFormatType::Float(x) => x as u8 as char, diff --git a/common/src/format.rs b/common/src/format.rs index 4c1ce6c5c2..cd76272201 100644 --- a/common/src/format.rs +++ b/common/src/format.rs @@ -392,7 +392,7 @@ impl FormatSpec { } } - fn get_separator_interval(&self) -> usize { + const fn get_separator_interval(&self) -> usize { match self.format_type { Some(FormatType::Binary | FormatType::Octal | FormatType::Hex(_)) => 4, Some(FormatType::Decimal | FormatType::Number(_) | FormatType::FixedPoint(_)) => 3, @@ -677,7 +677,7 @@ struct AsciiStr<'a> { } impl<'a> AsciiStr<'a> { - fn new(inner: &'a str) -> Self { + const fn new(inner: &'a str) -> Self { Self { inner } } } @@ -690,6 +690,7 @@ impl CharLen for AsciiStr<'_> { impl Deref for AsciiStr<'_> { type Target = str; + fn deref(&self) -> &Self::Target { self.inner } diff --git a/common/src/hash.rs b/common/src/hash.rs index 9fea1e717e..a01629efa2 100644 --- a/common/src/hash.rs +++ b/common/src/hash.rs @@ -32,6 +32,7 @@ pub struct HashSecret { impl BuildHasher for HashSecret { type Hasher = SipHasher24; + fn build_hasher(&self) -> Self::Hasher { SipHasher24::new_with_keys(self.k0, self.k1) } @@ -80,7 +81,7 @@ impl HashSecret { } #[inline] -pub fn hash_pointer(value: usize) -> PyHash { +pub const fn hash_pointer(value: usize) -> PyHash { // TODO: 32bit? let hash = (value >> 4) | value; hash as _ @@ -140,17 +141,17 @@ pub fn hash_bigint(value: &BigInt) -> PyHash { } #[inline] -pub fn hash_usize(data: usize) -> PyHash { +pub const fn hash_usize(data: usize) -> PyHash { fix_sentinel(mod_int(data as i64)) } #[inline(always)] -pub fn fix_sentinel(x: PyHash) -> PyHash { +pub const fn fix_sentinel(x: PyHash) -> PyHash { if x == SENTINEL { -2 } else { x } } #[inline] -pub fn mod_int(value: i64) -> PyHash { +pub const fn mod_int(value: i64) -> PyHash { value % MODULUS as i64 } diff --git a/common/src/int.rs b/common/src/int.rs index 00b5231dff..9ec9e01498 100644 --- a/common/src/int.rs +++ b/common/src/int.rs @@ -128,7 +128,7 @@ pub fn bytes_to_int(lit: &[u8], mut base: u32) -> Option { } #[inline] -pub fn detect_base(c: &u8) -> Option { +pub const fn detect_base(c: &u8) -> Option { let base = match c { b'x' | b'X' => 16, b'b' | b'B' => 2, diff --git a/common/src/str.rs b/common/src/str.rs index 574c86a9f4..39215067d1 100644 --- a/common/src/str.rs +++ b/common/src/str.rs @@ -24,6 +24,7 @@ pub enum StrKind { impl std::ops::BitOr for StrKind { type Output = Self; + fn bitor(self, other: Self) -> Self { use StrKind::*; match (self, other) { @@ -35,11 +36,11 @@ impl std::ops::BitOr for StrKind { } impl StrKind { - pub fn is_ascii(&self) -> bool { + pub const fn is_ascii(&self) -> bool { matches!(self, Self::Ascii) } - pub fn is_utf8(&self) -> bool { + pub const fn is_utf8(&self) -> bool { matches!(self, Self::Ascii | Self::Utf8) } @@ -142,6 +143,7 @@ impl StrLen { fn zero() -> Self { 0usize.into() } + #[inline(always)] fn uncomputed() -> Self { usize::MAX.into() @@ -252,7 +254,7 @@ impl StrData { } #[inline] - pub fn as_wtf8(&self) -> &Wtf8 { + pub const fn as_wtf8(&self) -> &Wtf8 { &self.data } @@ -269,7 +271,7 @@ impl StrData { .then(|| unsafe { AsciiStr::from_ascii_unchecked(self.data.as_bytes()) }) } - pub fn kind(&self) -> StrKind { + pub const fn kind(&self) -> StrKind { self.kind } @@ -469,7 +471,7 @@ pub mod levenshtein { const CASE_COST: usize = 1; const MAX_STRING_SIZE: usize = 40; - fn substitution_cost(mut a: u8, mut b: u8) -> usize { + const fn substitution_cost(mut a: u8, mut b: u8) -> usize { if (a & 31) != (b & 31) { return MOVE_COST; } diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index 1b77109561..87f39ce38b 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -305,9 +305,11 @@ impl PyStrIterator { .builtins_iter_reduce(|x| x.clone().into(), vm) } } + impl Unconstructible for PyStrIterator {} impl SelfIter for PyStrIterator {} + impl IterNext for PyStrIterator { fn next(zelf: &Py, vm: &VirtualMachine) -> PyResult { let mut internal = zelf.internal.lock(); From dc8fc743337045bfa8ba59ce829727914794fa2b Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 28 Jun 2025 15:37:18 +0300 Subject: [PATCH 12/13] Constify more --- common/src/cformat.rs | 31 +++++++++++++++++------- common/src/encodings.rs | 3 +++ common/src/fileutils.rs | 3 ++- common/src/float_ops.rs | 4 ++-- derive-impl/src/pymodule.rs | 4 ++++ derive-impl/src/util.rs | 15 +++++++++--- wtf8/src/core_str_count.rs | 2 +- wtf8/src/lib.rs | 48 +++++++++++++++++++------------------ 8 files changed, 71 insertions(+), 39 deletions(-) diff --git a/common/src/cformat.rs b/common/src/cformat.rs index 345f8205fc..3a4b78f22d 100644 --- a/common/src/cformat.rs +++ b/common/src/cformat.rs @@ -1,6 +1,6 @@ //! Implementation of Printf-Style string formatting //! as per the [Python Docs](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting). -use bitflags::bitflags; +use bitflags::{bitflags, bitflags_match}; use itertools::Itertools; use malachite_bigint::{BigInt, Sign}; use num_traits::Signed; @@ -137,13 +137,12 @@ bitflags! { impl CConversionFlags { #[inline] pub fn sign_string(&self) -> &'static str { - if self.contains(CConversionFlags::SIGN_CHAR) { - "+" - } else if self.contains(CConversionFlags::BLANK_SIGN) { - " " - } else { - "" + bitflags_match!(*self, { + Self::SIGN_CHAR => "+", + Self::BLANK_SIGN => " ", + _ => "", } + ) } } @@ -172,12 +171,15 @@ pub trait FormatChar: Copy + Into + From { impl FormatBuf for String { type Char = char; + fn chars(&self) -> impl Iterator { (**self).chars() } + fn len(&self) -> usize { self.len() } + fn concat(mut self, other: Self) -> Self { self.extend([other]); self @@ -188,6 +190,7 @@ impl FormatChar for char { fn to_char_lossy(self) -> char { self } + fn eq_char(self, c: char) -> bool { self == c } @@ -195,12 +198,15 @@ impl FormatChar for char { impl FormatBuf for Wtf8Buf { type Char = CodePoint; + fn chars(&self) -> impl Iterator { self.code_points() } + fn len(&self) -> usize { (**self).len() } + fn concat(mut self, other: Self) -> Self { self.extend([other]); self @@ -211,6 +217,7 @@ impl FormatChar for CodePoint { fn to_char_lossy(self) -> char { self.to_char_lossy() } + fn eq_char(self, c: char) -> bool { self == c } @@ -218,12 +225,15 @@ impl FormatChar for CodePoint { impl FormatBuf for Vec { type Char = u8; + fn chars(&self) -> impl Iterator { self.iter().copied() } + fn len(&self) -> usize { self.len() } + fn concat(mut self, other: Self) -> Self { self.extend(other); self @@ -234,6 +244,7 @@ impl FormatChar for u8 { fn to_char_lossy(self) -> char { self.into() } + fn eq_char(self, c: char) -> bool { char::from(self) == c } @@ -394,6 +405,7 @@ impl CFormatSpec { Some(&(CFormatQuantity::Amount(1).into())), ) } + pub fn format_bytes(&self, bytes: &[u8]) -> Vec { let bytes = if let Some(CFormatPrecision::Quantity(CFormatQuantity::Amount(precision))) = self.precision @@ -707,12 +719,12 @@ pub enum CFormatPart { impl CFormatPart { #[inline] - pub fn is_specifier(&self) -> bool { + pub const fn is_specifier(&self) -> bool { matches!(self, CFormatPart::Spec { .. }) } #[inline] - pub fn has_key(&self) -> bool { + pub const fn has_key(&self) -> bool { match self { CFormatPart::Spec(s) => s.mapping_key.is_some(), _ => false, @@ -804,6 +816,7 @@ impl CFormatStrOrBytes { impl IntoIterator for CFormatStrOrBytes { type Item = (usize, CFormatPart); type IntoIter = std::vec::IntoIter; + fn into_iter(self) -> Self::IntoIter { self.parts.into_iter() } diff --git a/common/src/encodings.rs b/common/src/encodings.rs index c444e27a5a..9e89f9cdec 100644 --- a/common/src/encodings.rs +++ b/common/src/encodings.rs @@ -121,6 +121,7 @@ impl ops::Add for StrSize { } } } + impl ops::AddAssign for StrSize { fn add_assign(&mut self, rhs: Self) { self.bytes += rhs.bytes; @@ -133,6 +134,7 @@ struct DecodeError<'a> { rest: &'a [u8], err_len: Option, } + /// # Safety /// `v[..valid_up_to]` must be valid utf8 unsafe fn make_decode_err(v: &[u8], valid_up_to: usize, err_len: Option) -> DecodeError<'_> { @@ -152,6 +154,7 @@ enum HandleResult<'a> { reason: &'a str, }, } + fn decode_utf8_compatible( mut ctx: Ctx, errors: &E, diff --git a/common/src/fileutils.rs b/common/src/fileutils.rs index 5a0d380e20..e9a93947c1 100644 --- a/common/src/fileutils.rs +++ b/common/src/fileutils.rs @@ -256,7 +256,7 @@ pub mod windows { } } - fn attributes_to_mode(attr: u32) -> u16 { + const fn attributes_to_mode(attr: u32) -> u16 { let mut m = 0; if attr & FILE_ATTRIBUTE_DIRECTORY != 0 { m |= libc::S_IFDIR | 0o111; // IFEXEC for user,group,other @@ -362,6 +362,7 @@ pub mod windows { } } } + pub fn stat_basic_info_to_stat(info: &FILE_STAT_BASIC_INFORMATION) -> StatStruct { use windows_sys::Win32::Storage::FileSystem; use windows_sys::Win32::System::Ioctl; diff --git a/common/src/float_ops.rs b/common/src/float_ops.rs index b3c90d0ac6..b431e79313 100644 --- a/common/src/float_ops.rs +++ b/common/src/float_ops.rs @@ -2,7 +2,7 @@ use malachite_bigint::{BigInt, ToBigInt}; use num_traits::{Float, Signed, ToPrimitive, Zero}; use std::f64; -pub fn decompose_float(value: f64) -> (f64, i32) { +pub const fn decompose_float(value: f64) -> (f64, i32) { if 0.0 == value { (0.0, 0i32) } else { @@ -63,7 +63,7 @@ pub fn gt_int(value: f64, other_int: &BigInt) -> bool { } } -pub fn div(v1: f64, v2: f64) -> Option { +pub const fn div(v1: f64, v2: f64) -> Option { if v2 != 0.0 { Some(v1 / v2) } else { None } } diff --git a/derive-impl/src/pymodule.rs b/derive-impl/src/pymodule.rs index eb1e4bba9e..9e052cd1ff 100644 --- a/derive-impl/src/pymodule.rs +++ b/derive-impl/src/pymodule.rs @@ -31,6 +31,7 @@ impl std::fmt::Display for AttrName { impl FromStr for AttrName { type Err = String; + fn from_str(s: &str) -> std::result::Result { Ok(match s { "pyfunction" => Self::Function, @@ -404,6 +405,7 @@ struct AttributeItem { impl ContentItem for FunctionItem { type AttrName = AttrName; + fn inner(&self) -> &ContentItemInner { &self.inner } @@ -411,6 +413,7 @@ impl ContentItem for FunctionItem { impl ContentItem for ClassItem { type AttrName = AttrName; + fn inner(&self) -> &ContentItemInner { &self.inner } @@ -418,6 +421,7 @@ impl ContentItem for ClassItem { impl ContentItem for AttributeItem { type AttrName = AttrName; + fn inner(&self) -> &ContentItemInner { &self.inner } diff --git a/derive-impl/src/util.rs b/derive-impl/src/util.rs index 7e0eb96fb0..47a0606f05 100644 --- a/derive-impl/src/util.rs +++ b/derive-impl/src/util.rs @@ -277,6 +277,7 @@ impl ItemMeta for SimpleItemMeta { fn from_inner(inner: ItemMetaInner) -> Self { Self(inner) } + fn inner(&self) -> &ItemMetaInner { &self.0 } @@ -290,6 +291,7 @@ impl ItemMeta for ModuleItemMeta { fn from_inner(inner: ItemMetaInner) -> Self { Self(inner) } + fn inner(&self) -> &ItemMetaInner { &self.0 } @@ -299,6 +301,7 @@ impl ModuleItemMeta { pub fn sub(&self) -> Result { self.inner()._bool("sub") } + pub fn with(&self) -> Result> { let mut withs = Vec::new(); let Some(nested) = self.inner()._optional_list("with")? else { @@ -322,6 +325,7 @@ impl ItemMeta for AttrItemMeta { fn from_inner(inner: ItemMetaInner) -> Self { Self(inner) } + fn inner(&self) -> &ItemMetaInner { &self.0 } @@ -344,6 +348,7 @@ impl ItemMeta for ClassItemMeta { fn from_inner(inner: ItemMetaInner) -> Self { Self(inner) } + fn inner(&self) -> &ItemMetaInner { &self.0 } @@ -446,6 +451,7 @@ impl ItemMeta for ExceptionItemMeta { fn from_inner(inner: ItemMetaInner) -> Self { Self(ClassItemMeta(inner)) } + fn inner(&self) -> &ItemMetaInner { &self.0.0 } @@ -515,8 +521,8 @@ impl AttributeExt for Attribute { let name = self.get_ident().unwrap().to_string(); e.combine(err_span!( self, - "#[{name} = \"...\"] cannot be a name/value, you probably meant \ - #[{name}(name = \"...\")]", + r##"#[{name} = "..."] cannot be a name/value, you probably meant \ + #[{name}(name = "...")]"##, )); e })?; @@ -620,6 +626,7 @@ pub(crate) fn pyexception_ident_and_attrs(item: &syn::Item) -> Result<(&Ident, & pub(crate) trait ErrorVec: Sized { fn into_error(self) -> Option; + fn into_result(self) -> Result<()> { if let Some(error) = self.into_error() { Err(error) @@ -627,6 +634,7 @@ pub(crate) trait ErrorVec: Sized { Ok(()) } } + fn ok_or_push(&mut self, r: Result) -> Option; } @@ -642,6 +650,7 @@ impl ErrorVec for Vec { None } } + fn ok_or_push(&mut self, r: Result) -> Option { match r { Ok(v) => Some(v), @@ -732,7 +741,7 @@ fn func_sig(sig: &Signature) -> String { return Some("$self".to_owned()); } if ident == "vm" { - unreachable!("type &VirtualMachine(`{}`) must be filtered already", ty); + unreachable!("type &VirtualMachine(`{ty}`) must be filtered already"); } Some(ident) }) diff --git a/wtf8/src/core_str_count.rs b/wtf8/src/core_str_count.rs index 30fcd4645f..bbfbc7aa42 100644 --- a/wtf8/src/core_str_count.rs +++ b/wtf8/src/core_str_count.rs @@ -157,6 +157,6 @@ unsafe fn slice_as_chunks_unchecked(slice: &[T]) -> &[[T; N]] unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), new_len) } } -fn unlikely(x: bool) -> bool { +const fn unlikely(x: bool) -> bool { x } diff --git a/wtf8/src/lib.rs b/wtf8/src/lib.rs index 02d3a8723e..c5d84e0579 100644 --- a/wtf8/src/lib.rs +++ b/wtf8/src/lib.rs @@ -91,7 +91,7 @@ impl CodePoint { /// /// `value` must be less than or equal to 0x10FFFF. #[inline] - pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint { + pub const unsafe fn from_u32_unchecked(value: u32) -> CodePoint { CodePoint { value } } @@ -99,7 +99,7 @@ impl CodePoint { /// /// Returns `None` if `value` is above 0x10FFFF. #[inline] - pub fn from_u32(value: u32) -> Option { + pub const fn from_u32(value: u32) -> Option { match value { 0..=0x10FFFF => Some(CodePoint { value }), _ => None, @@ -110,7 +110,7 @@ impl CodePoint { /// /// Since all Unicode scalar values are code points, this always succeeds. #[inline] - pub fn from_char(value: char) -> CodePoint { + pub const fn from_char(value: char) -> CodePoint { CodePoint { value: value as u32, } @@ -118,13 +118,13 @@ impl CodePoint { /// Returns the numeric value of the code point. #[inline] - pub fn to_u32(self) -> u32 { + pub const fn to_u32(self) -> u32 { self.value } /// Returns the numeric value of the code point if it is a leading surrogate. #[inline] - pub fn to_lead_surrogate(self) -> Option { + pub const fn to_lead_surrogate(self) -> Option { match self.value { lead @ 0xD800..=0xDBFF => Some(LeadSurrogate(lead as u16)), _ => None, @@ -133,7 +133,7 @@ impl CodePoint { /// Returns the numeric value of the code point if it is a trailing surrogate. #[inline] - pub fn to_trail_surrogate(self) -> Option { + pub const fn to_trail_surrogate(self) -> Option { match self.value { trail @ 0xDC00..=0xDFFF => Some(TrailSurrogate(trail as u16)), _ => None, @@ -144,7 +144,7 @@ impl CodePoint { /// /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). #[inline] - pub fn to_char(self) -> Option { + pub const fn to_char(self) -> Option { match self.value { 0xD800..=0xDFFF => None, _ => Some(unsafe { char::from_u32_unchecked(self.value) }), @@ -168,7 +168,7 @@ impl CodePoint { unsafe { Wtf8::from_mut_bytes_unchecked(encode_utf8_raw(self.value, dst)) } } - pub fn len_wtf8(&self) -> usize { + pub const fn len_wtf8(&self) -> usize { len_utf8(self.value) } @@ -225,7 +225,7 @@ pub struct LeadSurrogate(u16); pub struct TrailSurrogate(u16); impl LeadSurrogate { - pub fn merge(self, trail: TrailSurrogate) -> char { + pub const fn merge(self, trail: TrailSurrogate) -> char { decode_surrogate_pair(self.0, trail.0) } } @@ -301,7 +301,7 @@ impl Wtf8Buf { /// /// `value` must contain valid WTF-8. #[inline] - pub unsafe fn from_bytes_unchecked(value: Vec) -> Wtf8Buf { + pub const unsafe fn from_bytes_unchecked(value: Vec) -> Wtf8Buf { Wtf8Buf { bytes: value } } @@ -435,7 +435,7 @@ impl Wtf8Buf { /// Returns the number of bytes that this string buffer can hold without reallocating. #[inline] - pub fn capacity(&self) -> usize { + pub const fn capacity(&self) -> usize { self.bytes.capacity() } @@ -643,9 +643,11 @@ impl AsRef for Wtf8 { impl ToOwned for Wtf8 { type Owned = Wtf8Buf; + fn to_owned(&self) -> Self::Owned { self.to_wtf8_buf() } + fn clone_into(&self, buf: &mut Self::Owned) { self.bytes.clone_into(&mut buf.bytes); } @@ -742,7 +744,7 @@ impl Wtf8 { /// /// `value` must contain valid WTF-8. #[inline] - pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { + pub const unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { // SAFETY: start with &[u8], end with fancy &[u8] unsafe { &*(value as *const [u8] as *const Wtf8) } } @@ -752,7 +754,7 @@ impl Wtf8 { /// Since the byte slice is not checked for valid WTF-8, this functions is /// marked unsafe. #[inline] - unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { + const unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { // SAFETY: start with &mut [u8], end with fancy &mut [u8] unsafe { &mut *(value as *mut [u8] as *mut Wtf8) } } @@ -780,12 +782,12 @@ impl Wtf8 { /// Returns the length, in WTF-8 bytes. #[inline] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.bytes.len() } #[inline] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.bytes.is_empty() } @@ -796,7 +798,7 @@ impl Wtf8 { /// /// Panics if `position` is beyond the end of the string. #[inline] - pub fn ascii_byte_at(&self, position: usize) -> u8 { + pub const fn ascii_byte_at(&self, position: usize) -> u8 { match self.bytes[position] { ascii_byte @ 0x00..=0x7F => ascii_byte, _ => 0xFF, @@ -822,7 +824,7 @@ impl Wtf8 { /// Access raw bytes of WTF-8 data #[inline] - pub fn as_bytes(&self) -> &[u8] { + pub const fn as_bytes(&self) -> &[u8] { &self.bytes } @@ -832,7 +834,7 @@ impl Wtf8 { /// /// This does not copy the data. #[inline] - pub fn as_str(&self) -> Result<&str, str::Utf8Error> { + pub const fn as_str(&self) -> Result<&str, str::Utf8Error> { str::from_utf8(&self.bytes) } @@ -887,7 +889,7 @@ impl Wtf8 { } } - pub fn chunks(&self) -> Wtf8Chunks<'_> { + pub const fn chunks(&self) -> Wtf8Chunks<'_> { Wtf8Chunks { wtf8: self } } @@ -973,7 +975,7 @@ impl Wtf8 { } #[inline] - pub fn is_ascii(&self) -> bool { + pub const fn is_ascii(&self) -> bool { self.bytes.is_ascii() } @@ -1226,13 +1228,13 @@ impl ops::Index for Wtf8 { } #[inline] -fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { +const fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { // The first byte is assumed to be 0xED 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F } #[inline] -fn decode_surrogate_pair(lead: u16, trail: u16) -> char { +const fn decode_surrogate_pair(lead: u16, trail: u16) -> char { let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32); unsafe { char::from_u32_unchecked(code_point) } } @@ -1283,7 +1285,7 @@ pub fn check_utf8_boundary(slice: &Wtf8, index: usize) { /// /// `begin` and `end` must be within bounds and on codepoint boundaries. #[inline] -pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { +pub const unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { // SAFETY: memory layout of a &[u8] and &Wtf8 are the same unsafe { let len = end - begin; From 172f299ae161008e5f2ff117e411f5fbc06c926e Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 28 Jun 2025 16:38:02 +0300 Subject: [PATCH 13/13] Don't use bitflags_match macro --- common/src/cformat.rs | 13 +++++++------ vm/src/function/method.rs | 15 +++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/common/src/cformat.rs b/common/src/cformat.rs index 3a4b78f22d..25d9aaca66 100644 --- a/common/src/cformat.rs +++ b/common/src/cformat.rs @@ -1,6 +1,6 @@ //! Implementation of Printf-Style string formatting //! as per the [Python Docs](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting). -use bitflags::{bitflags, bitflags_match}; +use bitflags::bitflags; use itertools::Itertools; use malachite_bigint::{BigInt, Sign}; use num_traits::Signed; @@ -137,12 +137,13 @@ bitflags! { impl CConversionFlags { #[inline] pub fn sign_string(&self) -> &'static str { - bitflags_match!(*self, { - Self::SIGN_CHAR => "+", - Self::BLANK_SIGN => " ", - _ => "", + if self.contains(Self::SIGN_CHAR) { + "+" + } else if self.contains(Self::BLANK_SIGN) { + " " + } else { + "" } - ) } } diff --git a/vm/src/function/method.rs b/vm/src/function/method.rs index ce236b0467..5e109176c5 100644 --- a/vm/src/function/method.rs +++ b/vm/src/function/method.rs @@ -107,12 +107,15 @@ impl PyMethodDef { class: &'static Py, ctx: &Context, ) -> PyObjectRef { - bitflags::bitflags_match!(self.flags, { - PyMethodFlags::METHOD => self.build_method(ctx, class).into(), - PyMethodFlags::CLASS => self.build_classmethod(ctx, class).into(), - PyMethodFlags::STATIC => self.build_staticmethod(ctx, class).into(), - _ => unreachable!(), - }) + if self.flags.contains(PyMethodFlags::METHOD) { + self.build_method(ctx, class).into() + } else if self.flags.contains(PyMethodFlags::CLASS) { + self.build_classmethod(ctx, class).into() + } else if self.flags.contains(PyMethodFlags::STATIC) { + self.build_staticmethod(ctx, class).into() + } else { + unreachable!() + } } pub const fn to_function(&'static self) -> PyNativeFunction {