1use crate::{
5 convert::ToPyResult,
6 function::{BorrowedParam, OwnedParam, RefParam},
7 object::PyThreadingConstraint,
8 Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
9};
10
11#[derive(result_like::OptionLike, is_macro::Is, Debug)]
12pub enum PySetterValue<T = PyObjectRef> {
13 Assign(T),
14 Delete,
15}
16
17impl PySetterValue {
18 pub fn unwrap_or_none(self, vm: &VirtualMachine) -> PyObjectRef {
19 match self {
20 Self::Assign(value) => value,
21 Self::Delete => vm.ctx.none(),
22 }
23 }
24}
25
26trait FromPySetterValue
27where
28 Self: Sized,
29{
30 fn from_setter_value(vm: &VirtualMachine, obj: PySetterValue) -> PyResult<Self>;
31}
32
33impl<T> FromPySetterValue for T
34where
35 T: Sized + TryFromObject,
36{
37 #[inline]
38 fn from_setter_value(vm: &VirtualMachine, obj: PySetterValue) -> PyResult<Self> {
39 let obj = obj.ok_or_else(|| vm.new_type_error("can't delete attribute".to_owned()))?;
40 T::try_from_object(vm, obj)
41 }
42}
43
44impl<T> FromPySetterValue for PySetterValue<T>
45where
46 T: Sized + TryFromObject,
47{
48 #[inline]
49 fn from_setter_value(vm: &VirtualMachine, obj: PySetterValue) -> PyResult<Self> {
50 obj.map(|obj| T::try_from_object(vm, obj)).transpose()
51 }
52}
53
54pub type PyGetterFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult)>;
55pub type PySetterFunc =
56 Box<py_dyn_fn!(dyn Fn(&VirtualMachine, PyObjectRef, PySetterValue) -> PyResult<()>)>;
57
58pub trait IntoPyGetterFunc<T>: PyThreadingConstraint + Sized + 'static {
59 fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult;
60 fn into_getter(self) -> PyGetterFunc {
61 Box::new(move |vm, obj| self.get(obj, vm))
62 }
63}
64
65impl<F, T, R> IntoPyGetterFunc<(OwnedParam<T>, R, VirtualMachine)> for F
66where
67 F: Fn(T, &VirtualMachine) -> R + 'static + Send + Sync,
68 T: TryFromObject,
69 R: ToPyResult,
70{
71 fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
72 let obj = T::try_from_object(vm, obj)?;
73 (self)(obj, vm).to_pyresult(vm)
74 }
75}
76
77impl<F, S, R> IntoPyGetterFunc<(BorrowedParam<S>, R, VirtualMachine)> for F
78where
79 F: Fn(&Py<S>, &VirtualMachine) -> R + 'static + Send + Sync,
80 S: PyPayload,
81 R: ToPyResult,
82{
83 fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
84 let zelf = PyRef::<S>::try_from_object(vm, obj)?;
85 (self)(&zelf, vm).to_pyresult(vm)
86 }
87}
88
89impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R, VirtualMachine)> for F
90where
91 F: Fn(&S, &VirtualMachine) -> R + 'static + Send + Sync,
92 S: PyPayload,
93 R: ToPyResult,
94{
95 fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
96 let zelf = PyRef::<S>::try_from_object(vm, obj)?;
97 (self)(&zelf, vm).to_pyresult(vm)
98 }
99}
100
101impl<F, T, R> IntoPyGetterFunc<(OwnedParam<T>, R)> for F
102where
103 F: Fn(T) -> R + 'static + Send + Sync,
104 T: TryFromObject,
105 R: ToPyResult,
106{
107 fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
108 let obj = T::try_from_object(vm, obj)?;
109 (self)(obj).to_pyresult(vm)
110 }
111}
112
113impl<F, S, R> IntoPyGetterFunc<(BorrowedParam<S>, R)> for F
114where
115 F: Fn(&Py<S>) -> R + 'static + Send + Sync,
116 S: PyPayload,
117 R: ToPyResult,
118{
119 fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
120 let zelf = PyRef::<S>::try_from_object(vm, obj)?;
121 (self)(&zelf).to_pyresult(vm)
122 }
123}
124
125impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R)> for F
126where
127 F: Fn(&S) -> R + 'static + Send + Sync,
128 S: PyPayload,
129 R: ToPyResult,
130{
131 fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
132 let zelf = PyRef::<S>::try_from_object(vm, obj)?;
133 (self)(&zelf).to_pyresult(vm)
134 }
135}
136
137pub trait IntoPyNoResult {
138 fn into_noresult(self) -> PyResult<()>;
139}
140
141impl IntoPyNoResult for () {
142 #[inline]
143 fn into_noresult(self) -> PyResult<()> {
144 Ok(())
145 }
146}
147
148impl IntoPyNoResult for PyResult<()> {
149 #[inline]
150 fn into_noresult(self) -> PyResult<()> {
151 self
152 }
153}
154
155pub trait IntoPySetterFunc<T>: PyThreadingConstraint + Sized + 'static {
156 fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()>;
157 fn into_setter(self) -> PySetterFunc {
158 Box::new(move |vm, obj, value| self.set(obj, value, vm))
159 }
160}
161
162impl<F, T, V, R> IntoPySetterFunc<(OwnedParam<T>, V, R, VirtualMachine)> for F
163where
164 F: Fn(T, V, &VirtualMachine) -> R + 'static + Send + Sync,
165 T: TryFromObject,
166 V: FromPySetterValue,
167 R: IntoPyNoResult,
168{
169 fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
170 let obj = T::try_from_object(vm, obj)?;
171 let value = V::from_setter_value(vm, value)?;
172 (self)(obj, value, vm).into_noresult()
173 }
174}
175
176impl<F, S, V, R> IntoPySetterFunc<(BorrowedParam<S>, V, R, VirtualMachine)> for F
177where
178 F: Fn(&Py<S>, V, &VirtualMachine) -> R + 'static + Send + Sync,
179 S: PyPayload,
180 V: FromPySetterValue,
181 R: IntoPyNoResult,
182{
183 fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
184 let zelf = PyRef::<S>::try_from_object(vm, obj)?;
185 let value = V::from_setter_value(vm, value)?;
186 (self)(&zelf, value, vm).into_noresult()
187 }
188}
189
190impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R, VirtualMachine)> for F
191where
192 F: Fn(&S, V, &VirtualMachine) -> R + 'static + Send + Sync,
193 S: PyPayload,
194 V: FromPySetterValue,
195 R: IntoPyNoResult,
196{
197 fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
198 let zelf = PyRef::<S>::try_from_object(vm, obj)?;
199 let value = V::from_setter_value(vm, value)?;
200 (self)(&zelf, value, vm).into_noresult()
201 }
202}
203
204impl<F, T, V, R> IntoPySetterFunc<(OwnedParam<T>, V, R)> for F
205where
206 F: Fn(T, V) -> R + 'static + Send + Sync,
207 T: TryFromObject,
208 V: FromPySetterValue,
209 R: IntoPyNoResult,
210{
211 fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
212 let obj = T::try_from_object(vm, obj)?;
213 let value = V::from_setter_value(vm, value)?;
214 (self)(obj, value).into_noresult()
215 }
216}
217
218impl<F, S, V, R> IntoPySetterFunc<(BorrowedParam<S>, V, R)> for F
219where
220 F: Fn(&Py<S>, V) -> R + 'static + Send + Sync,
221 S: PyPayload,
222 V: FromPySetterValue,
223 R: IntoPyNoResult,
224{
225 fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
226 let zelf = PyRef::<S>::try_from_object(vm, obj)?;
227 let value = V::from_setter_value(vm, value)?;
228 (self)(&zelf, value).into_noresult()
229 }
230}
231
232impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R)> for F
233where
234 F: Fn(&S, V) -> R + 'static + Send + Sync,
235 S: PyPayload,
236 V: FromPySetterValue,
237 R: IntoPyNoResult,
238{
239 fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
240 let zelf = PyRef::<S>::try_from_object(vm, obj)?;
241 let value = V::from_setter_value(vm, value)?;
242 (self)(&zelf, value).into_noresult()
243 }
244}