How to prevent autoimplementation of Sync

Viewed 811

I have a struct containing unsafe code with the following method:

use std::sync::Arc;
use std::thread;

#[derive(Debug)]
struct Foo<T> {
    items: Vec<Box<(T, String)>>,
}

impl<T> Foo<T> {
    pub fn add_element(&self, element: T, key: String) {
        if !(self.items.iter().any( |i| i.1 == key)) {
            let mut items = unsafe {change_mut(&(self.items))};
            items.push(Box::new((element,key)));
        }
    }
}

unsafe fn change_mut<T>(x: &T) -> &mut T { // changes &self to &mut self
    &mut *(x as *const T as *mut T)
}

fn main() {
    let foo = Arc::new(Foo { items: vec!() });
    let clone = foo.clone();

    // This should not be possible, as it might lead to UB
    thread::spawn(move || clone.add_element(1, String::from("one")));

    println!("{:?}", *foo);

}

This struct is completely safe until someone starts using this method while multithreading. However, due to the fact the struct only contains a Vec<Box<T,String>>, Syncis implemented by default, which I would like to prevent.

I have found two ways to do this, both of which are not that great...

  1. Add a struct field which does not implement Sync for example *const u8, this is obviously rather bad, as it ends up resulting in unnecessary and unclear code and does not clearly show my intent.

  2. impl !Sync for Struct {} is not available on stable and will be removed according to this issue. The corresponding error is telling me to use marker types instead, but the documention does not present a way to solve my problem either.


error: negative trait bounds are not yet fully implemented; use marker types for
 now (see issue #13231)
  --> src\holder.rs:44:1
   |
44 | impl !Sync for Struct {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^
1 Answers
Related