Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
325
third-party/vendor/wayland-commons/src/user_data.rs
vendored
Normal file
325
third-party/vendor/wayland-commons/src/user_data.rs
vendored
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
//! Various utilities used for other implementations
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use std::any::Any;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::thread::{self, ThreadId};
|
||||
|
||||
use self::list::AppendList;
|
||||
|
||||
/// A wrapper for user data, able to store any type, and correctly
|
||||
/// handling access from a wrong thread
|
||||
#[derive(Debug)]
|
||||
pub struct UserData {
|
||||
inner: OnceCell<UserDataInner>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum UserDataInner {
|
||||
ThreadSafe(Box<dyn Any + Send + Sync + 'static>),
|
||||
NonThreadSafe(Box<ManuallyDrop<dyn Any + 'static>>, ThreadId),
|
||||
}
|
||||
|
||||
// UserData itself is always threadsafe, as it only gives access to its
|
||||
// content if it is send+sync or we are on the right thread
|
||||
unsafe impl Send for UserData {}
|
||||
unsafe impl Sync for UserData {}
|
||||
|
||||
impl UserData {
|
||||
/// Create a new UserData instance
|
||||
pub const fn new() -> UserData {
|
||||
UserData { inner: OnceCell::new() }
|
||||
}
|
||||
|
||||
/// Sets the UserData to a given value
|
||||
///
|
||||
/// The provided closure is called to init the UserData,
|
||||
/// does nothing is the UserData had already been set.
|
||||
pub fn set<T: Any + 'static, F: FnOnce() -> T>(&self, f: F) {
|
||||
self.inner.get_or_init(|| {
|
||||
UserDataInner::NonThreadSafe(Box::new(ManuallyDrop::new(f())), thread::current().id())
|
||||
});
|
||||
}
|
||||
|
||||
/// Sets the UserData to a given threadsafe value
|
||||
///
|
||||
/// The provided closure is called to init the UserData,
|
||||
/// does nothing is the UserData had already been set.
|
||||
pub fn set_threadsafe<T: Any + Send + Sync + 'static, F: FnOnce() -> T>(&self, f: F) {
|
||||
self.inner.get_or_init(|| UserDataInner::ThreadSafe(Box::new(f())));
|
||||
}
|
||||
|
||||
/// Attempt to access the wrapped user data
|
||||
///
|
||||
/// Will return `None` if either:
|
||||
///
|
||||
/// - The requested type `T` does not match the type used for construction
|
||||
/// - This `UserData` has been created using the non-threadsafe variant and access
|
||||
/// is attempted from an other thread than the one it was created on
|
||||
pub fn get<T: 'static>(&self) -> Option<&T> {
|
||||
match self.inner.get() {
|
||||
Some(&UserDataInner::ThreadSafe(ref val)) => <dyn Any>::downcast_ref::<T>(&**val),
|
||||
Some(&UserDataInner::NonThreadSafe(ref val, threadid)) => {
|
||||
// only give access if we are on the right thread
|
||||
if threadid == thread::current().id() {
|
||||
<dyn Any>::downcast_ref::<T>(&***val)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for UserData {
|
||||
fn drop(&mut self) {
|
||||
// only drop non-Send user data if we are on the right thread, leak it otherwise
|
||||
if let Some(&mut UserDataInner::NonThreadSafe(ref mut val, threadid)) = self.inner.get_mut()
|
||||
{
|
||||
if threadid == thread::current().id() {
|
||||
unsafe {
|
||||
ManuallyDrop::drop(&mut **val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A storage able to store several values of `UserData`
|
||||
/// of different types. It behaves similarly to a `TypeMap`.
|
||||
#[derive(Debug)]
|
||||
pub struct UserDataMap {
|
||||
list: AppendList<UserData>,
|
||||
}
|
||||
|
||||
impl UserDataMap {
|
||||
/// Create a new map
|
||||
pub fn new() -> UserDataMap {
|
||||
UserDataMap { list: AppendList::new() }
|
||||
}
|
||||
|
||||
/// Attempt to access the wrapped user data of a given type
|
||||
///
|
||||
/// Will return `None` if no value of type `T` is stored in this `UserDataMap`
|
||||
/// and accessible from this thread
|
||||
pub fn get<T: 'static>(&self) -> Option<&T> {
|
||||
for user_data in &self.list {
|
||||
if let Some(val) = user_data.get::<T>() {
|
||||
return Some(val);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Insert a value in the map if it is not already there
|
||||
///
|
||||
/// This is the non-threadsafe variant, the type you insert don't have to be
|
||||
/// threadsafe, but they will not be visible from other threads (even if they are
|
||||
/// actually threadsafe).
|
||||
///
|
||||
/// If the value does not already exists, the closure is called to create it and
|
||||
/// this function returns `true`. If the value already exists, the closure is not
|
||||
/// called, and this function returns `false`.
|
||||
pub fn insert_if_missing<T: 'static, F: FnOnce() -> T>(&self, init: F) -> bool {
|
||||
if self.get::<T>().is_some() {
|
||||
return false;
|
||||
}
|
||||
let data = UserData::new();
|
||||
data.set(init);
|
||||
self.list.append(data);
|
||||
true
|
||||
}
|
||||
|
||||
/// Insert a value in the map if it is not already there
|
||||
///
|
||||
/// This is the threadsafe variant, the type you insert must be threadsafe and will
|
||||
/// be visible from all threads.
|
||||
///
|
||||
/// If the value does not already exists, the closure is called to create it and
|
||||
/// this function returns `true`. If the value already exists, the closure is not
|
||||
/// called, and this function returns `false`.
|
||||
pub fn insert_if_missing_threadsafe<T: Send + Sync + 'static, F: FnOnce() -> T>(
|
||||
&self,
|
||||
init: F,
|
||||
) -> bool {
|
||||
if self.get::<T>().is_some() {
|
||||
return false;
|
||||
}
|
||||
let data = UserData::new();
|
||||
data.set_threadsafe(init);
|
||||
self.list.append(data);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UserDataMap {
|
||||
fn default() -> UserDataMap {
|
||||
UserDataMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
mod list {
|
||||
/*
|
||||
* This is a lock-free append-only list, it is used as an implementation
|
||||
* detail of the UserDataMap.
|
||||
*
|
||||
* It was extracted from https://github.com/Diggsey/lockless under MIT license
|
||||
* Copyright © Diggory Blake <diggsey@googlemail.com>
|
||||
*/
|
||||
|
||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
use std::{mem, ptr};
|
||||
|
||||
type NodePtr<T> = Option<Box<Node<T>>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node<T> {
|
||||
value: T,
|
||||
next: AppendList<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppendList<T>(AtomicPtr<Node<T>>);
|
||||
|
||||
impl<T> AppendList<T> {
|
||||
fn node_into_raw(ptr: NodePtr<T>) -> *mut Node<T> {
|
||||
match ptr {
|
||||
Some(b) => Box::into_raw(b),
|
||||
None => ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
unsafe fn node_from_raw(ptr: *mut Node<T>) -> NodePtr<T> {
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Box::from_raw(ptr))
|
||||
}
|
||||
}
|
||||
|
||||
fn new_internal(ptr: NodePtr<T>) -> Self {
|
||||
AppendList(AtomicPtr::new(Self::node_into_raw(ptr)))
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self::new_internal(None)
|
||||
}
|
||||
|
||||
pub fn append(&self, value: T) {
|
||||
self.append_list(AppendList::new_internal(Some(Box::new(Node {
|
||||
value,
|
||||
next: AppendList::new(),
|
||||
}))));
|
||||
}
|
||||
|
||||
unsafe fn append_ptr(&self, p: *mut Node<T>) {
|
||||
loop {
|
||||
match self.0.compare_exchange_weak(
|
||||
ptr::null_mut(),
|
||||
p,
|
||||
Ordering::AcqRel,
|
||||
Ordering::Acquire,
|
||||
) {
|
||||
Ok(_) => return,
|
||||
Err(head) => {
|
||||
if !head.is_null() {
|
||||
return (*head).next.append_ptr(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_list(&self, other: AppendList<T>) {
|
||||
let p = other.0.load(Ordering::Acquire);
|
||||
mem::forget(other);
|
||||
unsafe { self.append_ptr(p) };
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> AppendListIterator<T> {
|
||||
AppendListIterator(&self.0)
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> AppendListMutIterator<T> {
|
||||
AppendListMutIterator(&mut self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a AppendList<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = AppendListIterator<'a, T>;
|
||||
|
||||
fn into_iter(self) -> AppendListIterator<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a mut AppendList<T> {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = AppendListMutIterator<'a, T>;
|
||||
|
||||
fn into_iter(self) -> AppendListMutIterator<'a, T> {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for AppendList<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { Self::node_from_raw(mem::replace(self.0.get_mut(), ptr::null_mut())) };
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppendListIterator<'a, T: 'a>(&'a AtomicPtr<Node<T>>);
|
||||
|
||||
impl<'a, T: 'a> Iterator for AppendListIterator<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
let p = self.0.load(Ordering::Acquire);
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
unsafe {
|
||||
self.0 = &(*p).next.0;
|
||||
Some(&(*p).value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppendListMutIterator<'a, T: 'a>(&'a mut AtomicPtr<Node<T>>);
|
||||
|
||||
impl<'a, T: 'a> Iterator for AppendListMutIterator<'a, T> {
|
||||
type Item = &'a mut T;
|
||||
|
||||
fn next(&mut self) -> Option<&'a mut T> {
|
||||
let p = self.0.load(Ordering::Acquire);
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
unsafe {
|
||||
self.0 = &mut (*p).next.0;
|
||||
Some(&mut (*p).value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::UserDataMap;
|
||||
|
||||
#[test]
|
||||
fn insert_twice() {
|
||||
let map = UserDataMap::new();
|
||||
|
||||
assert_eq!(map.get::<usize>(), None);
|
||||
assert!(map.insert_if_missing(|| 42usize));
|
||||
assert!(!map.insert_if_missing(|| 43usize));
|
||||
assert_eq!(map.get::<usize>(), Some(&42));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue