3
3
*/
4
4
use super :: objtype:: PyClassRef ;
5
5
use crate :: function:: OptionalArg ;
6
- use crate :: pyobject:: { PyClassImpl , PyContext , PyObjectRef , PyRef , PyResult , PyValue } ;
6
+ use crate :: pyobject:: {
7
+ IntoPyObject , PyClassImpl , PyContext , PyObjectRef , PyRef , PyResult , PyValue , TryFromObject ,
8
+ } ;
7
9
use crate :: slots:: PyBuiltinDescriptor ;
8
10
use crate :: vm:: VirtualMachine ;
9
11
10
- pub type PyGetter = dyn Fn ( PyObjectRef , & VirtualMachine ) -> PyResult ;
11
- pub type PySetter = dyn Fn ( PyObjectRef , PyObjectRef , & VirtualMachine ) -> PyResult < ( ) > ;
12
+ pub type PyGetterFunc = Box < dyn Fn ( & VirtualMachine , PyObjectRef ) -> PyResult > ;
13
+ pub type PySetterFunc = Box < dyn Fn ( & VirtualMachine , PyObjectRef , PyObjectRef ) -> PyResult < ( ) > > ;
14
+
15
+ pub trait IntoPyGetterFunc < T , R > {
16
+ fn into_getter ( self ) -> PyGetterFunc ;
17
+ }
18
+
19
+ impl < F , T , R > IntoPyGetterFunc < T , R > for F
20
+ where
21
+ F : Fn ( T , & VirtualMachine ) -> R + ' static ,
22
+ T : TryFromObject ,
23
+ R : IntoPyObject ,
24
+ {
25
+ fn into_getter ( self ) -> PyGetterFunc {
26
+ Box :: new ( move |vm, obj| {
27
+ let obj = T :: try_from_object ( vm, obj) ?;
28
+ ( self ) ( obj, vm) . into_pyobject ( vm)
29
+ } )
30
+ }
31
+ }
32
+
33
+ pub trait IntoPySetterFunc < T , V > {
34
+ fn into_setter ( self ) -> PySetterFunc ;
35
+ }
36
+
37
+ impl < F , T , V > IntoPySetterFunc < T , V > for F
38
+ where
39
+ F : Fn ( T , V , & VirtualMachine ) -> PyResult < ( ) > + ' static ,
40
+ T : TryFromObject ,
41
+ V : TryFromObject ,
42
+ {
43
+ fn into_setter ( self ) -> PySetterFunc {
44
+ Box :: new ( move |vm, obj, value| {
45
+ let obj = T :: try_from_object ( vm, obj) ?;
46
+ let value = V :: try_from_object ( vm, value) ?;
47
+ ( self ) ( obj, value, vm)
48
+ } )
49
+ }
50
+ }
12
51
13
52
#[ pyclass]
14
53
pub struct PyGetSet {
15
- // name: String,
16
- getter : Box < PyGetter > ,
17
- setter : Box < PySetter > ,
54
+ name : String ,
55
+ getter : Option < PyGetterFunc > ,
56
+ setter : Option < PySetterFunc > ,
18
57
// doc: Option<String>,
19
58
}
20
59
21
60
impl std:: fmt:: Debug for PyGetSet {
22
61
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
23
62
write ! (
24
63
f,
25
- "PyGetSet {{ getter: {:p}, setter: {:p} }}" ,
26
- self . getter, self . setter
64
+ "PyGetSet {{ name: {}, getter: {}, setter: {} }}" ,
65
+ self . name,
66
+ if self . getter. is_some( ) {
67
+ "Some"
68
+ } else {
69
+ "None"
70
+ } ,
71
+ if self . setter. is_some( ) {
72
+ "Some"
73
+ } else {
74
+ "None"
75
+ } ,
27
76
)
28
77
}
29
78
}
@@ -43,15 +92,39 @@ impl PyBuiltinDescriptor for PyGetSet {
43
92
_cls : OptionalArg < PyObjectRef > ,
44
93
vm : & VirtualMachine ,
45
94
) -> PyResult {
46
- ( zelf. getter ) ( obj, vm)
95
+ if let Some ( ref f) = zelf. getter {
96
+ f ( vm, obj)
97
+ } else {
98
+ Err ( vm. new_attribute_error ( format ! (
99
+ "attribute '{}' of '{}' objects is not readable" ,
100
+ zelf. name,
101
+ Self :: class( vm) . name
102
+ ) ) )
103
+ }
47
104
}
48
105
}
49
106
50
107
impl PyGetSet {
51
- pub fn new ( getter : & ' static PyGetter , setter : & ' static PySetter ) -> Self {
108
+ pub fn with_get < G , T , R > ( name : String , getter : G ) -> Self
109
+ where
110
+ G : IntoPyGetterFunc < T , R > ,
111
+ {
112
+ Self {
113
+ name,
114
+ getter : Some ( getter. into_getter ( ) ) ,
115
+ setter : None ,
116
+ }
117
+ }
118
+
119
+ pub fn with_get_set < G , S , GT , GR , ST , SV > ( name : String , getter : G , setter : S ) -> Self
120
+ where
121
+ G : IntoPyGetterFunc < GT , GR > ,
122
+ S : IntoPySetterFunc < ST , SV > ,
123
+ {
52
124
Self {
53
- getter : Box :: new ( getter) ,
54
- setter : Box :: new ( setter) ,
125
+ name,
126
+ getter : Some ( getter. into_getter ( ) ) ,
127
+ setter : Some ( setter. into_setter ( ) ) ,
55
128
}
56
129
}
57
130
}
@@ -62,7 +135,15 @@ impl PyGetSet {
62
135
63
136
#[ pymethod( magic) ]
64
137
fn set ( & self , obj : PyObjectRef , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
65
- ( self . setter ) ( obj, value, vm)
138
+ if let Some ( ref f) = self . setter {
139
+ f ( vm, obj, value)
140
+ } else {
141
+ Err ( vm. new_attribute_error ( format ! (
142
+ "attribute '{}' of '{}' objects is not writable" ,
143
+ self . name,
144
+ Self :: class( vm) . name
145
+ ) ) )
146
+ }
66
147
}
67
148
}
68
149
0 commit comments