1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::cell::Cell; |
4 | use std::cell::RefCell; |
5 | use std::marker::PhantomData; |
6 | use std::rc::Rc; |
7 | use std::sync::atomic::Ordering; |
8 | use std::sync::Arc; |
9 | use std::sync::Mutex; |
10 | use std::sync::RwLock; |
11 | |
12 | use crate::HasParamSpec; |
13 | use crate::IsA; |
14 | use crate::Object; |
15 | use crate::SendWeakRef; |
16 | use crate::WeakRef; |
17 | |
18 | // rustdoc-stripper-ignore-next |
19 | /// A type that can be used as a property. It covers every type which have an associated `ParamSpec` |
20 | /// (`HasParamSpec`) and some useful types wrapping `HasParamSpec`. |
21 | /// The definition is recursive, so you can nest many `Property`s together. The final `ParamSpec` will |
22 | /// be the one of the innermost type |
23 | pub trait Property { |
24 | type Value: HasParamSpec; |
25 | } |
26 | impl<T: HasParamSpec> Property for T { |
27 | type Value = T; |
28 | } |
29 | impl<T: Property> Property for PhantomData<T> { |
30 | type Value = T::Value; |
31 | } |
32 | impl<T: Property> Property for RefCell<T> { |
33 | type Value = T::Value; |
34 | } |
35 | impl<T: Property> Property for Cell<T> { |
36 | type Value = T::Value; |
37 | } |
38 | impl<T: Property> Property for Mutex<T> { |
39 | type Value = T::Value; |
40 | } |
41 | impl<T: Property> Property for RwLock<T> { |
42 | type Value = T::Value; |
43 | } |
44 | impl<T: Property> Property for once_cell::sync::OnceCell<T> { |
45 | type Value = T::Value; |
46 | } |
47 | impl<T: Property> Property for once_cell::unsync::OnceCell<T> { |
48 | type Value = T::Value; |
49 | } |
50 | impl<T: Property> Property for std::cell::OnceCell<T> { |
51 | type Value = T::Value; |
52 | } |
53 | impl<T: Property> Property for std::sync::OnceLock<T> { |
54 | type Value = T::Value; |
55 | } |
56 | // Handle smart pointers trasparently |
57 | impl<T: Property> Property for Rc<T> { |
58 | type Value = T::Value; |
59 | } |
60 | impl<T: Property> Property for Arc<T> { |
61 | type Value = T::Value; |
62 | } |
63 | impl<T: IsA<Object> + HasParamSpec> Property for WeakRef<T> { |
64 | type Value = Option<T>; |
65 | } |
66 | impl<T: IsA<Object> + HasParamSpec> Property for SendWeakRef<T> { |
67 | type Value = Option<T>; |
68 | } |
69 | |
70 | // rustdoc-stripper-ignore-next |
71 | /// A container type implementing this trait can be read by the default getter generated by the `Props` macro. |
72 | pub trait PropertyGet { |
73 | type Value; |
74 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R; |
75 | } |
76 | |
77 | // rustdoc-stripper-ignore-next |
78 | /// A container type implementing this trait can be written by the default setter generated by the `Props` macro. |
79 | /// It takes a `FnOnce(&mut Self::Value)` so that the caller may access nested fields of a struct |
80 | /// by doing `${Self::Value}.member` |
81 | pub trait PropertySetNested { |
82 | type SetNestedValue; |
83 | fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F); |
84 | } |
85 | |
86 | // rustdoc-stripper-ignore-next |
87 | /// A container type implementing this trait can be written by the default setter generated by the `Props` macro. |
88 | pub trait PropertySet { |
89 | type SetValue; |
90 | fn set(&self, v: Self::SetValue); |
91 | } |
92 | impl<T: PropertySetNested> PropertySet for T { |
93 | type SetValue = T::SetNestedValue; |
94 | fn set(&self, v: Self::SetValue) { |
95 | self.set_nested(|x: &mut ::SetNestedValue| *x = v); |
96 | } |
97 | } |
98 | |
99 | impl<T: HasParamSpec> PropertyGet for T { |
100 | type Value = T; |
101 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
102 | f(self) |
103 | } |
104 | } |
105 | |
106 | impl<T: Copy> PropertyGet for Cell<T> { |
107 | type Value = T; |
108 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
109 | f(&Cell::get(self)) |
110 | } |
111 | } |
112 | impl<T> PropertySet for Cell<T> { |
113 | type SetValue = T; |
114 | fn set(&self, v: Self::SetValue) { |
115 | self.set(val:v); |
116 | } |
117 | } |
118 | impl<T> PropertyGet for RefCell<T> { |
119 | type Value = T; |
120 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
121 | f(&self.borrow()) |
122 | } |
123 | } |
124 | impl<T> PropertySetNested for RefCell<T> { |
125 | type SetNestedValue = T; |
126 | fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) { |
127 | f(&mut self.borrow_mut()); |
128 | } |
129 | } |
130 | |
131 | impl<T> PropertyGet for Mutex<T> { |
132 | type Value = T; |
133 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
134 | f(&self.lock().unwrap()) |
135 | } |
136 | } |
137 | impl<T> PropertySetNested for Mutex<T> { |
138 | type SetNestedValue = T; |
139 | fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) { |
140 | f(&mut self.lock().unwrap()); |
141 | } |
142 | } |
143 | |
144 | impl<T> PropertyGet for RwLock<T> { |
145 | type Value = T; |
146 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
147 | f(&self.read().unwrap()) |
148 | } |
149 | } |
150 | impl<T> PropertySetNested for RwLock<T> { |
151 | type SetNestedValue = T; |
152 | fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) { |
153 | f(&mut self.write().unwrap()); |
154 | } |
155 | } |
156 | |
157 | impl<T> PropertyGet for once_cell::sync::OnceCell<T> { |
158 | type Value = T; |
159 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
160 | f(self.get().unwrap()) |
161 | } |
162 | } |
163 | impl<T> PropertyGet for once_cell::unsync::OnceCell<T> { |
164 | type Value = T; |
165 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
166 | f(self.get().unwrap()) |
167 | } |
168 | } |
169 | impl<T> PropertySet for once_cell::sync::OnceCell<T> { |
170 | type SetValue = T; |
171 | fn set(&self, v: Self::SetValue) { |
172 | // I can't use `unwrap` because I would have to add a `Debug` bound to _v |
173 | if let Err(_v: T) = self.set(v) { |
174 | panic!("can't set value of OnceCell multiple times" ) |
175 | }; |
176 | } |
177 | } |
178 | impl<T> PropertySet for once_cell::unsync::OnceCell<T> { |
179 | type SetValue = T; |
180 | fn set(&self, v: Self::SetValue) { |
181 | // I can't use `unwrap` because I would have to add a `Debug` bound to _v |
182 | if let Err(_v: T) = self.set(v) { |
183 | panic!("can't set value of OnceCell multiple times" ) |
184 | }; |
185 | } |
186 | } |
187 | |
188 | impl<T> PropertyGet for std::cell::OnceCell<T> { |
189 | type Value = T; |
190 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
191 | f(self.get().unwrap()) |
192 | } |
193 | } |
194 | impl<T> PropertyGet for std::sync::OnceLock<T> { |
195 | type Value = T; |
196 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
197 | f(self.get().unwrap()) |
198 | } |
199 | } |
200 | impl<T> PropertySet for std::cell::OnceCell<T> { |
201 | type SetValue = T; |
202 | fn set(&self, v: Self::SetValue) { |
203 | // I can't use `unwrap` because I would have to add a `Debug` bound to _v |
204 | if let Err(_v: T) = self.set(v) { |
205 | panic!("can't set value of OnceCell multiple times" ) |
206 | }; |
207 | } |
208 | } |
209 | impl<T> PropertySet for std::sync::OnceLock<T> { |
210 | type SetValue = T; |
211 | fn set(&self, v: Self::SetValue) { |
212 | // I can't use `unwrap` because I would have to add a `Debug` bound to _v |
213 | if let Err(_v: T) = self.set(v) { |
214 | panic!("can't set value of OnceCell multiple times" ) |
215 | }; |
216 | } |
217 | } |
218 | |
219 | impl<T: IsA<Object>> PropertyGet for WeakRef<T> { |
220 | type Value = Option<T>; |
221 | |
222 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
223 | f(&self.upgrade()) |
224 | } |
225 | } |
226 | impl<T: IsA<Object>> PropertySet for WeakRef<T> { |
227 | type SetValue = Option<T>; |
228 | |
229 | fn set(&self, v: Self::SetValue) { |
230 | self.set(obj:v.as_ref()) |
231 | } |
232 | } |
233 | impl<T: IsA<Object>> PropertyGet for SendWeakRef<T> { |
234 | type Value = Option<T>; |
235 | |
236 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
237 | f(&self.upgrade()) |
238 | } |
239 | } |
240 | impl<T: IsA<Object>> PropertySet for SendWeakRef<T> { |
241 | type SetValue = Option<T>; |
242 | |
243 | fn set(&self, v: Self::SetValue) { |
244 | WeakRef::set(self, obj:v.as_ref()); |
245 | } |
246 | } |
247 | |
248 | // Smart pointers wrapping a `PropertyRead`/`PropertyWrite` |
249 | impl<T: PropertyGet> PropertyGet for Rc<T> { |
250 | type Value = T::Value; |
251 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
252 | (**self).get(f) |
253 | } |
254 | } |
255 | impl<T: PropertySetNested> PropertySetNested for Rc<T> { |
256 | type SetNestedValue = T::SetNestedValue; |
257 | fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) { |
258 | (**self).set_nested(f) |
259 | } |
260 | } |
261 | |
262 | impl<T: PropertyGet> PropertyGet for Arc<T> { |
263 | type Value = T::Value; |
264 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
265 | (**self).get(f) |
266 | } |
267 | } |
268 | impl<T: PropertySetNested> PropertySetNested for Arc<T> { |
269 | type SetNestedValue = T::SetNestedValue; |
270 | fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) { |
271 | (**self).set_nested(f) |
272 | } |
273 | } |
274 | |
275 | macro_rules! impl_atomic { |
276 | ($atomic:ty, $valuety:ty) => { |
277 | impl Property for $atomic { |
278 | type Value = $valuety; |
279 | } |
280 | impl PropertyGet for $atomic { |
281 | type Value = $valuety; |
282 | fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R { |
283 | f(&self.load(Ordering::Acquire)) |
284 | } |
285 | } |
286 | impl PropertySet for $atomic { |
287 | type SetValue = $valuety; |
288 | fn set(&self, v: Self::SetValue) { |
289 | self.store(v, Ordering::Release); |
290 | } |
291 | } |
292 | }; |
293 | } |
294 | |
295 | impl_atomic!(std::sync::atomic::AtomicBool, bool); |
296 | impl_atomic!(std::sync::atomic::AtomicI8, i8); |
297 | impl_atomic!(std::sync::atomic::AtomicI32, i32); |
298 | #[cfg (target_has_atomic = "64" )] |
299 | impl_atomic!(std::sync::atomic::AtomicI64, i64); |
300 | impl_atomic!(std::sync::atomic::AtomicU8, u8); |
301 | impl_atomic!(std::sync::atomic::AtomicU32, u32); |
302 | #[cfg (target_has_atomic = "64" )] |
303 | impl_atomic!(std::sync::atomic::AtomicU64, u64); |
304 | |