# \[post\] Safe pin projections through view types

**URL:** <https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248>\
**Category:** language design\
**Created:** [March 4, 2022, 3:12pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248 "2022-03-04T15:12:07Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![yoshuawuyts](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yoshuawuyts/32/3712_2.png) [@yoshuawuyts](https://internals.rust-lang.org/u/yoshuawuyts)\
**Post date:** [March 4, 2022, 3:12pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/1 "2022-03-04T15:12:07Z")

</div>

Hey all, I wrote an idea I had of how we could potentially use [Niko's idea for "view types"](http://smallcultfollowing.com/babysteps/blog/2021/11/05/view-types/) to create safe [pin projections](https://docs.rs/pin-project/latest/pin_project/) - and the general challenges of creating safe pin projections in Rust. It's intentionally less researched than some of my other posts, but I figured the idea was interesting enough that it was worth writing down. I hope y'all like it!

> **[Safe Pin Projections Through View Types](https://blog.yoshuawuyts.com/safe-pin-projections-through-view-types/)**

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [March 4, 2022, 3:46pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/2 "2022-03-04T15:46:49Z")

</div>

One thing I think this misses is that another key part of pin projection is that it's _consistent_. If you project a field as pinned in one function, you can't project it as unpinned in another, and vice versa.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [March 4, 2022, 3:48pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/3 "2022-03-04T15:48:51Z")

</div>

> Perhaps the compiler can be clever enough to infer that all `!Unpin` types in a view type should remain pinned when viewed.

I think this is unsound because I can have a type implement `Unpin` even if its fields do not. This means I can freely pin and unpin it, but after projecting it and getting a `Pin<&mut NotUnpinField>` then it must remain pinned.

You then propose to move the annotation on the `self` parameter of the functions, but this is equally problematic. Moreover you could also have two functions disagree on which field is pinned, creating problems even if `Self` is `!Unpin`.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [March 4, 2022, 3:59pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/4 "2022-03-04T15:59:45Z")

</div>

Another interesting edge case is a pin-unpin-pin sandwich; if `&unpin` is never leaked outside the safety barrier, you could in theory structurally project the pinning from the outer pinned type to the inner pinned field.

It'd be horrible, awful API design, and painfully unsafe and prone to accidentally becoming plain unsound, but it's theoretically allowed.

---

<div class="post-metadata">

**Author:** ![yoshuawuyts](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yoshuawuyts/32/3712_2.png) [@yoshuawuyts](https://internals.rust-lang.org/u/yoshuawuyts)\
**Post date:** [March 4, 2022, 4:37pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/5 "2022-03-04T16:37:58Z")

</div>

> [@SkiFire13](#):
>
> I think this is unsound because I can have a type implement `Unpin` even if its fields do not. This means I can freely pin and unpin it, but after projecting it and getting a `Pin<&mut NotUnpinField>` then it must remain pinned.

You're entirely right. A few paragraphs down in the "Unpin" section we go into this in more detail. In order for pin projections to be safe I believe we would need to change the `Unpin` trait be `unsafe`.

Whether going through the trouble of making that change is worth the effort is a good question. Because as things are today, we very much don't have a process for making this type of change in the stdlib.

> [@CAD97](#):
>
> Another interesting edge case is a pin-unpin-pin sandwich; if `&unpin` is never leaked outside the safety barrier, you could in theory structurally project the pinning from the outer pinned type to the inner pinned field.

Oh interesting, I hadn't thought of that. I'm familiar with other language sandwiches, so I think I get what you mean. But I'd love to see an example of this if you could share one?

---

<div class="post-metadata">

**Author:** ![yoshuawuyts](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yoshuawuyts/32/3712_2.png) [@yoshuawuyts](https://internals.rust-lang.org/u/yoshuawuyts)\
**Post date:** [March 4, 2022, 5:12pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/6 "2022-03-04T17:12:44Z")

</div>

> [@CAD97](#):
>
> One thing I think this misses is that another key part of pin projection is that it's _consistent_ . If you project a field as pinned in one function, you can't project it as unpinned in another, and vice versa.

I believe this only applies if a field is `!Unpin`? If a field is `Unpin` you can freely move it in and out of `Pin` containers because it doesn't matter if it's pinned. This is why for example we can call [`Pin<&mut T: Unpin>::get_mut`](https://doc.rust-lang.org/std/pin/struct.Pin.html#method.get_mut) which we can then pass to `mem::swap` to get the owned value out of. If `Unpin` values always had to be contained in a `Pin` container, I don't believe that method would be sound?

You're right that I didn't write out all the details I should have. That's on me. I was thinking that if we could make pin projections safe \[1\], then going from a `Pin<&mut T>` to its fields, any field which is `!Unpin` would _require_ being pinned in the projection. Failure to do so would result in a compiler error.

```plaintext
error[E0752]: cannot project `timer` as it's not marked `pin`
 --> src/main.rs:8:1
  |
8 | fn poll(self: pin Self { timer, completed }, cx: &mut Context<'_>) -> Poll<Self::Output> {
  | ----- help: consider changing this to be pin: `pin timer`

```

* * *

1. As mentioned in the post: to make pin projecting _safe_ we can't simply use view types. `Drop`, `Unpin`, `#[repr(packed)]` are all involved too. This reply assumes we've figured out all the details to get "safe pin projections".

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [March 4, 2022, 7:19pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/7 "2022-03-04T19:19:46Z")

</div>

> [@yoshuawuyts](#):
>
> You're right that I didn't write out all the details I should have. That's on me. I was thinking that if we could make pin projections safe [[1]](#footnote-107344-1), then going from a `Pin<&mut T>` to its fields, any field which is `!Unpin` would _require_ being pinned in the projection. Failure to do so would result in a compiler error.

In other words, you're saying that, instead of having an explicit choice anywhere of whether each field should be projected as pin or non-pin, they would just all be projected as pin? (Modulo `Unpin`, where it doesn't matter.)

If so, I don't see the advantage of linking this to view types or destructuring in function signatures. Why not 'just' extend dot syntax so that given a `Pin<&mut MyStruct>`, you can write, e.g., `&mut pin my_struct.my_field`, and it turns into `Pin<&mut MyField>`? Sure, there could also be a destructuring version, so that you could write something like `let MyStruct { pin my_field } = my_struct;`. And naturally you could use that in function signatures as well. And if view types are added to the language, there would presumably be some interaction there. But for the most part they seem like orthogonal features.

I see how the two features would be connected if you were using the signatures of methods on a struct as an implicit means to make "project field as pin or non-pin" decisions _for the struct itself_. In that case, the decision of whether to obtain a field as pinned or non-pinned would be part of the API and affect other code – similar to how, in the original view types proposal, the list of fields that a method borrows would be part of the API and affect callers. So it makes sense that it must be surfaced in the function signature. But then you run into the issue @CAD97 mentioned that the projection must be consistent.

> But rather than thinking about pin as "introducing issues into Rust", what if we instead think of pin as "surfacing issues we have in Rust". Pin is a fundamental type in Rust. Transformative even.

Obligatory derail: I still think `Pin` is the wrong answer to the right question. It was designed to work without making any language changes, and at that goal it succeeded, but at the cost of picking up unnecessary complexity and limitations. Bringing native language support for `Pin` can at best somewhat reduce that unnecessary complexity, but at worst it could multiply it (something which I get hints of here, e.g. with the suggestion to change `Drop::drop` signature but have existing impls magically work anyway). `!Move` seems scary, but in the long run it's less complex than `Pin` and more powerful; it's not too late.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [March 4, 2022, 7:23pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/8 "2022-03-04T19:23:50Z")

</div>

`Pin` is not the only type where having better support for projections would be good, another example is `Cell` -- given `&Cell<Struct>` it would be nice to be able to obtain `&Cell<Field>`. Does the approach proposed here scale to also handle that more general case?

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [March 4, 2022, 10:00pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/9 "2022-03-04T22:00:58Z")

</div>

> [@RalfJung](#):
>
> `Pin` is not the only type where having better support for projections would be good, another example is `Cell` -- given `&Cell<Struct>` it would be nice to be able to obtain `&Cell<Field>` . Does the approach proposed here scale to also handle that more general case?

And `MaybeUninit<T>`, and `UnsafeCell<T>`, and the proposed `VolatileCell<T>`. And we could create an `Unaligned<T>` as a safer and more powerful alternative to `#[repr(packed)]`. (We could create it today, but without field projection I think the ergonomics wouldn't be good enough.)

Depending on how the feature is designed, it might be possible to apply to reference-counted pointers. Imagine if you could go from `Rc<Struct>` to some kind of `MappedRc<Field>`, a hypothetical type that represents a +1 to the reference count of the whole `Struct` but derefs to the `Field` – similar to what C++ `shared_ptr` can do.

And perhaps it could even tie into the [raw pointer projections in-bounds discussion](https://github.com/rust-lang/unsafe-code-guidelines/issues/319#issuecomment-1057192333). If you imagine `&T` as the 'fundamental pointer type' and all these other types as variant pointer types (regardless of where the `&` goes: contrast `&Cell<T>`, `Pin<&T>`, and `Rc<T>`), then `*const T` itself could be seen as another variant pointer type.

There's definitely enormous potential here.

---

<div class="post-metadata">

**Author:** ![yoshuawuyts](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yoshuawuyts/32/3712_2.png) [@yoshuawuyts](https://internals.rust-lang.org/u/yoshuawuyts)\
**Post date:** [March 4, 2022, 10:19pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/10 "2022-03-04T22:19:56Z")

</div>

Oh that's interesting; I hadn't thought of that. Perhaps it could be, I'm not sure. I guess I can't immediately think of an example of what you're describing; if you could share one that'd be very helpful!

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [March 5, 2022, 3:10am UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/11 "2022-03-05T03:10:26Z")

</div>

Turns out there's even a crate for this: [cell\_project - Rust](https://docs.rs/cell-project/latest/cell_project/)

---

<div class="post-metadata">

**Author:** ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)\
**Post date:** [March 5, 2022, 12:12pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/12 "2022-03-05T12:12:04Z")

</div>

The key idea was also mentioned in an older thread about generic field projection. History that I know of:

- this prior internals post: [[Idea] Pointer to Field](https://internals.rust-lang.org/t/idea-pointer-to-field/10061)
- lead to this RFC: [Generic Pointer to Field by RustyYato · Pull Request #2708 · rust-lang/rfcs · GitHub](https://github.com/rust-lang/rfcs/pull/2708)
- that lead to this prototype: [GitHub - RustyYato/generic-field-projection: This crate was created to implement the ideas in this RFC #rust-lang/rfcs/2708](https://github.com/RustyYato/generic-field-projection)
- which was recently touched upon in unsafe-guidelines: [Should raw pointer deref/projections have to be in-bounds? · Issue #319 · rust-lang/unsafe-code-guidelines · GitHub](https://github.com/rust-lang/unsafe-code-guidelines/issues/319#issuecomment-1049316167)

I believe the last point at least touches on the subject mentioned for closing the RFC. If outstanding semantic difficulties of pointer offsetting _could_ be solved by field-projection then that's seems like a clear case for moving from a library to a language feature.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [June 3, 2022, 12:12pm UTC](https://internals.rust-lang.org/t/post-safe-pin-projections-through-view-types/16248/13 "2022-06-03T12:12:52Z")

</div>

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