Is it possible to move even with immutable borrows? - rust

use std::marker;
use std::ops;
pub struct Shared<'r, T: 'r> {
data: *mut T,
_pd: marker::PhantomData<&'r T>,
}
impl<'r, T> Shared<'r, T> {
pub fn new(value: T) -> Shared<'r, T> {
let boxed = Box::new(value);
Shared {
data: Box::into_raw(boxed),
_pd: marker::PhantomData,
}
}
pub fn as_ref(&self) -> SharedRef<'r, T> {
SharedRef {
data: self.data,
_pd: marker::PhantomData,
}
}
}
impl<'r, T> ops::Deref for Shared<'r, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.data }
}
}
pub struct SharedRef<'r, T: 'r> {
data: *mut T,
_pd: marker::PhantomData<&'r T>,
}
impl<'r, T> ops::Deref for SharedRef<'r, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.data }
}
}
impl<'r, T> Drop for Shared<'r, T> {
fn drop(&mut self) {
unsafe {
Box::from_raw(self.data);
}
}
}
fn main() {
let s = Shared::new(42);
let s_ref = s.as_ref();
{
let s1 = s;
}
// lifetime should end here
println!("{}", *s_ref);
}
What I wanted to express was a mix between a Box and an Arc. A uniquely owned pointer that is also capable of giving out references.
The problem is that I want to be able to move Shared around even if there are currently immutable borrows to it. It should be legal in this scenario because it is heap allocated.
The problem is that I have no idea how to express this.
fn main() {
let s = Shared::new(42);
let s_ref = s.as_ref();
{
let s1 = s;
}
// lifetime should end here
println!("{}", *s_ref);
}
Here I move s into a scope with "less" lifetime than it had before. But now after I have moved s into s1, s_ref should not be accessible anymore. So what I want to say is that it is okay to move a Shared if the lifetime does not get smaller.
Can this be expressed in Rust?

The reason Rust allows you to move out of the Shared is that you haven't tied the lifetime of the returned SharedRef to it:
pub fn as_ref(&self) -> SharedRef<'r, T> {
SharedRef {
data: self.data,
_pd: marker::PhantomData,
}
}
Annotating the &self fixes that:
pub fn as_ref(&'r self) -> SharedRef<'r, T> { .. }
My current understanding is that the key difference here is that this says that the lifetime of the SharedRef now matches the lifetime of the borrow of self, keeping the borrow alive. Indeed it doesn't have to be the same lifetime ('r) as in the Shared; it works with a new lifetime just for the borrow/return:
pub fn as_ref<'b>(&'b self) -> SharedRef<'b, T> { .. }
This also disallows the move.
As for the bonus part of the question, where you want to allow moving as long as it's to something with a long enough lifetime, I think the answer is no. The only way I know to stop something being moved at all is to borrow it, and that stops any move.

Related

Shared ownership inside a struct (mutable_borrow_reservation_conflict warning)

The following code compiles and runs but emits a mutable_borrow_reservation_conflict warning.
My goal is to have a field all_ops owning a set of Op's implementations (readonly) where each op can be referenced in another container in the same struct (and when the main all_ops container is cleared, used_ops access becomes illegal as expected)
Of course, one could use Rc but it causes performance issues.
Do you have an idea to do that properly ? (i.e. a way which will not become an hard error in the (near?) future).
trait Op {
fn f(&self);
}
struct OpA;
impl Op for OpA {
fn f(&self) {
println!("OpA");
}
}
struct OpB;
impl Op for OpB {
fn f(&self) {
println!("OpB");
}
}
struct Container<'a> {
all_ops: Vec<Box<dyn Op>>,
used_ops: Vec<&'a Box<dyn Op>>, // data pointing to data in all_ops field
}
fn main() {
let v: Vec<Box<dyn Op>> = vec![Box::new(OpA), Box::new(OpB)];
let mut c = Container { all_ops: v, used_ops: Vec::new() };
c.used_ops.push(&c.all_ops.get(0).unwrap());
c.used_ops.push(&c.all_ops.get(1).unwrap());
c.used_ops.push(&c.all_ops.get(0).unwrap());
for op in c.used_ops {
op.f();
}
c.all_ops.clear();
// c.used.first().unwrap().f(); // cannot borrow `c.all` as mutable because it is also borrowed as immutable
}
Rust playground
If I replace used_ops: Vec<&'a Box<dyn Op>>
by used_ops: Vec<&'a dyn Op>, it seems sufficient to fix the warning.
Unfortunately, Container isn't movable even if all references in used_ops are on objects allocated in the heap (and I understand why since there are references to (inner parts of) the object).
trait Op {
fn f(&self);
}
struct OpA;
impl Op for OpA {
fn f(&self) {
println!("OpA");
}
}
struct OpB;
impl Op for OpB {
fn f(&self) {
println!("OpB");
}
}
struct Container<'a> {
all_ops: Vec<Box<dyn Op>>,
used_ops: Vec<&'a dyn Op>, // data pointing to data in all_ops field
}
fn main() {
let v: Vec<Box<dyn Op>> = vec![Box::new(OpA), Box::new(OpB)];
let mut c = Container { all_ops: v, used_ops: Vec::new() };
c.used_ops.push(c.all_ops.get(0).unwrap().as_ref());
c.used_ops.push(c.all_ops.get(1).unwrap().as_ref());
c.used_ops.push(c.all_ops.get(0).unwrap().as_ref());
for op in c.used_ops.iter() {
op.f();
}
// let c2 = c; // cannot move out of `c` because it is borrowed
}
Playground

Borrow checker error after adding generic parameter to struct

I have code that works, but it stops compiling with a borrow checker error after a change. I don't understand how the change could affect borrow checking.
Common part to both working and non-working code:
/// Some struct that has references inside
#[derive(Debug)]
struct MyValue<'a> {
number: &'a u32,
}
/// There are many structs similar to `MyValue` and there is a
/// trait common to them all that can create them. In this
/// example I use the `From` trait.
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue { number: value }
}
}
/// `Producer` makes objects that hold references into it. So
/// the produced object must be first dropped before any new
/// one can be made.
trait Producer<'a, T: 'a> {
fn make(&'a mut self) -> T;
}
Here is the working code:
struct MyProducer {
number: u32,
}
impl MyProducer {
fn new() -> Self {
Self { number: 0 }
}
}
impl<'a, T: 'a + From<&'a u32>> Producer<'a, T> for MyProducer {
fn make(&'a mut self) -> T {
self.number += 1;
T::from(&self.number)
}
}
fn main() {
let mut producer = MyProducer::new();
println!(
"made this: {:?}",
<MyProducer as Producer<MyValue>>::make(&mut producer)
);
println!(
"made this: {:?}",
<MyProducer as Producer<MyValue>>::make(&mut producer)
);
}
This compiles and prints the expected output:
made this: MyValue { number: 1 }
made this: MyValue { number: 2 }
I don't like that MyProducer actually implements Producer for every T as it makes it impossible to call make directly on it. I would like to have a type that is a MyProducer for a specific T (for example for MyValue).
To achieve this, I want to add a generic parameter to MyProducer. Because the MyProducer does not really use the T, I use PhantomData to prevent the compiler from complaining.
Here is the code after changes:
use std::marker::PhantomData;
struct MyProducer<'a, T: 'a + From<&'a u32>> {
number: u32,
_phantom: PhantomData<&'a T>,
}
impl<'a, T: 'a + From<&'a u32>> MyProducer<'a, T> {
fn new() -> Self {
Self {
number: 0,
_phantom: PhantomData::default(),
}
}
}
impl<'a, T: From<&'a u32>> Producer<'a, T> for MyProducer<'a, T> {
fn make(&'a mut self) -> T {
self.number += 1;
T::from(&self.number)
}
}
fn main() {
let mut producer = MyProducer::<MyValue>::new();
println!("made this: {:?}", producer.make());
println!("made this: {:?}", producer.make());
}
The main function now looks exactly as I would like it to look like. But the code does not compile. This is the error:
error[E0499]: cannot borrow `producer` as mutable more than once at a time
--> src/main.rs:50:33
|
49 | println!("made this: {:?}", producer.make());
| -------- first mutable borrow occurs here
50 | println!("made this: {:?}", producer.make());
| ^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
I don't understand why it no longer works. The produced object is still dropped before the next one is made.
If I call the make function just once, it compiles and works.
I am using edition 2018, so NLL is active.
Rust Playground: working version before change
Rust Playground: broken version after change
I reduced the noise from the code so the following is an even shorter version of the broken case which demonstrates the same problem: (test in the playground)
use std::marker::PhantomData;
#[derive(Debug)]
struct MyValue<'a>(&'a u32);
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue(value)
}
}
struct MyProducer<'a, T>(u32, PhantomData<&'a T>);
impl<'a, T> MyProducer<'a, T>
where
T: From<&'a u32>,
{
fn new() -> Self {
Self(0, PhantomData)
}
fn make(&'a mut self) -> T {
self.0 += 1;
T::from(&self.0)
}
}
fn main() {
let mut producer = MyProducer::<MyValue>::new();
println!("made this: {:?}", producer.make());
println!("made this: {:?}", producer.make());
}
The main problem here is that the mutable borrow's lifetime is the lifetime of MyProducer, that is, the lifetime of the instance called producer is the same as the mutable borrow taken in its make method. Because the producer instance does not go out of scope (if it would then MyValue wouldn't be able to hold a reference to a value stored in it) so the mutable borrow lives until the end of main's scope. The first rule of borrowing is that there can only be a single mutable borrow of a given value in a scope at any time, hence the compiler error.
If you are looking at my solution here, which is actually working and does what I think you wanted it to: (test in the playground):
#[derive(Debug)]
struct MyValue<'a>(&'a u32);
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue(value)
}
}
struct MyProducer(u32);
impl MyProducer {
fn new() -> Self {
Self(0)
}
fn make<'a, T>(&'a mut self) -> T
where
T: From<&'a u32>,
{
self.0 += 1;
T::from(&self.0)
}
}
fn main() {
let mut producer = MyProducer::new();
println!("made this: {:?}", producer.make::<MyValue>());
println!("made this: {:?}", producer.make::<MyValue>());
}
then you can see that the mutable borrow only lives as long as the make method, therefore after the invocation there's no more living mutable borrow to producer in main's scope, thus you can have another one.

How do I implement move semantics on a struct with a mutable field?

I have a minimal example of code that implements move semantics for some container:
use std::mem;
impl<'a, T: 'a + ?Sized> Drop for Cointainer<'a, T> {
fn drop(&mut self) {}
}
struct Cointainer<'a, T: 'a + ?Sized> {
item: &'a /* mut */ T,
}
impl<'a, T> Cointainer<'a, T> {
fn mv(self) -> Cointainer<'a, T> {
let new = Cointainer { item: /* &mut */ self.item };
mem::forget(self);
new
}
}
fn main() {}
That compiles and works without any problems.
I realized I will need to mutate the value referenced by Cointainer::item, so I've made the reference mut. When I do so, I get:
error[E0505]: cannot move out of `self` because it is borrowed
--> src/main.rs:14:21
|
13 | let new = Cointainer { item: /* &mut */ self.item };
| --------- borrow of `*self.item` occurs here
14 | mem::forget(self);
| ^^^^ move out of `self` occurs here
I need to create a new container and transfer ownership of item there, and drop the old one.
This example is artificial. The actual "move" operation does some other stuff, and doesn't necessarily return the same container type.
The rules of references state:
At any given time, you can have either but not both of:
One mutable reference.
Any number of immutable references.
Your code with immutable references works because those can be freely copied. Your code with mutable references fails because, as far as the compiler can tell, you would need to have have two concurrent mutable references: the saved reference in new and then mem::forget might also need it.
As humans, we recognize that mem::forget will not access the guts of our structure. This is what unsafe code is for: when the compiler cannot guarantee the code we have is truly safe.
A small unsafe block and some casting to a raw pointer and back solves the problem. As with any unsafe code, it should have a big comment block explaining why the compiler doesn't understand it and why it's truly safe.
impl<'a, T: 'a + ?Sized> Drop for Cointainer<'a, T> {
fn drop(&mut self) {
println!("dropping 1: {:p}", self.item)
}
}
struct Cointainer<'a, T: 'a + ?Sized> {
item: &'a mut T,
}
impl<'a, T> Cointainer<'a, T> {
fn into_inner(self) -> &'a mut T {
// I copied this code from Stack Overflow but didn't read
// the warning about explaining why it's safe. Sure hope
// this doesn't cause any bugs!
unsafe {
let x = self.item as *mut _;
std::mem::forget(self);
&mut *x
}
}
fn mv(self) -> Cointainer2<'a, T> {
let item = self.into_inner();
Cointainer2 { item }
}
}
struct Cointainer2<'a, T: 'a + ?Sized> {
item: &'a mut T,
}
impl<'a, T: 'a + ?Sized> Drop for Cointainer2<'a, T> {
fn drop(&mut self) {
println!("dropping 2: {:p}", self.item)
}
}
fn main() {
let mut a = String::new();
let c1 = Cointainer { item: &mut a };
let c2 = c1.mv();
}

How to have a struct field with the same mutability as the parent struct?

I'm trying to wrap a slice in a struct so that I will be able to instantiate the struct mutably or immutably. Here's a minimal example:
use std::ops::{ Index, IndexMut };
struct Test<'a, T: 'a> {
inner: &'a[T]
}
impl<'a, T: 'a> Test<'a, T> {
fn new (inner: &'a[T]) -> Self { Test { inner: inner } }
}
impl<'a, T> Index<usize> for Test<'a, T> {
type Output = T;
fn index (&self, i: usize) -> &T { &self.inner[i] }
}
impl<'a, T> IndexMut<usize> for Test<'a, T> {
fn index_mut (&mut self, i: usize) -> &mut T { &mut self.inner[i] }
}
fn main() {
let store = [0; 3];
let test = Test::new (&store);
println!("{}", test[1]);
let mut mut_store = [0; 3];
let mut mut_test = Test::new (&mut mut_store);
mut_test[1] = 42;
println!("{}", mut_test[1]);
}
This doesn't compile: "cannot borrow immutable indexed content self.inner[..] as mutable".
I could get it to compile by changing the definition of inner to be of type &'a mut[T], but then inner is mutable even when I don't need it to be (in the above example, I must then declare store as mutable too even though test is immutable).
Is there a way to make it so that the mutability of inner follows the mutability of the Test instance?
As well said in the question, this code compiles:
struct Test<'a, A: 'a> {
inner: &'a mut A,
}
fn main() {
let t = Test { inner: &mut 5i32 };
*t.inner = 9;
}
It is indeed possible to mutate a borrowed element, even when the borrowing content is immutable. This is a case where you must choose your guarantees, while keeping in mind that the mutability of a binding is always independent of the borrowed content's mutability.
Right now, I can think of two possible solutions: you can encapsulate the borrowed content over methods that depend on self's mutability (Playground, will no longer compile):
impl<'a, A: 'a> Test<'a, A> {
fn inner(&self) -> &A {
self.inner
}
fn inner_mut(&mut self) -> &mut A {
self.inner
}
}
Although you still need to keep a borrow to mutable content, it can no longer be mutated from an immutable binding of Test. If you also need it to point to immutable content, you should consider having two different structs (Playground):
struct Test<'a, A: 'a> {
inner: &'a A,
}
impl<'a, A: 'a> Test<'a, A> {
fn inner(&self) -> &A {
self.inner
}
}
struct TestMut<'a, A: 'a> {
inner: &'a mut A,
}
impl<'a, A: 'a> TestMut<'a, A> {
fn inner(&self) -> &A {
self.inner
}
fn inner_mut(&mut self) -> &mut A {
self.inner
}
}
There is a third option: to keep both kinds of borrows exclusively with an enum. At this point however, using the borrowed content as mutable requires run-time checks.

How to capture self consuming variable in a struct?

I have a Reader instance with a method that consumes the Reader and returns a Writer and the Writer can similarly get back to a Reader again. It's trivial to use immutably, but I can't figure out how to hide the immutability from callers and just do the reader-writer-reader dance behind the scenes with a mutable Self.
Essentially I'd like something like:
struct Container<'a> {
reader: Reader<'a, File>
}
fn update(&mut self) {
let writer = self.reader.as_writer();
writer.write_something();
self.reader = writer.as_reader();
}
which just gives cannot move out of borrowed content error. Tried to add a Box, Cell, or RefCell around the Reader which just lead to other errors.
Can the reader be hidden behind a mutable interface or does it force the whole struct hierarchy to be mutable as well? (i.e. similar to IO in Haskell)
Self contained sample with the types matching the real thing (I think)
#[derive(Debug)]
struct NoCopy(u32);
#[derive(Debug)]
struct Flipper<'a, T: 'a> {
data: &'a mut T,
}
#[derive(Debug)]
struct Flopper<'a, T: 'a> {
data: &'a mut T,
}
impl<'a, T> Flipper<'a, T> {
fn flip(self) -> Flopper<'a, T> {
Flopper{data: self.data}
}
}
impl<'a, T> Flopper<'a, T> {
fn flop(self) -> Flipper<'a, T> {
Flipper{data: self.data}
}
}
#[derive(Debug)]
struct Container<'a, T: 'a> {
flipper: Flipper<'a, T>,
}
impl<'a, T> Container<'a, T> {
fn run(&mut self) {
self.flipper = self.flipper.flip().flop();
}
}
fn main() {
let f = Flipper{data: &mut NoCopy(42)};
let f = f.flip().flop();
println!("f={:?}", f);
let mut c = Container{flipper: f};
c.run();
println!("c={:?}", c);
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:29:24
|
29 | self.flipper = self.flipper.flip().flop();
| ^^^^ cannot move out of borrowed content
The simpler solution is to use an Option to wrap the Reader.
An Option has a take method which returns the content (and puts None in the Option), then you can place the Reader back by assigning.
struct Container<'a> {
reader: Option<Reader<'a, File>>
}
fn update(&mut self) {
let writer = self.reader.take().unwrap().as_writer();
^~~~~~~
writer.write_something();
self.reader = Some(writer.as_reader());
^~~~~ ^
}
Building on Matthieu's answer I figured it's straightforward to add a (trivial) wrapper around the Option to enforce compile time checks that only allow "borrowing" the Reader instance while requiring another one is returned afterwards.
struct State<T>(Option<T>);
impl<T> State<T> {
pub fn new(val: T) -> Self {
State(Some(val))
}
pub fn modify<F>(&mut self, fun: F)
where F: FnOnce(T) -> T
{
self.0 = Some(fun(self.0.take().unwrap()));
}
}
Usage:
fn modify(&mut self) {
self.state.modify(|reader| {
let writer = reader.as_writer();
writer.write_something();
writer.as_reader()
}
}
Should be good enough to avoid accidental misuses. No idea about panic! unwindings though.
Probably not following Rust naming conventions, state and modify come from Haskell's State.

Resources