pin-project
/pin-project-lite
is the primary way Rustaceans project a pin from a type, T
, to one of its fields when the field is ?Unpin
. Is there an idiomatic way to project a pin to a field of a field when the innermost field is ?Unpin
?
use core::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use pin_project::pin_project;
struct Foo<T>(T);
#[pin_project]
struct Bar<T>(#[pin] Foo<T>);
impl<T: Future> Future for Bar<T> {
type Output = T::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// This is more concise and relies on the same amount of
// `unsafe` code as the commented out portion.
// SAFETY:
// This is okay because `self.0.0` is pinned when `self` is.
let p = unsafe { self.map_unchecked_mut(|f| &mut f.0 .0) };
p.poll(cx)
//let projected_foo = self.project().0;
//let p = unsafe { projected_foo.map_unchecked_mut(|f| &mut f.0) };
//p.poll(cx)
}
}
I realize this is rather contrived. For example Foo
would likely be defined in a separate crate; and unless Bar
knows Foo
doesn't implement Unpin
for T: ?Unpin
, then PhantomPinned
would need to be added to Bar
to prevent it from auto implementing Unpin
.
In this example, I think § Choosing pinning to be structural for field
… only needs to be amended such that "inner field" is substituted for "field" (e.g., item 1 requires Bar
to not implement Unpin
when Foo
's field is ?Unpin
).
Edit
The primary motivation behind this question is comprehension. Most (all?) of the time pin-project
would be enough. I'm trying to understand if the rules mentioned in the pin
module only apply to fields directly contained in the type or can they be generalized to any field in the object graph. If they can't be generalized, why?
There is nothing special about Foo
either. If Bar
is unable to project to Foo
's T
field, then that would seem to mean that even if Bar
contained a primitive type that doesn't explicitly provide a pin projection method, it would be unable to project to the contained data. For example if Bar
contained (T, T2)
, tuples don't provide pin projection methods; thus Bar
would seemingly not be able to construct a Pin<&mut T>
. I find that hard to believe.
13 posts - 5 participants