wayland_commons/
user_data.rs

1//! Various utilities used for other implementations
2
3use 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/// A wrapper for user data, able to store any type, and correctly
12/// handling access from a wrong thread
13#[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
24// UserData itself is always threadsafe, as it only gives access to its
25// content if it is send+sync or we are on the right thread
26unsafe impl Send for UserData {}
27unsafe impl Sync for UserData {}
28
29impl UserData {
30    /// Create a new UserData instance
31    pub const fn new() -> UserData {
32        UserData { inner: OnceCell::new() }
33    }
34
35    /// Sets the UserData to a given value
36    ///
37    /// The provided closure is called to init the UserData,
38    /// does nothing is the UserData had already been set.
39    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    /// Sets the UserData to a given threadsafe value
46    ///
47    /// The provided closure is called to init the UserData,
48    /// does nothing is the UserData had already been set.
49    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    /// Attempt to access the wrapped user data
54    ///
55    /// Will return `None` if either:
56    ///
57    /// - The requested type `T` does not match the type used for construction
58    /// - This `UserData` has been created using the non-threadsafe variant and access
59    ///   is attempted from an other thread than the one it was created on
60    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                // only give access if we are on the right thread
65                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        // only drop non-Send user data if we are on the right thread, leak it otherwise
79        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/// A storage able to store several values of `UserData`
91/// of different types. It behaves similarly to a `TypeMap`.
92#[derive(Debug)]
93pub struct UserDataMap {
94    list: AppendList<UserData>,
95}
96
97impl UserDataMap {
98    /// Create a new map
99    pub fn new() -> UserDataMap {
100        UserDataMap { list: AppendList::new() }
101    }
102
103    /// Attempt to access the wrapped user data of a given type
104    ///
105    /// Will return `None` if no value of type `T` is stored in this `UserDataMap`
106    /// and accessible from this thread
107    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    /// Insert a value in the map if it is not already there
117    ///
118    /// This is the non-threadsafe variant, the type you insert don't have to be
119    /// threadsafe, but they will not be visible from other threads (even if they are
120    /// actually threadsafe).
121    ///
122    /// If the value does not already exists, the closure is called to create it and
123    /// this function returns `true`. If the value already exists, the closure is not
124    /// called, and this function returns `false`.
125    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    /// Insert a value in the map if it is not already there
136    ///
137    /// This is the threadsafe variant, the type you insert must be threadsafe and will
138    /// be visible from all threads.
139    ///
140    /// If the value does not already exists, the closure is called to create it and
141    /// this function returns `true`. If the value already exists, the closure is not
142    /// called, and this function returns `false`.
143    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    /*
165     * This is a lock-free append-only list, it is used as an implementation
166     * detail of the UserDataMap.
167     *
168     * It was extracted from https://github.com/Diggsey/lockless under MIT license
169     * Copyright © Diggory Blake <diggsey@googlemail.com>
170     */
171
172    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}