For example, is the following implementation of Mutex
(playground link) sound? I use raw pointers for changing the value, and Miri doesn’t complain about it.
use std::marker::PhantomData;
use std::ptr::NonNull;
use std::sync::Mutex;
use std::thread;
pub struct MyMutex<T>
where
T: ?Sized,
{
mutex: Mutex<()>,
value: NonNull<T>,
_invariant_for_t: PhantomData<*mut T>,
}
impl<T> MyMutex<T>
where
T: ?Sized,
{
pub fn new(value: T) -> Self
where
T: Sized,
{
Self {
mutex: Mutex::new(()),
value: NonNull::new(Box::into_raw(Box::new(value))).unwrap(),
_invariant_for_t: PhantomData,
}
}
pub fn with_mut<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
let _guard = self.mutex.lock().unwrap();
f(unsafe { &mut *self.value.as_ptr() })
}
}
impl<T> Drop for MyMutex<T>
where
T: ?Sized,
{
fn drop(&mut self) {
drop(unsafe { Box::from_raw(self.value.as_ptr()) });
}
}
unsafe impl<T> Send for MyMutex<T> where T: Send + ?Sized {}
unsafe impl<T> Sync for MyMutex<T> where T: Send + ?Sized {}
fn main() {
let my_mutex = MyMutex::new(0);
thread::scope(|scope| {
for _ in 0..100 {
scope.spawn(|| {
for _ in 0..100 {
my_mutex.with_mut(|value| *value += 1);
}
});
}
});
assert_eq!(my_mutex.with_mut(|value| *value), 10000);
}