Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Interior Mutability on a Copy type?

Tags:

rust

unsafe

I have a few Copy types, and I really appreciate the handiness of them being Copy.

I would like one of those types to contain a mutable field, using Interior Mutability as in cell::Cell. There are probably other solutions for the problem I am trying to solve, but Interior Mutability is cheap. I like cheap.

However, it turns out that cell::Cell is not Copy, and from the comments is unlikely to become Copy as the maintainers fear this would be error-prone.

A comment by the OP is my current beacon of hope:

It's not the absolute end of the world if it doesn't for my own data structures (since I can just make my own version of Cell)

Though I do not see how they purport to achieve this feat.

The core issue I have is that UnsafeCell:

  • is mandatory to implement Interior Mutability,
  • is not Copy.

Which seems to close the door to any hope of implementing a CopyCell, unless I am missing a trick (a way to unsafe impl the Copy trait?).


MCVE:

#[derive(Clone, Copy)]
struct HelloWorld(Cell<u32>);
  |
3 | #[derive(Clone, Copy)]
  |                 ^^^^
4 | struct HelloWorld(Cell<u32>);
  |                   ---------- this field does not implement `Copy`

What should I replace Cell with for HelloWorld to be Copy?


Note: at the moment, the only way I can see of achieving the desired outcome is to use a &Cell<T>; with all the lifetimes implications.

like image 793
Matthieu M. Avatar asked Oct 17 '22 22:10

Matthieu M.


1 Answers

I think there's a good reason that UnsafeCell doesn't implement Copy: it would be unsafe in the general case. Reading from an UnsafeCell is an unsafe operation, as shown by the get method's signature: it returns a raw pointer, and dereferencing a raw pointer is an unsafe operation. A copy would implicitly read the value, which could race with another thread writing to the same UnsafeCell. Cell doesn't have that race because it is !Sync (i.e. two threads can't access the same Cell).

Personally, I would just use Clone::clone instead of messing with references. Cell's clone is #[inline], so it's highly likely that the call will be optimized away in release builds.

like image 196
Francis Gagné Avatar answered Oct 26 '22 23:10

Francis Gagné