Skip to content

Commit 53a6021

Browse files
author
boats
committed
No Pin/PinMut distinction.
1 parent 0e67fad commit 53a6021

File tree

1 file changed

+70
-79
lines changed

1 file changed

+70
-79
lines changed

text/0000-pin.md

Lines changed: 70 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ Let's take that goal apart, piece by piece, from the perspective of the futures
3636

3737
At the same time, we want to support futures (and iterators, etc.) that *can* move. While it's possible to do so by providing two distinct `Future` (or `Iterator`, etc) traits, such designs incur unacceptable ergonomic costs.
3838

39-
The key insight of this RFC is that we can create a new library type, `PinMut<'a, T>`, which encompasses *both* moveable and immobile referents. The type is paired with a new auto trait, `Unpin`, which determines the meaning of `PinMut<'a, T>`:
39+
The key insight of this RFC is that we can create a new library type, `Pin<'a, T>`, which encompasses *both* moveable and immobile referents. The type is paired with a new auto trait, `Unpin`, which determines the meaning of `Pin<'a, T>`:
4040

41-
- If `T: Unpin` (which is the default), then `PinMut<'a, T>` is entirely equivalent to `&'a mut T`.
42-
- If `T: !Unpin`, then `PinMut<'a, T>` provides a unique reference to a `T` with lifetime `'a`, but only provides `&'a T` access safely. It also guarantees that the referent will *never* be moved. However, getting `&'a mut T` access is unsafe, because operations like `mem::replace` mean that `&mut` access is enough to move data out of the referent; you must promise not to do so.
41+
- If `T: Unpin` (which is the default), then `Pin<'a, T>` is entirely equivalent to `&'a mut T`.
42+
- If `T: !Unpin`, then `Pin<'a, T>` provides a unique reference to a `T` with lifetime `'a`, but only provides `&'a T` access safely. It also guarantees that the referent will *never* be moved. However, getting `&'a mut T` access is unsafe, because operations like `mem::replace` mean that `&mut` access is enough to move data out of the referent; you must promise not to do so.
4343

44-
To be clear: the *sole* function of `Unpin` is to control the meaning of `PinMut`. Making `Unpin` an auto trait means that the vast majority of types are automatically "movable", so `PinMut` degenerates to `&mut`. In the case that you need immobility, you *opt out* of `Unpin`, and then `PinMut` becomes meaningful for your type.
44+
To be clear: the *sole* function of `Unpin` is to control the meaning of `Pin`. Making `Unpin` an auto trait means that the vast majority of types are automatically "movable", so `Pin` degenerates to `&mut`. In the case that you need immobility, you *opt out* of `Unpin`, and then `Pin` becomes meaningful for your type.
4545

4646
Putting this all together, we arrive at the following definition of `Future`:
4747

@@ -50,13 +50,13 @@ trait Future {
5050
type Item;
5151
type Error;
5252

53-
fn poll(self: PinMut<Self>, cx: task::Context) -> Poll<Self::Item, Self::Error>;
53+
fn poll(self: Pin<Self>, cx: &mut task::Context) -> Poll<Self::Item, Self::Error>;
5454
}
5555
```
5656

57-
By default when implementing `Future` for a struct, this definition is equivalent to today's, which takes `&mut self`. But if you want to allow self-referencing in your future, you just opt out of `Unpin`, and `PinMut` takes care of the rest.
57+
By default when implementing `Future` for a struct, this definition is equivalent to today's, which takes `&mut self`. But if you want to allow self-referencing in your future, you just opt out of `Unpin`, and `Pin` takes care of the rest.
5858

59-
This RFC also provides pinned analogies to `Box` and `&T` - `PinBox<T>` and `Pin<T>`. They work along the same lines as the `PinMut` type discussed here - if the type implements `Unpin`, they function the same as their unpinned varieties; if the type has opted out of `Unpin`, they guarantee that they type behind the reference will not be moved again.
59+
This RFC also provides a pinned analogiy to `Box` called `PinBox<T>`. It work alongs the same lines as the `Pin` type discussed here - if the type implements `Unpin`, it functions the same as the unpinned `Box`; if the type has opted out of `Unpin`, it guarantees that they type behind the reference will not be moved again.
6060

6161
# Reference-level explanation
6262

@@ -80,109 +80,87 @@ generators. Unlike previous `?Move` proposals, and unlike some traits like
8080
types that do or don't implement it. Instead, the semantics are entirely
8181
enforced through library APIs which use `Unpin` as a marker.
8282

83-
## `Pin` and `PinMut`
83+
## `Pin`
8484

85-
`Pin` and `PinMut` are two types added to `core::mem` and `std::mem`. They are
86-
analogous to `&T` and `&mut T` respectively.
85+
The `Pin` struct is added to both `core::mem` and `std::mem`. It is a new kind
86+
of reference, with stronger requirements than `&mut T`
8787

8888
```rust
8989
#[fundamental]
9090
pub struct Pin<'a, T: ?Sized + 'a> {
91-
data: &'a T,
92-
}
93-
94-
#[fundamental]
95-
pub struct PinMut<'a, T: ?Sized + 'a> {
9691
data: &'a mut T,
9792
}
9893
```
9994

10095
### Safe APIs
10196

102-
They both implement `Deref`, but `PinMut` only implements `DerefMut` if the
103-
type it references implements `Unpin`:
97+
`Pin` implements `Deref`, but only implements `DerefMut` if the type it
98+
references implements `Unpin`. This way, it is not safe to call `mem::swap` or
99+
`mem::replace` when the type referenced does not implement `Unpin`.
104100

105101
```rust
106102
impl<'a, T: ?Sized> Deref for Pin<'a, T> { ... }
107103

108-
impl<'a, T: ?Sized> Deref for PinMut<'a, T> { ... }
109-
110-
impl<'a, T: Unpin + ?Sized> DerefMut for PinMut<'a, T> { ... }
104+
impl<'a, T: Unpin + ?Sized> DerefMut for Pin<'a, T> { ... }
111105
```
112106

113-
They can only be safely constructed from references to types that implement
107+
It can only be safely constructed from references to types that implement
114108
`Unpin`:
115109

116110
```rust
117111
impl<'a, T: Unpin + ?Sized> Pin<'a, T> {
118-
pub fn new(reference: &'a T) -> Pin<'a, T> { ... }
119-
}
120-
121-
impl<'a, T: Unpin + ?Sized> PinMut<'a, T> {
122-
pub fn new(reference: &'a mut T) -> PinMut<'a, T> { ... }
112+
pub fn new(reference: &'a mut T) -> Pin<'a, T> { ... }
123113
}
124114
```
125115

126-
They also have a `borrow` function, which allows them to be transformed to pins
127-
with shorter lifetimes as may be necessary:
116+
It also has a function called `borrow`, which allows it to be transformed to a
117+
pin of a shorter lifetime:
128118

129119
```rust
130120
impl<'a, T: ?Sized> Pin<'a, T> {
131-
pub fn borrow<'b>(this: &'b Pin<'a, T>) -> Pin<'b, T> { ... }
132-
}
133-
134-
impl<'a, T: ?Sized> PinMut<'a, T> {
135-
pub fn borrow<'b>(this: &'b PinMut<'a, T>) -> PinMut<'b, T> { ... }
121+
pub fn borrow<'b>(this: &'b mut Pin<'a, T>) -> Pin<'b, T> { ... }
136122
}
137123
```
138124

139-
They may also implement additional APIs as is useful for type conversions, such
140-
as `AsRef`, `From`, and so on. They implement `CoerceUnsized` as necessary to
125+
It may also implement additional APIs as is useful for type conversions, such
126+
as `AsRef`, `From`, and so on. `Pin` implements `CoerceUnsized` as necessary to
141127
make coercing them into trait objects possible.
142128

143129
### Unsafe APIs
144130

145-
Both types can be unsafely constructed from references to types which may not
146-
implement `Unpin`. Users who use these constructors must know that the type
147-
they are passing a reference to will never be moved again after the Pin is
148-
constructed.
131+
`Pin` can be unsafely constructed from mutable references to types that may not
132+
implement `Unpin`. Users who use this constructor must know that the type
133+
they are passing a reference to will never be moved again after the `Pin` is
134+
constructed, even after the lifetime of the reference has ended. (For example,
135+
it is always unsafe to construct a `Pin` from a reference you did not create,
136+
because you don't know what will happen once the lifetime of that reference
137+
ends.)
149138

150139
```rust
151140
impl<'a, T: ?Sized> Pin<'a, T> {
152-
pub unsafe fn new_unchecked(reference: &'a T) -> Pin<'a, T> { ... }
153-
}
154-
155-
impl<'a, T: ?Sized> PinMut<'a, T> {
156-
pub unsafe fn new_unchecked(reference: &'a mut T) -> PinMut<'a, T> { ... }
141+
pub unsafe fn new_unchecked(reference: &'a mut T) -> Pin<'a, T> { ... }
157142
}
158143
```
159144

160-
`PinMut` also has an API which allows it to be converted into a mutable
161-
reference for a type that doesn't implement `Unpin`. Users who use this API
162-
must guarantee that they never move out of the mutable reference they receive.
145+
`Pin` also has an API which allows it to be converted into a mutable reference
146+
for a type that doesn't implement `Unpin`. Users who use this API must
147+
guarantee that they never move out of the mutable reference they receive.
163148

164149
```rust
165-
impl<'a, T: ?Sized> PinMut<'a, T> {
166-
pub unsafe fn get_mut<'b>(this: &'b mut PinMut<'a, T>) -> &'b mut T { ... }
150+
impl<'a, T: ?Sized> Pin<'a, T> {
151+
pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T { ... }
167152
}
168153
```
169154

170-
Finally, as a convenience, they both implement an unsafe `map` function, which
155+
Finally, as a convenience, `Pin` implements an unsafe `map` function, which
171156
makes it easier to project through a field. Users calling this function must
172157
guarantee that the value returned will not move as long as the referent of this
173158
pin doesn't move (e.g. it is a private field of the value). They also must not
174-
move out of the mutable reference they receive as the closure argument, in the
175-
case of `PinMut`:
159+
move out of the mutable reference they receive as the closure argument:
176160

177161
```rust
178162
impl<'a, T: ?Sized> Pin<'a, T> {
179-
pub unsafe fn map<'b, U, F>(this: &'b Pin<'a, T>, f: F) -> Pin<'b, U>
180-
where F: FnOnce(&T) -> &U
181-
{ ... }
182-
}
183-
184-
impl<'a, T: ?Sized> PinMut<'a, T> {
185-
pub unsafe fn map<'b, U, F>(this: &'b mut PinMut<'a, T>, f: F) -> PinMut<'b, U>
163+
pub unsafe fn map<'b, U, F>(this: &'b mut Pin<'a, T>, f: F) -> Pin<'b, U>
186164
where F: FnOnce(&mut T) -> &mut U
187165
{ ... }
188166
}
@@ -193,15 +171,20 @@ struct Foo {
193171
}
194172

195173
let foo_pin: Pin<Foo>;
196-
// ...
197-
let bar_pin: Pin<Bar> = unsafe { Pin::map(&foo_pin, |foo| &foo.bar) };
174+
175+
let bar_pin: Pin<Bar> = unsafe { Pin::map(&mut foo_pin, |foo| &mut foo.bar) };
176+
// Equivalent to:
177+
let bar_pin: Pin<Bar> = unsafe {
178+
let foo: &mut Foo = Pin::get_mut(&mut foo_pin);
179+
Pin::new_unchecked(&mut foo.bar)
180+
};
198181
```
199182

200183
## `PinBox`
201184

202185
The `PinBox` type is added to alloc::boxed and std::boxed. It is analogous to
203-
the `Box` type in the same way that `Pin` and `PinMut` are analogous to the
204-
reference types, and it has a similar API.
186+
the `Box` type in the same way that `Pin` is analogous to the reference types,
187+
and it has a similar API.
205188

206189
```rust
207190
#[fundamental]
@@ -212,8 +195,8 @@ pub struct PinBox<T: ?Sized> {
212195

213196
### Safe API
214197

215-
Unlike the other pin types, it is safe to construct a `PinBox` from a `T` and
216-
from a `Box<T>`:
198+
Unlike `Pin`, it is safe to construct a `PinBox` from a `T` and from a
199+
`Box<T>`, even if the type does not implement `Unpin`:
217200

218201
```rust
219202
impl<T> PinBox<T> {
@@ -225,7 +208,7 @@ impl<T: ?Sized> From<Box<T>> for PinBox<T> {
225208
}
226209
```
227210

228-
It also provides the same Deref impls as `PinMut` does:
211+
It also provides the same Deref impls as `Pin` does:
229212

230213
```rust
231214
impl<T: ?Sized> Deref for PinBox<T> { ... }
@@ -239,24 +222,23 @@ If the data implements `Unpin`, its also safe to convert a `PinBox` into a
239222
impl<T: Unpin + ?Sized> From<PinBox<T>> for Box<T> { ... }
240223
```
241224

242-
Finally, it is safe to get a `Pin` and a `PinMut` from borrows of `PinBox`:
225+
Finally, it is safe to get a `Pin` from borrows of `PinBox`:
243226

244227
```rust
245228
impl<T: ?Sized> PinBox<T> {
246-
fn as_pin<'a>(&'a self) -> Pin<'a, T> { ... }
247-
fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> { ... }
229+
fn as_pin<'a>(&'a mut self) -> Pin<'a, T> { ... }
248230
}
249231
```
250232

251233
These APIs make `PinBox` a reasonable way of handling data which does not
252234
implement `!Unpin`. Once you heap allocate that data inside of a `PinBox`, you
253-
know that it will never change address again, and you can hand out `Pin` and
254-
`PinMut` references to that data.
235+
know that it will never change address again, and you can hand out `Pin`
236+
references to that data.
255237

256238
### Unsafe API
257239

258240
`PinBox` can be unsafely converted into `&mut T` and `Box<T>` even if the type
259-
it references does not implement `Unpin`, similar to `PinMut`:
241+
it references does not implement `Unpin`, similar to `Pin`:
260242

261243
```rust
262244
impl<T: ?Sized> PinBox<T> {
@@ -276,7 +258,7 @@ references are invalidated if the type is moved, these kinds of generators
276258
Once the arbitrary_self_types feature becomes object safe, we will make three
277259
changes to the generator API:
278260

279-
1. We will change the `resume` method to take self by `self: PinMut<Self>`
261+
1. We will change the `resume` method to take self by `self: Pin<Self>`
280262
instead of `&mut self`.
281263
2. We will implement `!Unpin` for the anonymous type of an immovable generator.
282264
3. We will make it safe to define an immovable generator.
@@ -377,12 +359,8 @@ struct PinTemporary<'a, T: 'a> {
377359
}
378360

379361
impl<'a, T> PinTemporary<'a, T> {
380-
pub fn into_pin(&'a self) -> Pin<'a, T> {
381-
unsafe { Pin::new_unchecked(&self.data) }
382-
}
383-
384-
pub fn into_pin_mut(&'a mut self) -> PinMut<'a, T> {
385-
unsafe { PinMut::new_unchecked(&mut self.data) }
362+
pub fn into_pin(&'a mut self) -> Pin<'a, T> {
363+
unsafe { Pin::new_unchecked(&mut self.data) }
386364
}
387365
}
388366
```
@@ -398,6 +376,19 @@ big language change.
398376
For now, we're happy to stick with the `Pin` struct in std, and if this type is
399377
ever added, turn the `Pin` type into an alias for the reference type.
400378

379+
## Having both `Pin` and `PinMut`
380+
381+
Instead of just having `Pin`, the type called `Pin` could instead be `PinMut`,
382+
and we could have a type called `Pin`, which is like `PinMut`, but only
383+
contains a shared, immutable reference.
384+
385+
Because we've determined that it should be safe to immutably dereference
386+
`Pin`/`PinMut`, this `Pin` type would not provide significant guarantees that a
387+
normal immutable reference does not. If a user needs to pass around references
388+
to data stored pinned, an `&Pin` (under the definition of `Pin` provided in
389+
this RFC) would suffice. For this reason, the `Pin`/`PinMut` distinction
390+
introduced extra types and complexity without any impactful benefit.
391+
401392
# Unresolved questions
402393
[unresolved]: #unresolved-questions
403394

0 commit comments

Comments
 (0)