audit pass Pin
This commit is contained in:
@@ -183,14 +183,7 @@ is just too many nuances and edge-cases to consider which is easily overlooked w
|
|||||||
naively giving these markers different names, and I'm convinced that we'll
|
naively giving these markers different names, and I'm convinced that we'll
|
||||||
just have to get used to them and use them as is.</p>
|
just have to get used to them and use them as is.</p>
|
||||||
<p>If you want to you can read a bit of the discussion from the
|
<p>If you want to you can read a bit of the discussion from the
|
||||||
<a href="https://internals.rust-lang.org/t/naming-pin-anchor-move/6864/12">internals thread</a>. One of the best takeaways from there in my
|
<a href="https://internals.rust-lang.org/t/naming-pin-anchor-move/6864/12">internals thread</a>.</p>
|
||||||
eyes is this quote from <code>tmandry</code>:</p>
|
|
||||||
<blockquote>
|
|
||||||
<p><em>Think of taking a thumbtack out of a cork board so you can tweak how a flyer
|
|
||||||
looks. For Unpin types, this unpinning is directly supported by the type; you
|
|
||||||
can do this implicitly. You can even swap out the object with another before you
|
|
||||||
put the pin back. For other types, you must be much more careful.</em></p>
|
|
||||||
</blockquote>
|
|
||||||
<h2><a class="header" href="#pinning-and-self-referential-structs" id="pinning-and-self-referential-structs">Pinning and self-referential structs</a></h2>
|
<h2><a class="header" href="#pinning-and-self-referential-structs" id="pinning-and-self-referential-structs">Pinning and self-referential structs</a></h2>
|
||||||
<p>Let's start where we left off in the last chapter by making the problem we
|
<p>Let's start where we left off in the last chapter by making the problem we
|
||||||
saw using a self-referential struct in our generator a lot simpler by making
|
saw using a self-referential struct in our generator a lot simpler by making
|
||||||
@@ -546,12 +539,53 @@ stack frame and return it since any pointers we take to "self" is inva
|
|||||||
stack. A mistake that is easy to make is, forgetting to shadow the original variable
|
stack. A mistake that is easy to make is, forgetting to shadow the original variable
|
||||||
since you could drop the pinned pointer and access the old value
|
since you could drop the pinned pointer and access the old value
|
||||||
after it's initialized like this:</p>
|
after it's initialized like this:</p>
|
||||||
<pre><code class="language-rust ignore"> let mut test1 = Test::new("test1");
|
<pre><pre class="playpen"><code class="language-rust">fn main() {
|
||||||
|
let mut test1 = Test::new("test1");
|
||||||
let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
|
let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
|
||||||
Test::init(test1_pin.as_mut());
|
Test::init(test1_pin.as_mut());
|
||||||
drop(test1_pin);
|
drop(test1_pin);
|
||||||
println!("{:?}", test1.b);
|
|
||||||
</code></pre>
|
let mut test2 = Test::new("test2");
|
||||||
|
mem::swap(&mut test1, &mut test2);
|
||||||
|
println!("Not self referential anymore: {:?}", test1.b);
|
||||||
|
}
|
||||||
|
# use std::pin::Pin;
|
||||||
|
# use std::marker::PhantomPinned;
|
||||||
|
# use std::mem;
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# struct Test {
|
||||||
|
# a: String,
|
||||||
|
# b: *const String,
|
||||||
|
# _marker: PhantomPinned,
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# impl Test {
|
||||||
|
# fn new(txt: &str) -> Self {
|
||||||
|
# let a = String::from(txt);
|
||||||
|
# Test {
|
||||||
|
# a,
|
||||||
|
# b: std::ptr::null(),
|
||||||
|
# // This makes our type `!Unpin`
|
||||||
|
# _marker: PhantomPinned,
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# fn init<'a>(self: Pin<&'a mut Self>) {
|
||||||
|
# let self_ptr: *const String = &self.a;
|
||||||
|
# let this = unsafe { self.get_unchecked_mut() };
|
||||||
|
# this.b = self_ptr;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn a<'a>(self: Pin<&'a Self>) -> &'a str {
|
||||||
|
# &self.get_ref().a
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||||
|
# unsafe { &*(self.b) }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
</code></pre></pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
<h2><a class="header" href="#pinning-to-the-heap" id="pinning-to-the-heap">Pinning to the heap</a></h2>
|
<h2><a class="header" href="#pinning-to-the-heap" id="pinning-to-the-heap">Pinning to the heap</a></h2>
|
||||||
<p>For completeness let's remove some unsafe and the need for an <code>init</code> method
|
<p>For completeness let's remove some unsafe and the need for an <code>init</code> method
|
||||||
@@ -599,7 +633,7 @@ pub fn main() {
|
|||||||
println!("a: {}, b: {}",test2.as_ref().a(), test2.as_ref().b());
|
println!("a: {}, b: {}",test2.as_ref().a(), test2.as_ref().b());
|
||||||
}
|
}
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
<p>The fact that pinning a heap allocated value that implements <code>!Unpin</code> is safe
|
<p>The fact that it's safe to pin a heap allocated value even if it is <code>!Unpin</code>
|
||||||
makes sense. Once the data is allocated on the heap it will have a stable address.</p>
|
makes sense. Once the data is allocated on the heap it will have a stable address.</p>
|
||||||
<p>There is no need for us as users of the API to take special care and ensure
|
<p>There is no need for us as users of the API to take special care and ensure
|
||||||
that the self-referential pointer stays valid.</p>
|
that the self-referential pointer stays valid.</p>
|
||||||
|
|||||||
@@ -1651,14 +1651,7 @@ is just too many nuances and edge-cases to consider which is easily overlooked w
|
|||||||
naively giving these markers different names, and I'm convinced that we'll
|
naively giving these markers different names, and I'm convinced that we'll
|
||||||
just have to get used to them and use them as is.</p>
|
just have to get used to them and use them as is.</p>
|
||||||
<p>If you want to you can read a bit of the discussion from the
|
<p>If you want to you can read a bit of the discussion from the
|
||||||
<a href="https://internals.rust-lang.org/t/naming-pin-anchor-move/6864/12">internals thread</a>. One of the best takeaways from there in my
|
<a href="https://internals.rust-lang.org/t/naming-pin-anchor-move/6864/12">internals thread</a>.</p>
|
||||||
eyes is this quote from <code>tmandry</code>:</p>
|
|
||||||
<blockquote>
|
|
||||||
<p><em>Think of taking a thumbtack out of a cork board so you can tweak how a flyer
|
|
||||||
looks. For Unpin types, this unpinning is directly supported by the type; you
|
|
||||||
can do this implicitly. You can even swap out the object with another before you
|
|
||||||
put the pin back. For other types, you must be much more careful.</em></p>
|
|
||||||
</blockquote>
|
|
||||||
<h2><a class="header" href="#pinning-and-self-referential-structs" id="pinning-and-self-referential-structs">Pinning and self-referential structs</a></h2>
|
<h2><a class="header" href="#pinning-and-self-referential-structs" id="pinning-and-self-referential-structs">Pinning and self-referential structs</a></h2>
|
||||||
<p>Let's start where we left off in the last chapter by making the problem we
|
<p>Let's start where we left off in the last chapter by making the problem we
|
||||||
saw using a self-referential struct in our generator a lot simpler by making
|
saw using a self-referential struct in our generator a lot simpler by making
|
||||||
@@ -2014,12 +2007,53 @@ stack frame and return it since any pointers we take to "self" is inva
|
|||||||
stack. A mistake that is easy to make is, forgetting to shadow the original variable
|
stack. A mistake that is easy to make is, forgetting to shadow the original variable
|
||||||
since you could drop the pinned pointer and access the old value
|
since you could drop the pinned pointer and access the old value
|
||||||
after it's initialized like this:</p>
|
after it's initialized like this:</p>
|
||||||
<pre><code class="language-rust ignore"> let mut test1 = Test::new("test1");
|
<pre><pre class="playpen"><code class="language-rust">fn main() {
|
||||||
|
let mut test1 = Test::new("test1");
|
||||||
let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
|
let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
|
||||||
Test::init(test1_pin.as_mut());
|
Test::init(test1_pin.as_mut());
|
||||||
drop(test1_pin);
|
drop(test1_pin);
|
||||||
println!("{:?}", test1.b);
|
|
||||||
</code></pre>
|
let mut test2 = Test::new("test2");
|
||||||
|
mem::swap(&mut test1, &mut test2);
|
||||||
|
println!("Not self referential anymore: {:?}", test1.b);
|
||||||
|
}
|
||||||
|
# use std::pin::Pin;
|
||||||
|
# use std::marker::PhantomPinned;
|
||||||
|
# use std::mem;
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# struct Test {
|
||||||
|
# a: String,
|
||||||
|
# b: *const String,
|
||||||
|
# _marker: PhantomPinned,
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# impl Test {
|
||||||
|
# fn new(txt: &str) -> Self {
|
||||||
|
# let a = String::from(txt);
|
||||||
|
# Test {
|
||||||
|
# a,
|
||||||
|
# b: std::ptr::null(),
|
||||||
|
# // This makes our type `!Unpin`
|
||||||
|
# _marker: PhantomPinned,
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# fn init<'a>(self: Pin<&'a mut Self>) {
|
||||||
|
# let self_ptr: *const String = &self.a;
|
||||||
|
# let this = unsafe { self.get_unchecked_mut() };
|
||||||
|
# this.b = self_ptr;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn a<'a>(self: Pin<&'a Self>) -> &'a str {
|
||||||
|
# &self.get_ref().a
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||||
|
# unsafe { &*(self.b) }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
</code></pre></pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
<h2><a class="header" href="#pinning-to-the-heap" id="pinning-to-the-heap">Pinning to the heap</a></h2>
|
<h2><a class="header" href="#pinning-to-the-heap" id="pinning-to-the-heap">Pinning to the heap</a></h2>
|
||||||
<p>For completeness let's remove some unsafe and the need for an <code>init</code> method
|
<p>For completeness let's remove some unsafe and the need for an <code>init</code> method
|
||||||
@@ -2067,7 +2101,7 @@ pub fn main() {
|
|||||||
println!("a: {}, b: {}",test2.as_ref().a(), test2.as_ref().b());
|
println!("a: {}, b: {}",test2.as_ref().a(), test2.as_ref().b());
|
||||||
}
|
}
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
<p>The fact that pinning a heap allocated value that implements <code>!Unpin</code> is safe
|
<p>The fact that it's safe to pin a heap allocated value even if it is <code>!Unpin</code>
|
||||||
makes sense. Once the data is allocated on the heap it will have a stable address.</p>
|
makes sense. Once the data is allocated on the heap it will have a stable address.</p>
|
||||||
<p>There is no need for us as users of the API to take special care and ensure
|
<p>There is no need for us as users of the API to take special care and ensure
|
||||||
that the self-referential pointer stays valid.</p>
|
that the self-referential pointer stays valid.</p>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
55
src/4_pin.md
55
src/4_pin.md
@@ -38,13 +38,7 @@ naively giving these markers different names, and I'm convinced that we'll
|
|||||||
just have to get used to them and use them as is.
|
just have to get used to them and use them as is.
|
||||||
|
|
||||||
If you want to you can read a bit of the discussion from the
|
If you want to you can read a bit of the discussion from the
|
||||||
[internals thread][internals_unpin]. One of the best takeaways from there in my
|
[internals thread][internals_unpin].
|
||||||
eyes is this quote from `tmandry`:
|
|
||||||
|
|
||||||
>_Think of taking a thumbtack out of a cork board so you can tweak how a flyer
|
|
||||||
looks. For Unpin types, this unpinning is directly supported by the type; you
|
|
||||||
can do this implicitly. You can even swap out the object with another before you
|
|
||||||
put the pin back. For other types, you must be much more careful._
|
|
||||||
|
|
||||||
## Pinning and self-referential structs
|
## Pinning and self-referential structs
|
||||||
|
|
||||||
@@ -446,12 +440,53 @@ us from swapping the pinned pointers.
|
|||||||
> since you could drop the pinned pointer and access the old value
|
> since you could drop the pinned pointer and access the old value
|
||||||
> after it's initialized like this:
|
> after it's initialized like this:
|
||||||
>
|
>
|
||||||
> ```rust, ignore
|
> ```rust
|
||||||
|
> fn main() {
|
||||||
> let mut test1 = Test::new("test1");
|
> let mut test1 = Test::new("test1");
|
||||||
> let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
|
> let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
|
||||||
> Test::init(test1_pin.as_mut());
|
> Test::init(test1_pin.as_mut());
|
||||||
> drop(test1_pin);
|
> drop(test1_pin);
|
||||||
> println!("{:?}", test1.b);
|
>
|
||||||
|
> let mut test2 = Test::new("test2");
|
||||||
|
> mem::swap(&mut test1, &mut test2);
|
||||||
|
> println!("Not self referential anymore: {:?}", test1.b);
|
||||||
|
> }
|
||||||
|
> # use std::pin::Pin;
|
||||||
|
> # use std::marker::PhantomPinned;
|
||||||
|
> # use std::mem;
|
||||||
|
> #
|
||||||
|
> # #[derive(Debug)]
|
||||||
|
> # struct Test {
|
||||||
|
> # a: String,
|
||||||
|
> # b: *const String,
|
||||||
|
> # _marker: PhantomPinned,
|
||||||
|
> # }
|
||||||
|
> #
|
||||||
|
> #
|
||||||
|
> # impl Test {
|
||||||
|
> # fn new(txt: &str) -> Self {
|
||||||
|
> # let a = String::from(txt);
|
||||||
|
> # Test {
|
||||||
|
> # a,
|
||||||
|
> # b: std::ptr::null(),
|
||||||
|
> # // This makes our type `!Unpin`
|
||||||
|
> # _marker: PhantomPinned,
|
||||||
|
> # }
|
||||||
|
> # }
|
||||||
|
> # fn init<'a>(self: Pin<&'a mut Self>) {
|
||||||
|
> # let self_ptr: *const String = &self.a;
|
||||||
|
> # let this = unsafe { self.get_unchecked_mut() };
|
||||||
|
> # this.b = self_ptr;
|
||||||
|
> # }
|
||||||
|
> #
|
||||||
|
> # fn a<'a>(self: Pin<&'a Self>) -> &'a str {
|
||||||
|
> # &self.get_ref().a
|
||||||
|
> # }
|
||||||
|
> #
|
||||||
|
> # fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||||
|
> # unsafe { &*(self.b) }
|
||||||
|
> # }
|
||||||
|
> # }
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
## Pinning to the heap
|
## Pinning to the heap
|
||||||
@@ -504,7 +539,7 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The fact that pinning a heap allocated value that implements `!Unpin` is safe
|
The fact that it's safe to pin a heap allocated value even if it is `!Unpin`
|
||||||
makes sense. Once the data is allocated on the heap it will have a stable address.
|
makes sense. Once the data is allocated on the heap it will have a stable address.
|
||||||
|
|
||||||
There is no need for us as users of the API to take special care and ensure
|
There is no need for us as users of the API to take special care and ensure
|
||||||
|
|||||||
Reference in New Issue
Block a user