[Pre-RFC] pattern matching std::pin::Pin, converting &mut T to Pin and narrowing scope

When looking at std::pin::Pin it seemed that following operations should be safe - narrowing scope, converting &mut T into Pin<&mut T> and pin pattern matching.

struct Map<F, G> {
    future: F,
    func: Option<G>
impl<F, G, B> Future for Map<F,G>
    F: Future,
    G: FnOnce(Future::Output) -> B + Unpin
    type Output = B;
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>
        // future: Pin<&mut F>
        // func: &Option<FnOnce(Future::Output) -> B>
        // To have lack of pin it needs to be Unpin
        let Map {pin ref mut future, ref mut func} = self;
        match future.poll(cx) {
            Ready(value) => Ready(func.take().expect("Map value already consumed")(value)),
            Pending => Pending.

Converting &mut T into Pin<&mut T> - since &mut T is an exclusive reference to T any access to T needs to be done by this reference. So we can temporarily pin it as we know no-one will move the value from underneath us:

impl<'a, T> Pin<&'a mut T> {
    pub fn new_from_mut(&'a mut T) -> Self;

Narrowing scope (Pin is contravariant in scope):

impl<'a> Pin<&'a T> {
    fn narrow<'b>(&'mut self) -> Pin<&'b T> where 'a: 'b

If data is unmovable in larger scope it is also unmovable in smaller scope.

Pattern matching - currently field access is under unsafe. However this seems to be unnecessarily restrictive. However we already have a pattern matching on references so pin might make sense:

struct FlatMap<F, G, H> {
    BeforeF(F, Option<G>),

impl<B> Future for FlatMap<B, F, G, H>
    F: Future<Output = B>,
    G: FnOnce(B) -> H + Unpin,
    H: Future
    type Output = H::Output;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>
        let new_h_opt = if let FlatMap::BeforeF(pin ref mut future, ref mut func) = self.narrow() {
            match future.poll(cx) {
                Ready(value) => Some(func.take().unwrap()(value)),
                Pending => return Pending;
        } else {
        if let Some(new_h) = new_h_opt {
        if let FlatMap::BeforeH(pin ref mut future) {
        } else {

I don't see any related proposals and my (very basic) understanding of Pin indicates those operations should be safe

1 Like

You can't do this, once a value is pinned, it must remain pinned for the rest of it's lifetime (until it's dropped)

From the pin module docs (emphasis mine)

At a high level, a Pin<P> ensures that the pointee of any pointer type P has a stable location in memory, meaning it cannot be moved elsewhere and its memory cannot be deallocated until it gets dropped

You can also use



(Unless it implements Unpin.)


Regarding projections, every type can decide which fields it pins and which not. It may leave some fields unpinned even if they don't implement Unpin. If a field is left unpinned, it is just not allowed to take an Pin<&mut T> for that field in that case. If the field is pinned and not Unpin it is not allowed to take an &mut T unless it isn't exposed to the user and the pinning invariants are maintained.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.