rustpython_vm/builtins/
getset.rs

1/*! Python `attribute` descriptor class. (PyGetSet)
2
3*/
4use super::{PyType, PyTypeRef};
5use crate::{
6    class::PyClassImpl,
7    function::{IntoPyGetterFunc, IntoPySetterFunc, PyGetterFunc, PySetterFunc, PySetterValue},
8    types::{GetDescriptor, Unconstructible},
9    AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
10};
11
12#[pyclass(module = false, name = "getset_descriptor")]
13pub struct PyGetSet {
14    name: String,
15    class: &'static Py<PyType>,
16    getter: Option<PyGetterFunc>,
17    setter: Option<PySetterFunc>,
18    // doc: Option<String>,
19}
20
21impl std::fmt::Debug for PyGetSet {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        write!(
24            f,
25            "PyGetSet {{ name: {}, getter: {}, setter: {} }}",
26            self.name,
27            if self.getter.is_some() {
28                "Some"
29            } else {
30                "None"
31            },
32            if self.setter.is_some() {
33                "Some"
34            } else {
35                "None"
36            },
37        )
38    }
39}
40
41impl PyPayload for PyGetSet {
42    fn class(ctx: &Context) -> &'static Py<PyType> {
43        ctx.types.getset_type
44    }
45}
46
47impl GetDescriptor for PyGetSet {
48    fn descr_get(
49        zelf: PyObjectRef,
50        obj: Option<PyObjectRef>,
51        _cls: Option<PyObjectRef>,
52        vm: &VirtualMachine,
53    ) -> PyResult {
54        let (zelf, obj) = match Self::_check(&zelf, obj, vm) {
55            Some(obj) => obj,
56            None => return Ok(zelf),
57        };
58        if let Some(ref f) = zelf.getter {
59            f(vm, obj)
60        } else {
61            Err(vm.new_attribute_error(format!(
62                "attribute '{}' of '{}' objects is not readable",
63                zelf.name,
64                Self::class(&vm.ctx).name()
65            )))
66        }
67    }
68}
69
70impl PyGetSet {
71    pub fn new(name: String, class: &'static Py<PyType>) -> Self {
72        Self {
73            name,
74            class,
75            getter: None,
76            setter: None,
77        }
78    }
79
80    pub fn with_get<G, X>(mut self, getter: G) -> Self
81    where
82        G: IntoPyGetterFunc<X>,
83    {
84        self.getter = Some(getter.into_getter());
85        self
86    }
87
88    pub fn with_set<S, X>(mut self, setter: S) -> Self
89    where
90        S: IntoPySetterFunc<X>,
91    {
92        self.setter = Some(setter.into_setter());
93        self
94    }
95}
96
97#[pyclass(with(GetDescriptor, Unconstructible))]
98impl PyGetSet {
99    // Descriptor methods
100
101    #[pyslot]
102    fn descr_set(
103        zelf: &PyObject,
104        obj: PyObjectRef,
105        value: PySetterValue<PyObjectRef>,
106        vm: &VirtualMachine,
107    ) -> PyResult<()> {
108        let zelf = zelf.try_to_ref::<Self>(vm)?;
109        if let Some(ref f) = zelf.setter {
110            f(vm, obj, value)
111        } else {
112            Err(vm.new_attribute_error(format!(
113                "attribute '{}' of '{}' objects is not writable",
114                zelf.name,
115                obj.class().name()
116            )))
117        }
118    }
119    #[pymethod]
120    fn __set__(
121        zelf: PyObjectRef,
122        obj: PyObjectRef,
123        value: PyObjectRef,
124        vm: &VirtualMachine,
125    ) -> PyResult<()> {
126        Self::descr_set(&zelf, obj, PySetterValue::Assign(value), vm)
127    }
128    #[pymethod]
129    fn __delete__(zelf: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
130        Self::descr_set(&zelf, obj, PySetterValue::Delete, vm)
131    }
132
133    #[pygetset(magic)]
134    fn name(&self) -> String {
135        self.name.clone()
136    }
137
138    #[pygetset(magic)]
139    fn qualname(&self) -> String {
140        format!("{}.{}", self.class.slot_name(), self.name.clone())
141    }
142
143    #[pygetset(magic)]
144    fn objclass(&self) -> PyTypeRef {
145        self.class.to_owned()
146    }
147}
148impl Unconstructible for PyGetSet {}
149
150pub(crate) fn init(context: &Context) {
151    PyGetSet::extend_class(context, context.types.getset_type);
152}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.