When building primitives for futures (like Inspect
), we often need partial pinning. I think this is done by first defining which fields we are pinning, and then apply this to the Unpin
impl and projection helpers. In the Inspect
example, we’re pinning the future
field, but f
not.
However, although partial pinning is defined for each field in programmers’ mind, they instead implicitly appear in the implementations. I see this as a possible footgun.
Isn’t it clever to provide this tiny wrapper for partial pinning? It’s easy to use: you wrap non-pinned fields using this. You don’t need to carefully implement Unpin
. Pin projections simply work. I’d name it Kite
because a kite floats around even when its root is pinned.
#![feature(pin)]
use std::ops::{Deref, DerefMut};
use std::pin::Unpin;
pub struct Kite<T: ?Sized> {
inner: T,
}
impl<T: ?Sized> Unpin for Kite<T> {}
impl<T> Kite<T> {
pub fn new(inner: T) -> Self {
Self { inner }
}
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T: ?Sized> Deref for Kite<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T: ?Sized> DerefMut for Kite<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
Usage
This is taken from the Inspect
example above.
pub struct Inspect<Fut, F> where Fut: Future {
future: Fut, // This is a pinned field
f: Option<F>, // This is a non-pinned field
}
impl<Fut: Future, F: FnOnce(&Fut::Output)> Inspect<Fut, F> {
// `unsafe_pinned!` for pinned fields, `unsafe_unpinned!` for non-pinned fields.
unsafe_pinned!(future: Fut);
unsafe_unpinned!(f: Option<F>);
}
// Require `Unpin` for pinned field types.
impl<Fut: Future + Unpin, F> Unpin for Inspect<Fut, F> {}
With Kite
, you can just wrap f
.
pub struct Inspect<Fut, F> where Fut: Future {
future: Fut,
f: Kite<Option<F>>,
}
impl<Fut: Future, F: FnOnce(&Fut::Output)> Inspect<Fut, F> {
// No difference here
unsafe_pinned!(future: Fut);
unsafe_pinned!(f: Kite<Option<F>>);
}
// No need to implement `Unpin` manually
One pitfall is that when doing pin projection, someone may accidentally go across the Kite
barrier.