I would assume the following code is sound, but since I have been running into bad surprises in past, I would like to know if it's really sound:
use std::cell::UnsafeCell;
#[derive(Default)]
struct Inner {
number: i32,
}
#[derive(Default)]
struct Outer {
inner: UnsafeCell<Inner>,
}
impl Outer {
fn increment(&self) {
// SAFETY: There may be no concurrent access to `inner` because
// only the `increment` and `get_number` methods access `inner` and
// `Outer` is !Sync
let inner: &mut Inner = unsafe { &mut *self.inner.get() };
inner.number = inner.number.checked_add(1).unwrap();
}
fn get_number(&self) -> i32 {
// SAFETY: There may be no concurrent access to `inner` because
// only the `increment` and `get_number` methods access `inner` and
// `Outer` is !Sync
let inner: &Inner = unsafe { &*self.inner.get() };
inner.number
}
}
fn main() {
let outer: Outer = Default::default();
outer.increment();
outer.increment();
println!("{}", outer.get_number());
let arc = std::sync::Arc::new(outer);
let _arc2 = arc.clone();
std::thread::spawn(move || {
// Rust is smart enough to prohibit this:
//_arc2.increment();
});
arc.increment();
}