1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// Take a look at the license at the top of the repository in the LICENSE file.

use std::cell::Cell;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::RwLock;

use crate::prelude::*;
use crate::Object;
use crate::SendWeakRef;
use crate::WeakRef;

// rustdoc-stripper-ignore-next
/// A type that can be used as a property. It covers every type which have an associated `ParamSpec`
/// (`HasParamSpec`) and some useful types wrapping `HasParamSpec`.
/// The definition is recursive, so you can nest many `Property`s together. The final `ParamSpec` will
/// be the one of the innermost type
pub trait Property {
    type Value: HasParamSpec;
}
impl<T: HasParamSpec> Property for T {
    type Value = T;
}
impl<T: Property> Property for PhantomData<T> {
    type Value = T::Value;
}
impl<T: Property> Property for RefCell<T> {
    type Value = T::Value;
}
impl<T: Property> Property for Cell<T> {
    type Value = T::Value;
}
impl<T: Property> Property for Mutex<T> {
    type Value = T::Value;
}
impl<T: Property> Property for RwLock<T> {
    type Value = T::Value;
}
impl<T: Property> Property for std::cell::OnceCell<T> {
    type Value = T::Value;
}
impl<T: Property> Property for std::sync::OnceLock<T> {
    type Value = T::Value;
}
// Handle smart pointers transparently
impl<T: Property> Property for Rc<T> {
    type Value = T::Value;
}
impl<T: Property> Property for Arc<T> {
    type Value = T::Value;
}
impl<T: IsA<Object> + HasParamSpec> Property for WeakRef<T> {
    type Value = Option<T>;
}
impl<T: IsA<Object> + HasParamSpec> Property for SendWeakRef<T> {
    type Value = Option<T>;
}

// rustdoc-stripper-ignore-next
/// A container type implementing this trait can be read by the default getter generated by the `Props` macro.
pub trait PropertyGet {
    type Value;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R;
}

// rustdoc-stripper-ignore-next
/// A container type implementing this trait can be written by the default setter generated by the `Props` macro.
/// It takes a `FnOnce(&mut Self::Value)` so that the caller may access nested fields of a struct
/// by doing `${Self::Value}.member`
pub trait PropertySetNested {
    type SetNestedValue;
    fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F);
}

// rustdoc-stripper-ignore-next
/// A container type implementing this trait can be written by the default setter generated by the `Props` macro.
pub trait PropertySet {
    type SetValue;
    fn set(&self, v: Self::SetValue);
}
impl<T: PropertySetNested> PropertySet for T {
    type SetValue = T::SetNestedValue;
    fn set(&self, v: Self::SetValue) {
        self.set_nested(|x| *x = v);
    }
}

impl<T: HasParamSpec> PropertyGet for T {
    type Value = T;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        f(self)
    }
}

impl<T: Copy> PropertyGet for Cell<T> {
    type Value = T;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        f(&Cell::get(self))
    }
}
impl<T> PropertySet for Cell<T> {
    type SetValue = T;
    fn set(&self, v: Self::SetValue) {
        self.set(v);
    }
}
impl<T> PropertyGet for RefCell<T> {
    type Value = T;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        f(&self.borrow())
    }
}
impl<T> PropertySetNested for RefCell<T> {
    type SetNestedValue = T;
    fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) {
        f(&mut self.borrow_mut());
    }
}

impl<T> PropertyGet for Mutex<T> {
    type Value = T;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        f(&self.lock().unwrap())
    }
}
impl<T> PropertySetNested for Mutex<T> {
    type SetNestedValue = T;
    fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) {
        f(&mut self.lock().unwrap());
    }
}

impl<T> PropertyGet for RwLock<T> {
    type Value = T;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        f(&self.read().unwrap())
    }
}
impl<T> PropertySetNested for RwLock<T> {
    type SetNestedValue = T;
    fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) {
        f(&mut self.write().unwrap());
    }
}

impl<T> PropertyGet for std::cell::OnceCell<T> {
    type Value = T;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        f(self.get().unwrap())
    }
}
impl<T> PropertyGet for std::sync::OnceLock<T> {
    type Value = T;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        f(self.get().unwrap())
    }
}
impl<T> PropertySet for std::cell::OnceCell<T> {
    type SetValue = T;
    fn set(&self, v: Self::SetValue) {
        // I can't use `unwrap` because I would have to add a `Debug` bound to _v
        if let Err(_v) = self.set(v) {
            panic!("can't set value of OnceCell multiple times")
        };
    }
}
impl<T> PropertySet for std::sync::OnceLock<T> {
    type SetValue = T;
    fn set(&self, v: Self::SetValue) {
        // I can't use `unwrap` because I would have to add a `Debug` bound to _v
        if let Err(_v) = self.set(v) {
            panic!("can't set value of OnceCell multiple times")
        };
    }
}

impl<T: IsA<Object>> PropertyGet for WeakRef<T> {
    type Value = Option<T>;

    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        f(&self.upgrade())
    }
}
impl<T: IsA<Object>> PropertySet for WeakRef<T> {
    type SetValue = Option<T>;

    fn set(&self, v: Self::SetValue) {
        self.set(v.as_ref())
    }
}
impl<T: IsA<Object>> PropertyGet for SendWeakRef<T> {
    type Value = Option<T>;

    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        f(&self.upgrade())
    }
}
impl<T: IsA<Object>> PropertySet for SendWeakRef<T> {
    type SetValue = Option<T>;

    fn set(&self, v: Self::SetValue) {
        WeakRef::set(self, v.as_ref());
    }
}

// Smart pointers wrapping a `PropertyRead`/`PropertyWrite`
impl<T: PropertyGet> PropertyGet for Rc<T> {
    type Value = T::Value;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        (**self).get(f)
    }
}
impl<T: PropertySetNested> PropertySetNested for Rc<T> {
    type SetNestedValue = T::SetNestedValue;
    fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) {
        (**self).set_nested(f)
    }
}

impl<T: PropertyGet> PropertyGet for Arc<T> {
    type Value = T::Value;
    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
        (**self).get(f)
    }
}
impl<T: PropertySetNested> PropertySetNested for Arc<T> {
    type SetNestedValue = T::SetNestedValue;
    fn set_nested<F: FnOnce(&mut Self::SetNestedValue)>(&self, f: F) {
        (**self).set_nested(f)
    }
}

macro_rules! impl_atomic {
    ($atomic:ty, $valuety:ty) => {
        impl Property for $atomic {
            type Value = $valuety;
        }
        impl PropertyGet for $atomic {
            type Value = $valuety;
            fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
                f(&self.load(Ordering::Acquire))
            }
        }
        impl PropertySet for $atomic {
            type SetValue = $valuety;
            fn set(&self, v: Self::SetValue) {
                self.store(v, Ordering::Release);
            }
        }
    };
}

impl_atomic!(std::sync::atomic::AtomicBool, bool);
impl_atomic!(std::sync::atomic::AtomicI8, i8);
impl_atomic!(std::sync::atomic::AtomicI32, i32);
#[cfg(target_has_atomic = "64")]
impl_atomic!(std::sync::atomic::AtomicI64, i64);
impl_atomic!(std::sync::atomic::AtomicU8, u8);
impl_atomic!(std::sync::atomic::AtomicU32, u32);
#[cfg(target_has_atomic = "64")]
impl_atomic!(std::sync::atomic::AtomicU64, u64);