mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
__hash__ to slot_wrapper (#6480)
This commit is contained in:
@@ -6,7 +6,8 @@ use crate::{
|
||||
common::hash::PyHash,
|
||||
function::{FuncArgs, PyMethodDef, PyMethodFlags, PySetterValue},
|
||||
types::{
|
||||
Callable, Comparable, GetDescriptor, Hashable, InitFunc, PyComparisonOp, Representable,
|
||||
Callable, Comparable, GetDescriptor, HashFunc, Hashable, InitFunc, PyComparisonOp,
|
||||
Representable,
|
||||
},
|
||||
};
|
||||
use rustpython_common::lock::PyRwLock;
|
||||
@@ -391,6 +392,44 @@ pub fn init(ctx: &Context) {
|
||||
|
||||
// PySlotWrapper - wrapper_descriptor
|
||||
|
||||
/// Type-erased slot function - mirrors CPython's void* d_wrapped
|
||||
/// Each variant knows how to call the wrapped function with proper types
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum SlotFunc {
|
||||
Init(InitFunc),
|
||||
Hash(HashFunc),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SlotFunc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
SlotFunc::Init(_) => write!(f, "SlotFunc::Init(...)"),
|
||||
SlotFunc::Hash(_) => write!(f, "SlotFunc::Hash(...)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SlotFunc {
|
||||
/// Call the wrapped slot function with proper type handling
|
||||
pub fn call(&self, obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
match self {
|
||||
SlotFunc::Init(func) => {
|
||||
func(obj, args, vm)?;
|
||||
Ok(vm.ctx.none())
|
||||
}
|
||||
SlotFunc::Hash(func) => {
|
||||
if !args.args.is_empty() || !args.kwargs.is_empty() {
|
||||
return Err(
|
||||
vm.new_type_error("__hash__() takes no arguments (1 given)".to_owned())
|
||||
);
|
||||
}
|
||||
let hash = func(&obj, vm)?;
|
||||
Ok(vm.ctx.new_int(hash).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// wrapper_descriptor: wraps a slot function as a Python method
|
||||
// = PyWrapperDescrObject
|
||||
#[pyclass(name = "wrapper_descriptor", module = false)]
|
||||
@@ -398,7 +437,7 @@ pub fn init(ctx: &Context) {
|
||||
pub struct PySlotWrapper {
|
||||
pub typ: &'static Py<PyType>,
|
||||
pub name: &'static PyStrInterned,
|
||||
pub wrapped: InitFunc,
|
||||
pub wrapped: SlotFunc,
|
||||
pub doc: Option<&'static str>,
|
||||
}
|
||||
|
||||
@@ -430,7 +469,7 @@ impl Callable for PySlotWrapper {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
// list.__init__(l, [1,2,3]) form
|
||||
// list.__init__(l, [1,2,3]) form - first arg is self
|
||||
let (obj, rest): (PyObjectRef, FuncArgs) = args.bind(vm)?;
|
||||
|
||||
if !obj.fast_isinstance(zelf.typ) {
|
||||
@@ -442,8 +481,7 @@ impl Callable for PySlotWrapper {
|
||||
)));
|
||||
}
|
||||
|
||||
(zelf.wrapped)(obj, rest, vm)?;
|
||||
Ok(vm.ctx.none())
|
||||
zelf.wrapped.call(obj, rest, vm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,8 +544,7 @@ impl Callable for PyMethodWrapper {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
(zelf.wrapper.wrapped)(zelf.obj.clone(), args, vm)?;
|
||||
Ok(vm.ctx.none())
|
||||
zelf.wrapper.wrapped.call(zelf.obj.clone(), args, vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
use crate::{
|
||||
PyPayload,
|
||||
builtins::{PyBaseObject, PyType, PyTypeRef, descriptor::PySlotWrapper},
|
||||
builtins::{
|
||||
PyBaseObject, PyType, PyTypeRef,
|
||||
descriptor::{PySlotWrapper, SlotFunc},
|
||||
},
|
||||
function::PyMethodDef,
|
||||
object::Py,
|
||||
types::{PyTypeFlags, PyTypeSlots, hash_not_implemented},
|
||||
@@ -143,13 +146,30 @@ pub trait PyClassImpl: PyClassDef {
|
||||
let wrapper = PySlotWrapper {
|
||||
typ: class,
|
||||
name: ctx.intern_str("__init__"),
|
||||
wrapped: init_func,
|
||||
wrapped: SlotFunc::Init(init_func),
|
||||
doc: Some("Initialize self. See help(type(self)) for accurate signature."),
|
||||
};
|
||||
class.set_attr(init_name, wrapper.into_ref(ctx).into());
|
||||
}
|
||||
}
|
||||
|
||||
// Add __hash__ slot wrapper if slot exists and not already in dict
|
||||
// Note: hash_not_implemented is handled separately (sets __hash__ = None)
|
||||
if let Some(hash_func) = class.slots.hash.load()
|
||||
&& hash_func as usize != hash_not_implemented as usize
|
||||
{
|
||||
let hash_name = identifier!(ctx, __hash__);
|
||||
if !class.attributes.read().contains_key(hash_name) {
|
||||
let wrapper = PySlotWrapper {
|
||||
typ: class,
|
||||
name: ctx.intern_str("__hash__"),
|
||||
wrapped: SlotFunc::Hash(hash_func),
|
||||
doc: Some("Return hash(self)."),
|
||||
};
|
||||
class.set_attr(hash_name, wrapper.into_ref(ctx).into());
|
||||
}
|
||||
}
|
||||
|
||||
if class.slots.hash.load().map_or(0, |h| h as usize) == hash_not_implemented as usize {
|
||||
class.set_attr(ctx.names.__hash__, ctx.none.clone().into());
|
||||
}
|
||||
|
||||
@@ -1098,11 +1098,7 @@ pub trait Hashable: PyPayload {
|
||||
Self::hash(zelf, vm)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[pymethod]
|
||||
fn __hash__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyHash> {
|
||||
Self::slot_hash(&zelf, vm)
|
||||
}
|
||||
// __hash__ is now exposed via SlotFunc::Hash wrapper in extend_class()
|
||||
|
||||
fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyHash>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user