2
2
3
3
*/
4
4
5
- use crate :: function:: IntoPyNativeFunc ;
6
- use crate :: function:: OptionalArg ;
7
- use crate :: obj:: objstr:: PyStringRef ;
5
+ use crate :: function:: { IntoPyNativeFunc , OptionalArg , PyFuncArgs } ;
8
6
use crate :: obj:: objtype:: PyClassRef ;
9
7
use crate :: pyobject:: {
10
- IdProtocol , PyContext , PyObject , PyObjectRef , PyRef , PyResult , PyValue , TypeProtocol ,
8
+ IdProtocol , PyClassImpl , PyContext , PyObject , PyObjectRef , PyRef , PyResult , PyValue ,
9
+ TypeProtocol ,
11
10
} ;
12
11
use crate :: vm:: VirtualMachine ;
13
12
14
- /// Read-only property, doesn't have __set__ or __delete__
13
+ // Read-only property, doesn't have __set__ or __delete__
14
+ #[ pyclass]
15
15
#[ derive( Debug ) ]
16
16
pub struct PyReadOnlyProperty {
17
17
getter : PyObjectRef ,
@@ -25,27 +25,62 @@ impl PyValue for PyReadOnlyProperty {
25
25
26
26
pub type PyReadOnlyPropertyRef = PyRef < PyReadOnlyProperty > ;
27
27
28
- impl PyReadOnlyPropertyRef {
28
+ #[ pyimpl]
29
+ impl PyReadOnlyProperty {
30
+ #[ pymethod( name = "__get__" ) ]
29
31
fn get (
30
- self ,
32
+ zelf : PyRef < Self > ,
31
33
obj : PyObjectRef ,
32
34
_owner : OptionalArg < PyClassRef > ,
33
35
vm : & VirtualMachine ,
34
36
) -> PyResult {
35
37
if obj. is ( vm. ctx . none . as_object ( ) ) {
36
- Ok ( self . into_object ( ) )
38
+ Ok ( zelf . into_object ( ) )
37
39
} else {
38
- vm. invoke ( self . getter . clone ( ) , obj)
40
+ vm. invoke ( zelf . getter . clone ( ) , obj)
39
41
}
40
42
}
41
43
}
42
44
43
- /// Fully fledged property
45
+ /// Property attribute.
46
+ ///
47
+ /// fget
48
+ /// function to be used for getting an attribute value
49
+ /// fset
50
+ /// function to be used for setting an attribute value
51
+ /// fdel
52
+ /// function to be used for del'ing an attribute
53
+ /// doc
54
+ /// docstring
55
+ ///
56
+ /// Typical use is to define a managed attribute x:
57
+ ///
58
+ /// class C(object):
59
+ /// def getx(self): return self._x
60
+ /// def setx(self, value): self._x = value
61
+ /// def delx(self): del self._x
62
+ /// x = property(getx, setx, delx, "I'm the 'x' property.")
63
+ ///
64
+ /// Decorators make defining new properties or modifying existing ones easy:
65
+ ///
66
+ /// class C(object):
67
+ /// @property
68
+ /// def x(self):
69
+ /// "I am the 'x' property."
70
+ /// return self._x
71
+ /// @x.setter
72
+ /// def x(self, value):
73
+ /// self._x = value
74
+ /// @x.deleter
75
+ /// def x(self):
76
+ /// del self._x
77
+ #[ pyclass]
44
78
#[ derive( Debug ) ]
45
79
pub struct PyProperty {
46
80
getter : Option < PyObjectRef > ,
47
81
setter : Option < PyObjectRef > ,
48
82
deleter : Option < PyObjectRef > ,
83
+ doc : Option < PyObjectRef > ,
49
84
}
50
85
51
86
impl PyValue for PyProperty {
@@ -56,43 +91,61 @@ impl PyValue for PyProperty {
56
91
57
92
pub type PyPropertyRef = PyRef < PyProperty > ;
58
93
59
- impl PyPropertyRef {
94
+ #[ pyimpl]
95
+ impl PyProperty {
96
+ #[ pymethod( name = "__new__" ) ]
60
97
fn new_property (
61
98
cls : PyClassRef ,
62
- fget : OptionalArg < PyObjectRef > ,
63
- fset : OptionalArg < PyObjectRef > ,
64
- fdel : OptionalArg < PyObjectRef > ,
65
- _doc : OptionalArg < PyStringRef > ,
99
+ args : PyFuncArgs ,
66
100
vm : & VirtualMachine ,
67
101
) -> PyResult < PyPropertyRef > {
102
+ arg_check ! (
103
+ vm,
104
+ args,
105
+ required = [ ] ,
106
+ optional = [ ( fget, None ) , ( fset, None ) , ( fdel, None ) , ( doc, None ) ]
107
+ ) ;
108
+
109
+ fn into_option ( vm : & VirtualMachine , arg : Option < & PyObjectRef > ) -> Option < PyObjectRef > {
110
+ arg. and_then ( |arg| {
111
+ if vm. ctx . none ( ) . is ( arg) {
112
+ None
113
+ } else {
114
+ Some ( arg. clone ( ) )
115
+ }
116
+ } )
117
+ }
118
+
68
119
PyProperty {
69
- getter : fget. into_option ( ) ,
70
- setter : fset. into_option ( ) ,
71
- deleter : fdel. into_option ( ) ,
120
+ getter : into_option ( vm, fget) ,
121
+ setter : into_option ( vm, fset) ,
122
+ deleter : into_option ( vm, fdel) ,
123
+ doc : into_option ( vm, doc) ,
72
124
}
73
125
. into_ref_with_type ( vm, cls)
74
126
}
75
127
76
128
// Descriptor methods
77
129
78
130
// specialised version that doesn't check for None
79
- pub ( crate ) fn instance_binding_get ( self , obj : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
131
+ pub ( crate ) fn instance_binding_get ( & self , obj : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
80
132
if let Some ( getter) = self . getter . as_ref ( ) {
81
133
vm. invoke ( getter. clone ( ) , obj)
82
134
} else {
83
135
Err ( vm. new_attribute_error ( "unreadable attribute" . to_string ( ) ) )
84
136
}
85
137
}
86
138
139
+ #[ pymethod( name = "__get__" ) ]
87
140
fn get (
88
- self ,
141
+ zelf : PyRef < Self > ,
89
142
obj : PyObjectRef ,
90
143
_owner : OptionalArg < PyClassRef > ,
91
144
vm : & VirtualMachine ,
92
145
) -> PyResult {
93
- if let Some ( getter) = self . getter . as_ref ( ) {
146
+ if let Some ( getter) = zelf . getter . as_ref ( ) {
94
147
if obj. is ( vm. ctx . none . as_object ( ) ) {
95
- Ok ( self . into_object ( ) )
148
+ Ok ( zelf . into_object ( ) )
96
149
} else {
97
150
vm. invoke ( getter. clone ( ) , obj)
98
151
}
@@ -101,15 +154,17 @@ impl PyPropertyRef {
101
154
}
102
155
}
103
156
104
- fn set ( self , obj : PyObjectRef , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
157
+ #[ pymethod( name = "__set__" ) ]
158
+ fn set ( & self , obj : PyObjectRef , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
105
159
if let Some ( setter) = self . setter . as_ref ( ) {
106
160
vm. invoke ( setter. clone ( ) , vec ! [ obj, value] )
107
161
} else {
108
162
Err ( vm. new_attribute_error ( "can't set attribute" . to_string ( ) ) )
109
163
}
110
164
}
111
165
112
- fn delete ( self , obj : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
166
+ #[ pymethod( name = "__delete__" ) ]
167
+ fn delete ( & self , obj : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
113
168
if let Some ( deleter) = self . deleter . as_ref ( ) {
114
169
vm. invoke ( deleter. clone ( ) , obj)
115
170
} else {
@@ -119,45 +174,66 @@ impl PyPropertyRef {
119
174
120
175
// Access functions
121
176
122
- fn fget ( self , _vm : & VirtualMachine ) -> Option < PyObjectRef > {
177
+ #[ pyproperty]
178
+ fn fget ( & self , _vm : & VirtualMachine ) -> Option < PyObjectRef > {
123
179
self . getter . clone ( )
124
180
}
125
181
126
- fn fset ( self , _vm : & VirtualMachine ) -> Option < PyObjectRef > {
182
+ #[ pyproperty]
183
+ fn fset ( & self , _vm : & VirtualMachine ) -> Option < PyObjectRef > {
127
184
self . setter . clone ( )
128
185
}
129
186
130
- fn fdel ( self , _vm : & VirtualMachine ) -> Option < PyObjectRef > {
187
+ #[ pyproperty]
188
+ fn fdel ( & self , _vm : & VirtualMachine ) -> Option < PyObjectRef > {
131
189
self . deleter . clone ( )
132
190
}
133
191
134
192
// Python builder functions
135
193
136
- fn getter ( self , getter : Option < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < Self > {
194
+ #[ pymethod]
195
+ fn getter (
196
+ zelf : PyRef < Self > ,
197
+ getter : Option < PyObjectRef > ,
198
+ vm : & VirtualMachine ,
199
+ ) -> PyResult < PyPropertyRef > {
137
200
PyProperty {
138
- getter : getter. or_else ( || self . getter . clone ( ) ) ,
139
- setter : self . setter . clone ( ) ,
140
- deleter : self . deleter . clone ( ) ,
201
+ getter : getter. or_else ( || zelf. getter . clone ( ) ) ,
202
+ setter : zelf. setter . clone ( ) ,
203
+ deleter : zelf. deleter . clone ( ) ,
204
+ doc : None ,
141
205
}
142
- . into_ref_with_type ( vm, TypeProtocol :: class ( & self ) )
206
+ . into_ref_with_type ( vm, TypeProtocol :: class ( & zelf ) )
143
207
}
144
208
145
- fn setter ( self , setter : Option < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < Self > {
209
+ #[ pymethod]
210
+ fn setter (
211
+ zelf : PyRef < Self > ,
212
+ setter : Option < PyObjectRef > ,
213
+ vm : & VirtualMachine ,
214
+ ) -> PyResult < PyPropertyRef > {
146
215
PyProperty {
147
- getter : self . getter . clone ( ) ,
148
- setter : setter. or_else ( || self . setter . clone ( ) ) ,
149
- deleter : self . deleter . clone ( ) ,
216
+ getter : zelf. getter . clone ( ) ,
217
+ setter : setter. or_else ( || zelf. setter . clone ( ) ) ,
218
+ deleter : zelf. deleter . clone ( ) ,
219
+ doc : None ,
150
220
}
151
- . into_ref_with_type ( vm, TypeProtocol :: class ( & self ) )
221
+ . into_ref_with_type ( vm, TypeProtocol :: class ( & zelf ) )
152
222
}
153
223
154
- fn deleter ( self , deleter : Option < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < Self > {
224
+ #[ pymethod]
225
+ fn deleter (
226
+ zelf : PyRef < Self > ,
227
+ deleter : Option < PyObjectRef > ,
228
+ vm : & VirtualMachine ,
229
+ ) -> PyResult < PyPropertyRef > {
155
230
PyProperty {
156
- getter : self . getter . clone ( ) ,
157
- setter : self . setter . clone ( ) ,
158
- deleter : deleter. or_else ( || self . deleter . clone ( ) ) ,
231
+ getter : zelf. getter . clone ( ) ,
232
+ setter : zelf. setter . clone ( ) ,
233
+ deleter : deleter. or_else ( || zelf. deleter . clone ( ) ) ,
234
+ doc : None ,
159
235
}
160
- . into_ref_with_type ( vm, TypeProtocol :: class ( & self ) )
236
+ . into_ref_with_type ( vm, TypeProtocol :: class ( & zelf ) )
161
237
}
162
238
}
163
239
@@ -200,6 +276,7 @@ impl<'a> PropertyBuilder<'a> {
200
276
getter : self . getter . clone ( ) ,
201
277
setter : self . setter . clone ( ) ,
202
278
deleter : None ,
279
+ doc : None ,
203
280
} ;
204
281
205
282
PyObject :: new ( payload, self . ctx . property_type ( ) , None )
@@ -216,52 +293,6 @@ impl<'a> PropertyBuilder<'a> {
216
293
}
217
294
218
295
pub fn init ( context : & PyContext ) {
219
- extend_class ! ( context, & context. readonly_property_type, {
220
- "__get__" => context. new_rustfunc( PyReadOnlyPropertyRef :: get) ,
221
- } ) ;
222
-
223
- let property_doc =
224
- "Property attribute.\n \n \
225
- fget\n \
226
- function to be used for getting an attribute value\n \
227
- fset\n \
228
- function to be used for setting an attribute value\n \
229
- fdel\n \
230
- function to be used for del\' ing an attribute\n \
231
- doc\n \
232
- docstring\n \n \
233
- Typical use is to define a managed attribute x:\n \n \
234
- class C(object):\n \
235
- def getx(self): return self._x\n \
236
- def setx(self, value): self._x = value\n \
237
- def delx(self): del self._x\n \
238
- x = property(getx, setx, delx, \" I\' m the \' x\' property.\" )\n \n \
239
- Decorators make defining new properties or modifying existing ones easy:\n \n \
240
- class C(object):\n \
241
- @property\n \
242
- def x(self):\n \" I am the \' x\' property.\" \n \
243
- return self._x\n \
244
- @x.setter\n \
245
- def x(self, value):\n \
246
- self._x = value\n \
247
- @x.deleter\n \
248
- def x(self):\n \
249
- del self._x";
250
-
251
- extend_class ! ( context, & context. property_type, {
252
- "__new__" => context. new_rustfunc( PyPropertyRef :: new_property) ,
253
- "__doc__" => context. new_str( property_doc. to_string( ) ) ,
254
-
255
- "__get__" => context. new_rustfunc( PyPropertyRef :: get) ,
256
- "__set__" => context. new_rustfunc( PyPropertyRef :: set) ,
257
- "__delete__" => context. new_rustfunc( PyPropertyRef :: delete) ,
258
-
259
- "fget" => context. new_property( PyPropertyRef :: fget) ,
260
- "fset" => context. new_property( PyPropertyRef :: fset) ,
261
- "fdel" => context. new_property( PyPropertyRef :: fdel) ,
262
-
263
- "getter" => context. new_rustfunc( PyPropertyRef :: getter) ,
264
- "setter" => context. new_rustfunc( PyPropertyRef :: setter) ,
265
- "deleter" => context. new_rustfunc( PyPropertyRef :: deleter) ,
266
- } ) ;
296
+ PyReadOnlyProperty :: extend_class ( context, & context. readonly_property_type ) ;
297
+ PyProperty :: extend_class ( context, & context. property_type ) ;
267
298
}
0 commit comments