-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
impl Unpin for Pin #49621
impl Unpin for Pin #49621
Conversation
No, I could add that as well if you want. |
I thought we'd maybe wait a bit and at least make sure we have consensus on the guarantees provided by Once we are fine with that, we probably want instances for |
I definitely agree with that in general. For the specific case of Maybe one way to state it is: having an instance of Also, deciding whether this implementation is sound or not (before deciding for other types) is going to greatly affect those of us experimenting with As I briefly mentioned in the tracking issue this is important for ergonomics. Similar to most object safe traits (presuming that trait Foo {
fn foo(self: Pin<Self>);
} then you want to provide an implementation for references to the trait, currently that requires unsafe code to perform the re-borrow (which, if `Pin: !Unpin is presumably unsound), but as I said above I believe that re-borrow to be guaranteed sound so it should be possible to do it with just safe code: impl<'a, T: Foo + ?Sized + 'a> Foo for Pin<'a, T> {
fn foo(mut self: Pin<Self>) {
<T as Foo>::foo(Pin::borrow(unsafe { Pin::get_mut(&mut self) }))
// <T as Foo>::foo(Pin::borrow(&mut *self))
}
} which would then allow functions to take trait objects: fn bar(mut foo: Pin<Foo>) {
Pin::borrow(&mut foo).foo()
} and waaaay in the future if re-borrowing is formalised and made something that custom types can implement (or sooner if re-borrowing of impl<'a, T: Foo + ?Sized + 'a> Foo for Pin<'a, T> {
fn foo(self: Pin<Self>) {
<T as Foo>::foo(*self)
}
}
fn bar(foo: Pin<Foo>) {
foo.foo()
} I realise that arguing from how |
I do not see any fundamental reason why we should not be able to declare that However, I have to agree insofar as I cannot think if any way in which making Concerning your use-case for |
You're right, that use-case does not actually need the forwarding implementation (far too many re-revisions of my examples made that disappear 🙁). There are definitely use-cases that require it though. Reading the API guideline on taking fn bar<F: Foo>(foo: F) {
stack_pinned(foo, |mut foo: Pin<F>| { // When invoked from `baz2` this is `Pin<Pin<baz::F>>`
Pin::borrow(&mut foo).foo();
});
}
fn baz1<F: Foo>(foo: F) {
bar(foo);
bar(foo); // Error: use of moved value
}
fn baz2<F: Foo>(foo: F) {
stack_pinned(foo, |mut foo: Pin<F>| {
bar(Pin::borrow(&mut foo));
bar(Pin::borrow(&mut foo)); // just `bar(foo);` with re-borrowing support
}
}
Writing this out made me realise another important reason for fn bar<F: Foo + Unpin>(mut foo: F) {
Pin::new(&mut foo).foo(); // just `foo.foo()` with `&pin` coercion I think...
}
fn baz<F: Foo>(foo: F) {
stack_pinned(foo, |mut foo: Pin<F>| {
bar(Pin::borrow(&mut foo));
}
} EDIT: Fixed some |
Interesting, I was not aware of this particular API trick. There seems to be a confusion between
This is neat. I somehow feel like you're cheating here because you seem to get a free generalization from a function that requires I guess the reason this works is that If I phrase this in terms of the formalism I started to develop, the question is: What is the pinned typestate invariant for
I somehow though that would make |
I believe (based on my sloppy informal reasoning) that all the smart pointers in libstd can implement |
For now I agree for |
Sorry, I originally had the two examples from that post in one, missed renaming the function in the first from |
@Nemo157 can you add PinBox to this PR? then I'll r+ :D |
bbc20bc
to
a29d4d9
Compare
@bors r+ |
📌 Commit a29d4d9 has been approved by |
r? @withoutboats