Unsafe collection which allows immutable access while also allowing push() To get myself used to writing unsafe code, I wrote a collection which allows the user to keep immutable references to the elements of a vector while still being able to add new elements to it.

I would like to know if there is either a security problem with this code, an already implemented better alternative or some possible improvements in general (readability / performance).

pub struct UnsafeHolder&lt;T&gt; {
    items: Vec&lt;Box&lt;(T,String)&gt;&gt; // the vector contains Boxes, due to the fact that
                                // vectors can reallocate when adding elements
                                // which would end up creating dangling pointers
}

impl&lt;T&gt; UnsafeHolder&lt;T&gt; {
    pub fn new() -&gt; Self {
        UnsafeHolder {
            items: vec![],
        }
    }

    // this method pretends to be immutable while actually adding
    // elements to the vector, this allows for continuous reference to
    // previous elements
    pub fn add_element(&amp;self, element: T, key: String) {
        if !(self.items.iter().any( |i| i.1 == key)) {
            let mut items = unsafe {change_mut(&amp;(self.items))};
            items.push(Box::new((element,key)));
        }
    }

    pub fn get_element(&amp;self, key: &amp;str) -&gt; Option&lt;&amp;T&gt; {
        if let Some(return_val) = self.items.iter().find(|i| i.1 == key) {
            Some(&amp;return_val.0)
        }
        else {
            None
        }
    }

    pub fn clear(&amp;mut self) {
        self.items = vec![];
    }
}

// this is used to change '&amp;self' to '&amp;mut self' to avoid the borrow checker
unsafe fn change_mut&lt;T&gt;(x: &amp;T) -&gt; &amp;mut T {
    &amp;mut *(x as *const T as *mut T)
}


This is the whole module, meaning that there should be no other ways than these 4 methods to interact with UnsafeHolder.

There is currently a problem due to the fact that items can be changed by multiple threads at once, resulting in an error.

Here is a link to the most recent version on playground.
Safety First

Unfortunately, programming in unsafe Rust requires respecting a number of rules; and you have broken at least one here.

Rust memory safety is based on the principle of Aliasing XOR Mutability, which is enforced as much as possible at compile-time for obvious performance reasons. When you wish to shift the responsibility from compile-time to run-time, you need to inform the compiler about it at the type level, lest it infers properties about the code that do not hold.

For interior mutability, use UnsafeCell.

This is the basic block that is used by all abstractions which defer the enforcement of the principle to run-time. For example, here is AtomicBool:

#[cfg(target_has_atomic = "8")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct AtomicBool {
    v: UnsafeCell&lt;u8&gt;,
}


Thus, your type should be:

pub struct UnsafeHolder&lt;T&gt; {
    items: UnsafeCell&lt;Vec&lt;Box&lt;(T,String)&gt;&gt;&gt;,
}




Clean-up

UnsafeCell comes with a get method: UnsafeCell::get(&amp;self) -&gt; *mut T, and thus your change_mut function is unnecessary:

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




Nits and bits

Your add_element method should indicate when insertion fails; silent failures make programs harder to debug.

It seems strange to me to pass the element before the key; most APIs seem to do the reverse so I would advise following in their steps.

The complexity of your look-up is O(N), so that inserting repeatedly has O(N2) complexity; if you were sorting by key look-up could be O(log N) instead, and repeated insertion O(N log N).

I recommend avoiding unnecessary parentheses (such as in if !(...)); they clutter the code for no obvious gain.



Final Word

If you wish to venture into the world of unsafe, I recommend reading the Nomicon. Until Rust gets official unsafe semantics, it is probably the best reference about the dos and don'ts.