Skip to content

Instantly share code, notes, and snippets.

@withoutboats
Created August 13, 2018 13:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save withoutboats/f6d715ae8b8210cf8dc8090e95578580 to your computer and use it in GitHub Desktop.
Save withoutboats/f6d715ae8b8210cf8dc8090e95578580 to your computer and use it in GitHub Desktop.

We add a built in attribute for handling pin projection:

struct MyCombinator<F> {
    #[pin_accessor]
    field: F,
}

This generates a method fn field_pin(self: PinMut<'_, Self>) -> PinMut<'_, F>, and also generates these constraints:

  1. for<F> MyCombinator<F>: Unpin implies F: Unpin
  2. for<F> MyCombinator<F>: PinDrop or for<F: MyCombinator<F>: !Drop

This requires no unsafe code to perform pin projections.

Unpin

The unpin constraint is an implies constraint, we generate a query about the relationship between the field type and the self type. There's no way to generate a constraint like this in the surface syntax of Rust today, but the compiler builtin could.

The current compiler is not structured to solve this kind of constraint, but chalk is. Further integration of strategies from chalk into rustc is necessary before this kind of constraint could be generated.

PinDrop

We add a new, special trait, to the standard library:

trait PinDrop: Drop {
    fn pin_drop(self: PinMut<Self>);
}

impl<T: PinDrop> Drop for T {
     fn drop(&mut self) {
         pinned!(self);
         self.pin_drop();
     }
}

(This trait is special because this kind of blanket impl is not actually allowed in library Rust, so it would have to be implemented internally).

If a type using the #[pin_accessor] attribute needs a destructor, it must use the PinDrop trait, rather than the Drop trait. That way, it is guaranteed that it does not move out of the tagged field in safe code (unless the field implements Unpin).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment