Closed mcy closed 3 years ago
I strongly endorse this. I'd almost like to see the &move
emulation in a separate crate which moveit
then puts C++-style constructors on top of, but that's not really necessary.
As for reconstructing a moved-from box: this shouldn't need MoveRef<T>
to carry a drop flag. The pointee drops only when the &move T
drops, so there's no need to add another drop flag. Instead, I imagine a scheme like the following:
let owner: Box<T>;
// inhibit the inner destructor
let owner: MovedFrom<Box<T>> = MovedFrom::new(owner); // roughly, Box<ManuallyDrop<T>>
// extract a &move
let reference: RefMove<'a, T> = RefMove::new_unchecked(&'a mut owner);
// Do whatever with `reference` & `owner`
// If you still have `reference`, the pointee isn't dropped
// If you still have `owner`, the storage isn't dropped
// recombine
let owner: Box<T> = MovedFrom::revive(owner, reference);
If you want to get really tricky, you can manifest a generative lifetime brand to make revival safe without any checks. However, I think revival like this is a super niche thing that almost certainly wouldn't even be supported by a language &move
, so not necessary to cover here.
Actually, wait: there's no possible way to support reuniting a moved-from location with its MoveRef
'd value, while respecting both "dropping &move T
drops T
" and the borrow rules. This is because, well, you can't use the location until you drop the &move T
, so you can't actually touch the location to reunite it with the &move T
.
If "&move inout
" is to be supported, it should be a different type. This is &move out
, and that's simple enough, so we should have it.
I came to the same conclusion. I want to start layering more stuff on top of this work, and I don't think that &move inout
is super interesting at the moment.
This PR attempts to unify
P: MoveRef
andStackBox
into one type:MoveRef
, which approximates an&move T
reference.There are still one big open problem I don't have a solution for:
Once you
moveit!(let x = &move *y);
a value, you cannot undo it. It would be useful to be able to take aMoveRef<T>
out of aBox<T>
, do some non-destructive stuff to it (like a swap) and then release theMoveRef<T>
and get theBox<T>
back. One way I can see to do this is to add some kind ofMoveCell<P>
that wraps aDerefMove
, which contains a drop flag next to it. Then,MoveRef<T>
becomes a(&mut T, &mut bool)
to be able to flip the drop flag, which controls whether the inner dtor has been run or not. This has several downsides, including makingMoveRef
two pointers wide. Admittedly, I can't imagine a way the compiler could implement&move T
on the nose without having some way to carry around the drop flag, if&move T
going out of scope releases the borrow.