wayland_commons/
user_data.rs1use once_cell::sync::OnceCell;
4
5use std::any::Any;
6use std::mem::ManuallyDrop;
7use std::thread::{self, ThreadId};
8
9use self::list::AppendList;
10
11#[derive(Debug)]
14pub struct UserData {
15 inner: OnceCell<UserDataInner>,
16}
17
18#[derive(Debug)]
19enum UserDataInner {
20 ThreadSafe(Box<dyn Any + Send + Sync + 'static>),
21 NonThreadSafe(Box<ManuallyDrop<dyn Any + 'static>>, ThreadId),
22}
23
24unsafe impl Send for UserData {}
27unsafe impl Sync for UserData {}
28
29impl UserData {
30 pub const fn new() -> UserData {
32 UserData { inner: OnceCell::new() }
33 }
34
35 pub fn set<T: Any + 'static, F: FnOnce() -> T>(&self, f: F) {
40 self.inner.get_or_init(|| {
41 UserDataInner::NonThreadSafe(Box::new(ManuallyDrop::new(f())), thread::current().id())
42 });
43 }
44
45 pub fn set_threadsafe<T: Any + Send + Sync + 'static, F: FnOnce() -> T>(&self, f: F) {
50 self.inner.get_or_init(|| UserDataInner::ThreadSafe(Box::new(f())));
51 }
52
53 pub fn get<T: 'static>(&self) -> Option<&T> {
61 match self.inner.get() {
62 Some(&UserDataInner::ThreadSafe(ref val)) => <dyn Any>::downcast_ref::<T>(&**val),
63 Some(&UserDataInner::NonThreadSafe(ref val, threadid)) => {
64 if threadid == thread::current().id() {
66 <dyn Any>::downcast_ref::<T>(&***val)
67 } else {
68 None
69 }
70 }
71 None => None,
72 }
73 }
74}
75
76impl Drop for UserData {
77 fn drop(&mut self) {
78 if let Some(&mut UserDataInner::NonThreadSafe(ref mut val, threadid)) = self.inner.get_mut()
80 {
81 if threadid == thread::current().id() {
82 unsafe {
83 ManuallyDrop::drop(&mut **val);
84 }
85 }
86 }
87 }
88}
89
90#[derive(Debug)]
93pub struct UserDataMap {
94 list: AppendList<UserData>,
95}
96
97impl UserDataMap {
98 pub fn new() -> UserDataMap {
100 UserDataMap { list: AppendList::new() }
101 }
102
103 pub fn get<T: 'static>(&self) -> Option<&T> {
108 for user_data in &self.list {
109 if let Some(val) = user_data.get::<T>() {
110 return Some(val);
111 }
112 }
113 None
114 }
115
116 pub fn insert_if_missing<T: 'static, F: FnOnce() -> T>(&self, init: F) -> bool {
126 if self.get::<T>().is_some() {
127 return false;
128 }
129 let data = UserData::new();
130 data.set(init);
131 self.list.append(data);
132 true
133 }
134
135 pub fn insert_if_missing_threadsafe<T: Send + Sync + 'static, F: FnOnce() -> T>(
144 &self,
145 init: F,
146 ) -> bool {
147 if self.get::<T>().is_some() {
148 return false;
149 }
150 let data = UserData::new();
151 data.set_threadsafe(init);
152 self.list.append(data);
153 true
154 }
155}
156
157impl Default for UserDataMap {
158 fn default() -> UserDataMap {
159 UserDataMap::new()
160 }
161}
162
163mod list {
164 use std::sync::atomic::{AtomicPtr, Ordering};
173 use std::{mem, ptr};
174
175 type NodePtr<T> = Option<Box<Node<T>>>;
176
177 #[derive(Debug)]
178 struct Node<T> {
179 value: T,
180 next: AppendList<T>,
181 }
182
183 #[derive(Debug)]
184 pub struct AppendList<T>(AtomicPtr<Node<T>>);
185
186 impl<T> AppendList<T> {
187 fn node_into_raw(ptr: NodePtr<T>) -> *mut Node<T> {
188 match ptr {
189 Some(b) => Box::into_raw(b),
190 None => ptr::null_mut(),
191 }
192 }
193 unsafe fn node_from_raw(ptr: *mut Node<T>) -> NodePtr<T> {
194 if ptr.is_null() {
195 None
196 } else {
197 Some(Box::from_raw(ptr))
198 }
199 }
200
201 fn new_internal(ptr: NodePtr<T>) -> Self {
202 AppendList(AtomicPtr::new(Self::node_into_raw(ptr)))
203 }
204
205 pub fn new() -> Self {
206 Self::new_internal(None)
207 }
208
209 pub fn append(&self, value: T) {
210 self.append_list(AppendList::new_internal(Some(Box::new(Node {
211 value,
212 next: AppendList::new(),
213 }))));
214 }
215
216 unsafe fn append_ptr(&self, p: *mut Node<T>) {
217 loop {
218 match self.0.compare_exchange_weak(
219 ptr::null_mut(),
220 p,
221 Ordering::AcqRel,
222 Ordering::Acquire,
223 ) {
224 Ok(_) => return,
225 Err(head) => {
226 if !head.is_null() {
227 return (*head).next.append_ptr(p);
228 }
229 }
230 }
231 }
232 }
233
234 pub fn append_list(&self, other: AppendList<T>) {
235 let p = other.0.load(Ordering::Acquire);
236 mem::forget(other);
237 unsafe { self.append_ptr(p) };
238 }
239
240 pub fn iter(&self) -> AppendListIterator<T> {
241 AppendListIterator(&self.0)
242 }
243
244 pub fn iter_mut(&mut self) -> AppendListMutIterator<T> {
245 AppendListMutIterator(&mut self.0)
246 }
247 }
248
249 impl<'a, T> IntoIterator for &'a AppendList<T> {
250 type Item = &'a T;
251 type IntoIter = AppendListIterator<'a, T>;
252
253 fn into_iter(self) -> AppendListIterator<'a, T> {
254 self.iter()
255 }
256 }
257
258 impl<'a, T> IntoIterator for &'a mut AppendList<T> {
259 type Item = &'a mut T;
260 type IntoIter = AppendListMutIterator<'a, T>;
261
262 fn into_iter(self) -> AppendListMutIterator<'a, T> {
263 self.iter_mut()
264 }
265 }
266
267 impl<T> Drop for AppendList<T> {
268 fn drop(&mut self) {
269 unsafe { Self::node_from_raw(mem::replace(self.0.get_mut(), ptr::null_mut())) };
270 }
271 }
272
273 #[derive(Debug)]
274 pub struct AppendListIterator<'a, T: 'a>(&'a AtomicPtr<Node<T>>);
275
276 impl<'a, T: 'a> Iterator for AppendListIterator<'a, T> {
277 type Item = &'a T;
278
279 fn next(&mut self) -> Option<&'a T> {
280 let p = self.0.load(Ordering::Acquire);
281 if p.is_null() {
282 None
283 } else {
284 unsafe {
285 self.0 = &(*p).next.0;
286 Some(&(*p).value)
287 }
288 }
289 }
290 }
291
292 #[derive(Debug)]
293 pub struct AppendListMutIterator<'a, T: 'a>(&'a mut AtomicPtr<Node<T>>);
294
295 impl<'a, T: 'a> Iterator for AppendListMutIterator<'a, T> {
296 type Item = &'a mut T;
297
298 fn next(&mut self) -> Option<&'a mut T> {
299 let p = self.0.load(Ordering::Acquire);
300 if p.is_null() {
301 None
302 } else {
303 unsafe {
304 self.0 = &mut (*p).next.0;
305 Some(&mut (*p).value)
306 }
307 }
308 }
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use super::UserDataMap;
315
316 #[test]
317 fn insert_twice() {
318 let map = UserDataMap::new();
319
320 assert_eq!(map.get::<usize>(), None);
321 assert!(map.insert_if_missing(|| 42usize));
322 assert!(!map.insert_if_missing(|| 43usize));
323 assert_eq!(map.get::<usize>(), Some(&42));
324 }
325}