`Cell`-like primitive that lets me temporarily take ownership via reference

Hi, I have an interior mutability problem where I need to temporarily take ownership of a value, then replace it with a new value.

I'd like something like:

pub struct Foo {
   bar: OwnerCell<String>,
}

fn main() {
   let foo = foo::new();
   foo.bar.update(|s| {
      println!("Do something with {s} and return a ");
      String::from("new owned string")
   }
}

Is this something that unsafe Rust can do?

This is RefCell::borrow_mut() + std::mem::replace() or a similar function (take(), swap(), etc.)

Here's an example implementation.

typically, this is done with a Option, because Option<T> implements Default, you can use Cell::take() and Cell::set(). it is safe, though Option<T> does have a tiny bit of overhead.

if you really concerns about overhead, the unsafe way is to go through raw pointer. use std::ptr::read() to emulate "move" out the value, and use std::ptr::write() to overwrite the old value. you may want to play with MaybeUninit or UnsafeCell to get the exact behavior you wanted.

just be warned, it is HIGHLY UNSAFE because you can quite easily write unsound code this way!

Here's one little experiment along those lines you might be interested in: https://docs.rs/pawn/latest/src/pawn/lib.rs.html#54-63

I've never properly productized it, though -- no docs and such.

I considered that, but it's not exactly what I want. I need to be able to use the old value in order to initialize the new value. So for example

foo.bar.update(|s| {
   return do_something_with_owned(s)
}

take would work but there's no cheap implementation of Default since my type requires a lot of memory allocation.

Yeah, I was unsure whether Miri would even allow something like this since "technically" the data is owned in two places at once, even if it's just for a short period of time

This is not possible to do soundly without providing a value to replace the original with.

Then you can follow @nerditation's suggestion above and wrap the value into an Option, like this.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.