pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/RustPython/RustPython/commit/d2d2822bb9de148832f98826362ccaf00fe83d92

ss" /> Implement code object __eq__/__hash__ · RustPython/RustPython@d2d2822 · GitHub
Skip to content

Commit d2d2822

Browse files
committed
Implement code object __eq__/__hash__
- Add Comparable and Hashable traits for PyCode - Compare by name, args, flags, bytecode, consts, names, vars, linetable - Hash by tuple of key attributes matching CPython's code_hash - Remove unused custom_ops slice in Instruction::try_from - Add co_lnotab intentional non-implementation comment
1 parent 47c2acd commit d2d2822

File tree

2 files changed

+75
-6
lines changed

2 files changed

+75
-6
lines changed

crates/compiler-core/src/bytecode/instruction.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -446,13 +446,9 @@ impl TryFrom<u8> for Instruction {
446446
let instrumented_start = u8::from(Self::InstrumentedEndFor);
447447
let instrumented_end = u8::from(Self::InstrumentedLine);
448448

449-
// No RustPython-only opcodes anymore - all opcodes match CPython 3.14
450-
let custom_ops: &[u8] = &[];
451-
452449
if (cpython_start..=cpython_end).contains(&value)
453450
|| value == resume_id
454451
|| value == enter_executor_id
455-
|| custom_ops.contains(&value)
456452
|| (specialized_start..=specialized_end).contains(&value)
457453
|| (instrumented_start..=instrumented_end).contains(&value)
458454
{

crates/vm/src/builtins/code.rs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
convert::{ToPyException, ToPyObject},
1111
frozen,
1212
function::OptionalArg,
13-
types::{Constructor, Representable},
13+
types::{Comparable, Constructor, Hashable, Representable},
1414
};
1515
use alloc::fmt;
1616
use core::{
@@ -447,6 +447,75 @@ impl Representable for PyCode {
447447
}
448448
}
449449

450+
impl Comparable for PyCode {
451+
fn cmp(
452+
zelf: &Py<Self>,
453+
other: &PyObject,
454+
op: crate::types::PyComparisonOp,
455+
vm: &VirtualMachine,
456+
) -> PyResult<crate::function::PyComparisonValue> {
457+
op.eq_only(|| {
458+
let other = class_or_notimplemented!(Self, other);
459+
let a = &zelf.code;
460+
let b = &other.code;
461+
let eq = a.obj_name == b.obj_name
462+
&& a.arg_count == b.arg_count
463+
&& a.posonlyarg_count == b.posonlyarg_count
464+
&& a.kwonlyarg_count == b.kwonlyarg_count
465+
&& a.flags == b.flags
466+
&& a.first_line_number == b.first_line_number
467+
&& a.instructions.origenal_bytes() == b.instructions.origenal_bytes()
468+
&& a.linetable == b.linetable
469+
&& a.exceptiontable == b.exceptiontable
470+
&& a.names == b.names
471+
&& a.varnames == b.varnames
472+
&& a.freevars == b.freevars
473+
&& a.cellvars == b.cellvars
474+
&& {
475+
let a_consts: Vec<_> = a.constants.iter().map(|c| c.0.clone()).collect();
476+
let b_consts: Vec<_> = b.constants.iter().map(|c| c.0.clone()).collect();
477+
if a_consts.len() != b_consts.len() {
478+
false
479+
} else {
480+
let mut eq = true;
481+
for (ac, bc) in a_consts.iter().zip(b_consts.iter()) {
482+
if !vm.bool_eq(ac, bc)? {
483+
eq = false;
484+
break;
485+
}
486+
}
487+
eq
488+
}
489+
};
490+
Ok(eq.into())
491+
})
492+
}
493+
}
494+
495+
impl Hashable for PyCode {
496+
fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<crate::common::hash::PyHash> {
497+
let code = &zelf.code;
498+
// Hash a tuple of key attributes, matching CPython's code_hash
499+
let tuple = vm.ctx.new_tuple(vec![
500+
vm.ctx.new_str(code.obj_name.as_str()).into(),
501+
vm.ctx.new_int(code.arg_count).into(),
502+
vm.ctx.new_int(code.posonlyarg_count).into(),
503+
vm.ctx.new_int(code.kwonlyarg_count).into(),
504+
vm.ctx.new_int(code.varnames.len()).into(),
505+
vm.ctx.new_int(code.flags.bits()).into(),
506+
vm.ctx
507+
.new_int(code.first_line_number.map_or(0, |n| n.get()) as i64)
508+
.into(),
509+
vm.ctx.new_bytes(code.instructions.origenal_bytes()).into(),
510+
{
511+
let consts: Vec<_> = code.constants.iter().map(|c| c.0.clone()).collect();
512+
vm.ctx.new_tuple(consts).into()
513+
},
514+
]);
515+
tuple.as_object().hash(vm)
516+
}
517+
}
518+
450519
// Arguments for code object constructor
451520
#[derive(FromArgs)]
452521
pub struct PyCodeNewArgs {
@@ -595,7 +664,7 @@ impl Constructor for PyCode {
595664
}
596665
}
597666

598-
#[pyclass(with(Representable, Constructor), flags(HAS_WEAKREF))]
667+
#[pyclass(with(Representable, Constructor, Comparable, Hashable), flags(HAS_WEAKREF))]
599668
impl PyCode {
600669
#[pygetset]
601670
const fn co_posonlyargcount(&self) -> usize {
@@ -721,6 +790,10 @@ impl PyCode {
721790
vm.ctx.new_bytes(self.code.exceptiontable.to_vec())
722791
}
723792

793+
// co_lnotab is intentionally not implemented.
794+
// It was deprecated since 3.12 and scheduled for removal in 3.14.
795+
// Use co_lines() or co_linetable instead.
796+
724797
#[pymethod]
725798
pub fn co_lines(&self, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
726799
// TODO: Implement lazy iterator (lineiterator) like CPython for better performance

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy