Repository: RustPython/RustPython
File: crates/vm/src/builtins/descriptor.rs (Rust)

Code before:
pub struct PySlotWrapper {
    pub typ: &'static Py<PyType>,
    pub name: &'static PyStrInterned,
    pub wrapped: InitFunc,
    pub doc: Option<&'static str>,
}

impl PyPayload for PySlotWrapper {
    fn class(ctx: &Context) -> &'static Py<PyType> {
        ctx.types.wrapper_descriptor_type
    }
}

impl GetDescriptor for PySlotWrapper {
    fn descr_get(
        zelf: PyObjectRef,
        obj: Option<PyObjectRef>,
        _cls: Option<PyObjectRef>,
        vm: &VirtualMachine,
    ) -> PyResult {
        match obj {
            None => Ok(zelf),
            Some(obj) if vm.is_none(&obj) => Ok(zelf),
            Some(obj) => {
                let zelf = zelf.downcast::<Self>().unwrap();
                Ok(PyMethodWrapper { wrapper: zelf, obj }.into_pyobject(vm))
            }
        }
    }
}

impl Callable for PySlotWrapper {
    type Args = FuncArgs;

    fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
        // list.__init__(l, [1,2,3]) form
        let (obj, rest): (PyObjectRef, FuncArgs) = args.bind(vm)?;

        if !obj.fast_isinstance(zelf.typ) {
            return Err(vm.new_type_error(format!(
                "descriptor '{}' requires a '{}' object but received a '{}'",
                zelf.name.as_str(),
                zelf.typ.name(),
                obj.class().name()
            )));
        }

        (zelf.wrapped)(obj, rest, vm)?;
        Ok(vm.ctx.none())
    }
}

Review comment (suggestion):
```suggestion
                        vm.new_type_error("__hash__() takes no arguments (1 given)")
```

Code after:
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)]
#[derive(Debug)]
pub struct PySlotWrapper {
    pub typ: &'static Py<PyType>,
    pub name: &'static PyStrInterned,
    pub wrapped: SlotFunc,
    pub doc: Option<&'static str>,
}

impl PyPayload for PySlotWrapper {
    fn class(ctx: &Context) -> &'static Py<PyType> {
        ctx.types.wrapper_descriptor_type
    }
}