For test purposes, it's often useful to take a peek at (and possibly mess with) data which would otherwise be private to a component.
While writing test code for one of my projects, I found that this need sometimes conflicts with Rust's safety guarantees, in particular, the guarantee that there is at most one mutable reference to an object, and that if there is a mutable reference, then no immutable ones may also exist.
For example, say your type takes ownership of something in its constructor function, which you later want to take a peek at to see what was done with it, or to change it. Rust won't allow this normally, because by giving that type ownership, you've given up all control:
error: use of moved value
To work around this, you might be tempted to have your type take the object as a mutable reference, instead of taking ownership outright. Ah, but now you run into Rust's limitations on mutable references listed above. While that type holds a mutable reference, you can't touch or look at the object:
error: cannot borrow
xas mutable more than once at a time
Next try: use a
Rc to allow you to share the object. This won't work either, because you can only get a mutable reference out of an
Rc when there is exactly one strong reference, and in your usage, there will be two: one held by the type, and one held by your test code. This is the worst, as it only fails at runtime:
thread '<main>' panicked at 'called
The solution I came up with uses the
UnsafeCell allows you to get a mutable pointer at any time. This is unsafe in the general case, but if we're careful, we an use this to our advantage.
I implemented a type called
Sneaky that lets you do this. It takes an instance of whatever you want, and makes a
Rc of an
UnsafeCell of it. I used
Rc so that this type can safely be passed to other types that want to take ownership of a value.
Sneaky implements the
BorrowMut types by dereferencing the pointer obtained from calling
UnsafeCell::get(). It also implements
Everything is safe, except for a
sneak function which clones the inner
Rc and gives you another handle to the variable. Until you call
sneak, everything is safe because there is only one instance of the variable, and so it can be mutated freely. But once called, now you have two handles and you need to be careful. Therefore
sneak is marked as
Here's the full code:
And here's an example of its usage: