mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
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
This commit is contained in:
1 parent
efde23033e
commit
33ef1b9057
2 files changed
+75
-6
No files matched your search
@@ -446,13 +446,9 @@ impl TryFrom<u8> for Instruction {
|
||||
let instrumented_start = u8::from(Self::InstrumentedEndFor);
|
||||
let instrumented_end = u8::from(Self::InstrumentedLine);
|
||||
|
||||
// No RustPython-only opcodes anymore - all opcodes match CPython 3.14
|
||||
let custom_ops: &[u8] = &[];
|
||||
|
||||
if (cpython_start..=cpython_end).contains(&value)
|
||||
|| value == resume_id
|
||||
|| value == enter_executor_id
|
||||
|| custom_ops.contains(&value)
|
||||
|| (specialized_start..=specialized_end).contains(&value)
|
||||
|| (instrumented_start..=instrumented_end).contains(&value)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
convert::{ToPyException, ToPyObject},
|
||||
frozen,
|
||||
function::OptionalArg,
|
||||
types::{Constructor, Representable},
|
||||
types::{Comparable, Constructor, Hashable, Representable},
|
||||
};
|
||||
use alloc::fmt;
|
||||
use core::{
|
||||
@@ -447,6 +447,75 @@ impl Representable for PyCode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Comparable for PyCode {
|
||||
fn cmp(
|
||||
zelf: &Py<Self>,
|
||||
other: &PyObject,
|
||||
op: crate::types::PyComparisonOp,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<crate::function::PyComparisonValue> {
|
||||
op.eq_only(|| {
|
||||
let other = class_or_notimplemented!(Self, other);
|
||||
let a = &zelf.code;
|
||||
let b = &other.code;
|
||||
let eq = a.obj_name == b.obj_name
|
||||
&& a.arg_count == b.arg_count
|
||||
&& a.posonlyarg_count == b.posonlyarg_count
|
||||
&& a.kwonlyarg_count == b.kwonlyarg_count
|
||||
&& a.flags == b.flags
|
||||
&& a.first_line_number == b.first_line_number
|
||||
&& a.instructions.original_bytes() == b.instructions.original_bytes()
|
||||
&& a.linetable == b.linetable
|
||||
&& a.exceptiontable == b.exceptiontable
|
||||
&& a.names == b.names
|
||||
&& a.varnames == b.varnames
|
||||
&& a.freevars == b.freevars
|
||||
&& a.cellvars == b.cellvars
|
||||
&& {
|
||||
let a_consts: Vec<_> = a.constants.iter().map(|c| c.0.clone()).collect();
|
||||
let b_consts: Vec<_> = b.constants.iter().map(|c| c.0.clone()).collect();
|
||||
if a_consts.len() != b_consts.len() {
|
||||
false
|
||||
} else {
|
||||
let mut eq = true;
|
||||
for (ac, bc) in a_consts.iter().zip(b_consts.iter()) {
|
||||
if !vm.bool_eq(ac, bc)? {
|
||||
eq = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
eq
|
||||
}
|
||||
};
|
||||
Ok(eq.into())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Hashable for PyCode {
|
||||
fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<crate::common::hash::PyHash> {
|
||||
let code = &zelf.code;
|
||||
// Hash a tuple of key attributes, matching CPython's code_hash
|
||||
let tuple = vm.ctx.new_tuple(vec![
|
||||
vm.ctx.new_str(code.obj_name.as_str()).into(),
|
||||
vm.ctx.new_int(code.arg_count).into(),
|
||||
vm.ctx.new_int(code.posonlyarg_count).into(),
|
||||
vm.ctx.new_int(code.kwonlyarg_count).into(),
|
||||
vm.ctx.new_int(code.varnames.len()).into(),
|
||||
vm.ctx.new_int(code.flags.bits()).into(),
|
||||
vm.ctx
|
||||
.new_int(code.first_line_number.map_or(0, |n| n.get()) as i64)
|
||||
.into(),
|
||||
vm.ctx.new_bytes(code.instructions.original_bytes()).into(),
|
||||
{
|
||||
let consts: Vec<_> = code.constants.iter().map(|c| c.0.clone()).collect();
|
||||
vm.ctx.new_tuple(consts).into()
|
||||
},
|
||||
]);
|
||||
tuple.as_object().hash(vm)
|
||||
}
|
||||
}
|
||||
|
||||
// Arguments for code object constructor
|
||||
#[derive(FromArgs)]
|
||||
pub struct PyCodeNewArgs {
|
||||
@@ -595,7 +664,7 @@ impl Constructor for PyCode {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(with(Representable, Constructor), flags(HAS_WEAKREF))]
|
||||
#[pyclass(with(Representable, Constructor, Comparable, Hashable), flags(HAS_WEAKREF))]
|
||||
impl PyCode {
|
||||
#[pygetset]
|
||||
const fn co_posonlyargcount(&self) -> usize {
|
||||
@@ -721,6 +790,10 @@ impl PyCode {
|
||||
vm.ctx.new_bytes(self.code.exceptiontable.to_vec())
|
||||
}
|
||||
|
||||
// co_lnotab is intentionally not implemented.
|
||||
// It was deprecated since 3.12 and scheduled for removal in 3.14.
|
||||
// Use co_lines() or co_linetable instead.
|
||||
|
||||
#[pymethod]
|
||||
pub fn co_lines(&self, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
// TODO: Implement lazy iterator (lineiterator) like CPython for better performance
|
||||
|
||||
Reference in new issue
Block a user