glib/
property.rs

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