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
//! This module is full of hackery and dark magic.
//! Either spend a day fixing it and quietly submit a PR or don't mention it to anybody.

use core::cell::UnsafeCell;
use core::{mem, ptr};

#[inline(always)]
pub const fn ptr_size_bits() -> usize {
    mem::size_of::<usize>() * 8
}

#[inline(always)]
pub fn map_in_place_2<T, U, F: FnOnce(U, T) -> T>((k, v): (U, &mut T), f: F) {
    unsafe {
        // # Safety
        //
        // If the closure panics, we must abort otherwise we could double drop `T`
        let _promote_panic_to_abort = AbortOnPanic;

        ptr::write(v, f(k, ptr::read(v)));
    }
}

/// # Safety
///
/// Requires that you ensure the reference does not become invalid.
/// The object has to outlive the reference.
#[inline(always)]
pub unsafe fn change_lifetime_const<'a, 'b, T>(x: &'a T) -> &'b T {
    &*(x as *const T)
}

/// # Safety
///
/// Requires that you ensure the reference does not become invalid.
/// The object has to outlive the reference.
#[inline(always)]
pub unsafe fn change_lifetime_mut<'a, 'b, T>(x: &'a mut T) -> &'b mut T {
    &mut *(x as *mut T)
}

/// A simple wrapper around `T`
///
/// This is to prevent UB when using `HashMap::get_key_value`, because
/// `HashMap` doesn't expose an api to get the key and value, where
/// the value is a `&mut T`.
///
/// See [#10](https://github.com/xacrimon/dashmap/issues/10) for details
///
/// This type is meant to be an implementation detail, but must be exposed due to the `Dashmap::shards`
#[repr(transparent)]
pub struct SharedValue<T> {
    value: UnsafeCell<T>,
}

impl<T: Clone> Clone for SharedValue<T> {
    fn clone(&self) -> Self {
        let inner = self.get().clone();
        Self {
            value: UnsafeCell::new(inner),
        }
    }
}

unsafe impl<T: Send> Send for SharedValue<T> {}
unsafe impl<T: Sync> Sync for SharedValue<T> {}

impl<T> SharedValue<T> {
    /// Create a new `SharedValue<T>`
    #[inline]
    pub const fn new(value: T) -> Self {
        Self {
            value: UnsafeCell::new(value),
        }
    }

    /// Get a shared reference to `T`
    #[inline]
    pub fn get(&self) -> &T {
        unsafe { &*self.value.get() }
    }

    /// Get an unique reference to `T`
    #[inline]
    pub fn get_mut(&mut self) -> &mut T {
        unsafe { &mut *self.value.get() }
    }

    /// Unwraps the value
    #[inline]
    pub fn into_inner(self) -> T {
        self.value.into_inner()
    }

    /// Get a mutable raw pointer to the underlying value
    #[inline]
    pub(crate) fn as_ptr(&self) -> *mut T {
        self.value.get()
    }
}

struct AbortOnPanic;

impl Drop for AbortOnPanic {
    #[inline]
    fn drop(&mut self) {
        cfg_if::cfg_if! {
            if #[cfg(feature = "no_std")] {
                // Note: This is hard, as core/no_std has no concept of threads or knowledge of panicking.
                // An alternative would be to do this:
                //
                // ```rust
                // // Elsewhere in the library/host binary
                // use core::sync::atomic::{AtomicBool, Ordering};
                //
                // static UNWINDING: AtomicBool = AtomicBool::new(false);
                //
                // #[panic_handler]
                // fn panic(info: &PanicInfo) -> ! {
                //      UNWINDING.store(true, Ordering::Relaxed);
                //
                //      unsafe {
                //          core::intrinsics::abort();
                //      }
                // }
                //
                // // In AbortOnPanic::drop
                // if UNWINDING.load(Ordering::Relaxed) {
                //      unsafe {
                //          core::intrinsics::abort();
                //      }
                // }
                // ```
                //
                // Now, this isn't an ideal solution for multiple reasons, as it uses intrinsics which require a feature
                // and can be overwritten by the user without them even knowing. That being said, *most* users of no_std
                // do tend to use panic = "abort", which solves this problem for us by aborting on panics.
            } else {
                if std::thread::panicking() {
                    std::process::abort()
                }
            }
        }
    }
}