rustpython_vm/builtins/
staticmethod.rs1use super::{PyStr, PyType, PyTypeRef};
2use crate::{
3 class::PyClassImpl,
4 common::lock::PyMutex,
5 function::FuncArgs,
6 types::{Callable, Constructor, GetDescriptor, Initializer, Representable},
7 Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
8};
9
10#[pyclass(module = false, name = "staticmethod", traverse)]
11#[derive(Debug)]
12pub struct PyStaticMethod {
13 pub callable: PyMutex<PyObjectRef>,
14}
15
16impl PyPayload for PyStaticMethod {
17 fn class(ctx: &Context) -> &'static Py<PyType> {
18 ctx.types.staticmethod_type
19 }
20}
21
22impl GetDescriptor for PyStaticMethod {
23 fn descr_get(
24 zelf: PyObjectRef,
25 obj: Option<PyObjectRef>,
26 _cls: Option<PyObjectRef>,
27 vm: &VirtualMachine,
28 ) -> PyResult {
29 let (zelf, _obj) = Self::_unwrap(&zelf, obj, vm)?;
30 let x = Ok(zelf.callable.lock().clone());
31 x
32 }
33}
34
35impl From<PyObjectRef> for PyStaticMethod {
36 fn from(callable: PyObjectRef) -> Self {
37 Self {
38 callable: PyMutex::new(callable),
39 }
40 }
41}
42
43impl Constructor for PyStaticMethod {
44 type Args = PyObjectRef;
45
46 fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult {
47 let doc = callable.get_attr("__doc__", vm);
48
49 let result = PyStaticMethod {
50 callable: PyMutex::new(callable),
51 }
52 .into_ref_with_type(vm, cls)?;
53 let obj = PyObjectRef::from(result);
54
55 if let Ok(doc) = doc {
56 obj.set_attr("__doc__", doc, vm)?;
57 }
58
59 Ok(obj)
60 }
61}
62
63impl PyStaticMethod {
64 pub fn new_ref(callable: PyObjectRef, ctx: &Context) -> PyRef<Self> {
65 PyRef::new_ref(
66 Self {
67 callable: PyMutex::new(callable),
68 },
69 ctx.types.staticmethod_type.to_owned(),
70 None,
71 )
72 }
73}
74
75impl Initializer for PyStaticMethod {
76 type Args = PyObjectRef;
77
78 fn init(zelf: PyRef<Self>, callable: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
79 *zelf.callable.lock() = callable;
80 Ok(())
81 }
82}
83
84#[pyclass(
85 with(Callable, GetDescriptor, Constructor, Initializer, Representable),
86 flags(BASETYPE, HAS_DICT)
87)]
88impl PyStaticMethod {
89 #[pygetset(magic)]
90 fn func(&self) -> PyObjectRef {
91 self.callable.lock().clone()
92 }
93
94 #[pygetset(magic)]
95 fn wrapped(&self) -> PyObjectRef {
96 self.callable.lock().clone()
97 }
98
99 #[pygetset(magic)]
100 fn module(&self, vm: &VirtualMachine) -> PyResult {
101 self.callable.lock().get_attr("__module__", vm)
102 }
103
104 #[pygetset(magic)]
105 fn qualname(&self, vm: &VirtualMachine) -> PyResult {
106 self.callable.lock().get_attr("__qualname__", vm)
107 }
108
109 #[pygetset(magic)]
110 fn name(&self, vm: &VirtualMachine) -> PyResult {
111 self.callable.lock().get_attr("__name__", vm)
112 }
113
114 #[pygetset(magic)]
115 fn annotations(&self, vm: &VirtualMachine) -> PyResult {
116 self.callable.lock().get_attr("__annotations__", vm)
117 }
118
119 #[pygetset(magic)]
120 fn isabstractmethod(&self, vm: &VirtualMachine) -> PyObjectRef {
121 match vm.get_attribute_opt(self.callable.lock().clone(), "__isabstractmethod__") {
122 Ok(Some(is_abstract)) => is_abstract,
123 _ => vm.ctx.new_bool(false).into(),
124 }
125 }
126
127 #[pygetset(magic, setter)]
128 fn set_isabstractmethod(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
129 self.callable
130 .lock()
131 .set_attr("__isabstractmethod__", value, vm)?;
132 Ok(())
133 }
134}
135
136impl Callable for PyStaticMethod {
137 type Args = FuncArgs;
138 #[inline]
139 fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
140 let callable = zelf.callable.lock().clone();
141 callable.call(args, vm)
142 }
143}
144
145impl Representable for PyStaticMethod {
146 fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
147 let callable = zelf.callable.lock().repr(vm).unwrap();
148 let class = Self::class(&vm.ctx);
149
150 match (
151 class
152 .qualname(vm)
153 .downcast_ref::<PyStr>()
154 .map(|n| n.as_str()),
155 class.module(vm).downcast_ref::<PyStr>().map(|m| m.as_str()),
156 ) {
157 (None, _) => Err(vm.new_type_error("Unknown qualified name".into())),
158 (Some(qualname), Some(module)) if module != "builtins" => {
159 Ok(format!("<{module}.{qualname}({callable})>"))
160 }
161 _ => Ok(format!("<{}({})>", class.slot_name(), callable)),
162 }
163 }
164}
165
166pub fn init(context: &Context) {
167 PyStaticMethod::extend_class(context, context.types.staticmethod_type);
168}