-
-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement replace()
method to move out of struct/enum
#184
Comments
I was working on something very similar to this, but never quite finished. I can finish it up and open a PR. |
It seems that this can be replaced by wrapping the unpinned field with an Option. #[pin_project]
enum Example {
A(#[pin] PinnedValue),
B(Option<UnpinnedValue>),
C,
}
#[project]
match self.as_mut().project() {
Example::A(_) => { /* ... */ },
Example::B(value @ Some(_)) => {
let value = value.take().unwrap();
// ...
},
Example::B(None) | Example::C => {},
}
self.set(Example::C); // When using this way, whether you should replace self depends on the situation. |
It seems reasonable to add this, given that it increases the size if use Option and that we cannot easily change the public type signature. |
Assigning to @Aaron1011 based on the previous comment (feel free to unassign). |
IIUC, macro needs to generate an additional struct/enum to support this. @Aaron1011: Do you think it preferable to add a feature like #124 to implement this? (I feel the existing project-attribute-based approach becomes bothered as more types are generated.) |
In order to be panic-safe, it will need to generate code something like: struct DropInPlaceHelper<T>(*mut T);
impl<T> DropInPlaceHelper<T> {
fn drop(&mut self) {
ptr::drop_in_place(self.0);
}
}
struct OverwriteHelper<T>(*mut T, MaybeUninit<T>);
impl<T> OverwriteHelper<T> {
fn drop(&mut self) {
ptr::write(self.0, self.1.assume_init());
}
}
fn partial_replace(ptr: *mut Foo, new_value: Foo) -> Y {
let _helper0 = OverwriteHelper(ptr, MaybeUninit::new(new_value));
let _helper1 = DropInPlaceHelper(&mut (*ptr).pinned_field1);
let _helper2 = DropInPlaceHelper(&mut (*ptr).pinned_field2);
let _helper3 = DropInPlaceHelper(&mut (*ptr).pinned_field3);
ptr::read(&mut (*ptr).unpinned_field)
} |
(Maybe we need to wait for rust-lang/unsafe-code-guidelines#232 discussion?) |
Replacing a pinned value is safe as long as the destructors of types which do not implement
Unpin
are called.Pin::set allows replacing the whole value, but it does not allow recovering the un-pinned fields, so the idea is to provide a method to achieve this.
The API would look something like:
The text was updated successfully, but these errors were encountered: