Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #![feature(pin)]
- use std::pin::PinBox;
- use std::marker::Pinned;
- use std::ptr::NonNull;
- // This is a self referencial struct since the slice field points to the data field.
- // We cannot inform the compiler about that with a normal reference,
- // since this pattern cannot be described with the usual borrowing rules.
- // Instead we use a raw pointer, though one which is known to not be null,
- // since we know it's pointing at the string.
- struct Unmovable {
- data: String,
- slice: NonNull<String>,
- _pin: Pinned,
- }
- impl Unmovable {
- // To ensure the data doesn't move when the function returns,
- // we place it in the heap where it will stay for the lifetime of the object,
- // and the only way to access it would be through a pointer to it.
- fn new(data: String) -> PinBox<Self> {
- let res = Unmovable {
- data,
- // we only create the pointer once the data is in place
- // otherwise it will have already moved before we even started
- slice: NonNull::dangling(),
- _pin: Pinned,
- };
- let mut boxed = PinBox::new(res);
- let slice = NonNull::from(&boxed.data);
- // we know this is safe because modifying a field doesn't move the whole struct
- unsafe { PinBox::get_mut(&mut boxed).slice = slice };
- boxed
- }
- }
- fn main() {
- let unmoved = Unmovable::new("hello".to_string());
- // The pointer should point to the correct location,
- // so long as the struct hasn't moved.
- // Meanwhile, we are free to move the pointer around.
- let mut still_unmoved = unmoved;
- assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));
- // Since our type doesn't implement Unpin, this will fail to compile:
- let new_unmoved = Unmovable::new("world".to_string());
- std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
- }
Add Comment
Please, Sign In to add comment