fix outdated links re: #13
This commit is contained in:
459
book/4_pin.html
459
book/4_pin.html
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="sidebar-visible no-js light">
|
||||
<html lang="en" class="sidebar-visible no-js">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
@@ -32,11 +32,11 @@
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<body class="light">
|
||||
<!-- Provide site root to javascript -->
|
||||
<script type="text/javascript">
|
||||
var path_to_root = "";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
var default_theme = "light";
|
||||
</script>
|
||||
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
@@ -60,11 +60,8 @@
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
var html = document.querySelector('html');
|
||||
html.classList.remove('no-js')
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add('js');
|
||||
document.body.className = theme;
|
||||
document.querySelector('html').className = theme + ' js';
|
||||
</script>
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
@@ -80,8 +77,8 @@
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div id="sidebar-scrollbox" class="sidebar-scrollbox">
|
||||
<ol class="chapter"><li class="expanded affix "><a href="introduction.html">Introduction</a></li><li class="expanded "><a href="0_background_information.html"><strong aria-hidden="true">1.</strong> Background information</a></li><li class="expanded "><a href="1_futures_in_rust.html"><strong aria-hidden="true">2.</strong> Futures in Rust</a></li><li class="expanded "><a href="2_waker_context.html"><strong aria-hidden="true">3.</strong> Waker and Context</a></li><li class="expanded "><a href="3_generators_async_await.html"><strong aria-hidden="true">4.</strong> Generators and async/await</a></li><li class="expanded "><a href="4_pin.html" class="active"><strong aria-hidden="true">5.</strong> Pin</a></li><li class="expanded "><a href="6_future_example.html"><strong aria-hidden="true">6.</strong> Implementing Futures</a></li><li class="expanded "><a href="8_finished_example.html"><strong aria-hidden="true">7.</strong> Finished example (editable)</a></li><li class="expanded affix "><a href="conclusion.html">Conclusion and exercises</a></li></ol>
|
||||
<div class="sidebar-scrollbox">
|
||||
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="0_background_information.html"><strong aria-hidden="true">1.</strong> Background information</a></li><li><a href="1_futures_in_rust.html"><strong aria-hidden="true">2.</strong> Futures in Rust</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">3.</strong> Waker and Context</a></li><li><a href="3_generators_async_await.html"><strong aria-hidden="true">4.</strong> Generators and async/await</a></li><li><a href="4_pin.html" class="active"><strong aria-hidden="true">5.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">6.</strong> Implementing Futures</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">7.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
|
||||
</div>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||
</nav>
|
||||
@@ -167,7 +164,9 @@
|
||||
your head around in the start, but once you unlock a mental model for it
|
||||
it gets significantly easier to reason about.</p>
|
||||
<h2><a class="header" href="#definitions" id="definitions">Definitions</a></h2>
|
||||
<p>Pin is only relevant for pointers. A reference to an object is a pointer.</p>
|
||||
<p>Pin wraps a pointer. A reference to an object is a pointer. Pin gives some
|
||||
guarantees about the <em>pointee</em> (the data it points to) which we'll explore further
|
||||
in this chapter.</p>
|
||||
<p>Pin consists of the <code>Pin</code> type and the <code>Unpin</code> marker. Pin's purpose in life is
|
||||
to govern the rules that need to apply for types which implement <code>!Unpin</code>.</p>
|
||||
<p>Yep, you're right, that's double negation right there. <code>!Unpin</code> means
|
||||
@@ -189,7 +188,7 @@ just have to get used to them and use them as is.</p>
|
||||
<a href="https://internals.rust-lang.org/t/naming-pin-anchor-move/6864/12">internals thread</a>.</p>
|
||||
<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
|
||||
saw using a self-referential struct in our generator a lot simpler by making
|
||||
saw using a self-references in our generator a lot simpler by making
|
||||
some self-referential structs that are easier to reason about than our
|
||||
state machines:</p>
|
||||
<p>For now our example will look like this:</p>
|
||||
@@ -242,45 +241,44 @@ you see, this works as expected:</p>
|
||||
println!("a: {}, b: {}", test2.a(), test2.b());
|
||||
|
||||
}
|
||||
<span class="boring">use std::pin::Pin;
|
||||
</span><span class="boring">#[derive(Debug)]
|
||||
</span><span class="boring">struct Test {
|
||||
</span><span class="boring"> a: String,
|
||||
</span><span class="boring"> b: *const String,
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl Test {
|
||||
</span><span class="boring"> fn new(txt: &str) -> Self {
|
||||
</span><span class="boring"> let a = String::from(txt);
|
||||
</span><span class="boring"> Test {
|
||||
</span><span class="boring"> a,
|
||||
</span><span class="boring"> b: std::ptr::null(),
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> // We need an `init` method to actually set our self-reference
|
||||
</span><span class="boring"> fn init(&mut self) {
|
||||
</span><span class="boring"> let self_ref: *const String = &self.a;
|
||||
</span><span class="boring"> self.b = self_ref;
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn a(&self) -> &str {
|
||||
</span><span class="boring"> &self.a
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn b(&self) -> &String {
|
||||
</span><span class="boring"> unsafe {&*(self.b)}
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}
|
||||
</span></code></pre></pre>
|
||||
# use std::pin::Pin;
|
||||
# #[derive(Debug)]
|
||||
# struct Test {
|
||||
# a: String,
|
||||
# b: *const String,
|
||||
# }
|
||||
#
|
||||
# impl Test {
|
||||
# fn new(txt: &str) -> Self {
|
||||
# let a = String::from(txt);
|
||||
# Test {
|
||||
# a,
|
||||
# b: std::ptr::null(),
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# // We need an `init` method to actually set our self-reference
|
||||
# fn init(&mut self) {
|
||||
# let self_ref: *const String = &self.a;
|
||||
# self.b = self_ref;
|
||||
# }
|
||||
#
|
||||
# fn a(&self) -> &str {
|
||||
# &self.a
|
||||
# }
|
||||
#
|
||||
# fn b(&self) -> &String {
|
||||
# unsafe {&*(self.b)}
|
||||
# }
|
||||
# }
|
||||
</code></pre></pre>
|
||||
<p>In our main method we first instantiate two instances of <code>Test</code> and print out
|
||||
the value of the fields on <code>test1</code>. We get what we'd expect:</p>
|
||||
<pre><code class="language-rust ignore">a: test1, b: test1
|
||||
a: test2, b: test2
|
||||
</code></pre>
|
||||
<p>Let's see what happens if we swap the data stored at the memory location
|
||||
which <code>test1</code> is pointing to with the data stored at the memory location
|
||||
<code>test2</code> is pointing to and vice a versa.</p>
|
||||
<p>Let's see what happens if we swap the data stored at the memory location <code>test1</code> with the
|
||||
data stored at the memory location <code>test2</code> and vice a versa.</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">fn main() {
|
||||
let mut test1 = Test::new("test1");
|
||||
test1.init();
|
||||
@@ -292,36 +290,36 @@ which <code>test1</code> is pointing to with the data stored at the memory locat
|
||||
println!("a: {}, b: {}", test2.a(), test2.b());
|
||||
|
||||
}
|
||||
<span class="boring">use std::pin::Pin;
|
||||
</span><span class="boring">#[derive(Debug)]
|
||||
</span><span class="boring">struct Test {
|
||||
</span><span class="boring"> a: String,
|
||||
</span><span class="boring"> b: *const String,
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl Test {
|
||||
</span><span class="boring"> fn new(txt: &str) -> Self {
|
||||
</span><span class="boring"> let a = String::from(txt);
|
||||
</span><span class="boring"> Test {
|
||||
</span><span class="boring"> a,
|
||||
</span><span class="boring"> b: std::ptr::null(),
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn init(&mut self) {
|
||||
</span><span class="boring"> let self_ref: *const String = &self.a;
|
||||
</span><span class="boring"> self.b = self_ref;
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn a(&self) -> &str {
|
||||
</span><span class="boring"> &self.a
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn b(&self) -> &String {
|
||||
</span><span class="boring"> unsafe {&*(self.b)}
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}
|
||||
</span></code></pre></pre>
|
||||
# use std::pin::Pin;
|
||||
# #[derive(Debug)]
|
||||
# struct Test {
|
||||
# a: String,
|
||||
# b: *const String,
|
||||
# }
|
||||
#
|
||||
# impl Test {
|
||||
# fn new(txt: &str) -> Self {
|
||||
# let a = String::from(txt);
|
||||
# Test {
|
||||
# a,
|
||||
# b: std::ptr::null(),
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# fn init(&mut self) {
|
||||
# let self_ref: *const String = &self.a;
|
||||
# self.b = self_ref;
|
||||
# }
|
||||
#
|
||||
# fn a(&self) -> &str {
|
||||
# &self.a
|
||||
# }
|
||||
#
|
||||
# fn b(&self) -> &String {
|
||||
# unsafe {&*(self.b)}
|
||||
# }
|
||||
# }
|
||||
</code></pre></pre>
|
||||
<p>Naively, we could think that what we should get a debug print of <code>test1</code> two
|
||||
times like this</p>
|
||||
<pre><code class="language-rust ignore">a: test1, b: test1
|
||||
@@ -348,36 +346,36 @@ be tied to the lifetime of <code>test2</code> anymore.</p>
|
||||
println!("a: {}, b: {}", test2.a(), test2.b());
|
||||
|
||||
}
|
||||
<span class="boring">use std::pin::Pin;
|
||||
</span><span class="boring">#[derive(Debug)]
|
||||
</span><span class="boring">struct Test {
|
||||
</span><span class="boring"> a: String,
|
||||
</span><span class="boring"> b: *const String,
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl Test {
|
||||
</span><span class="boring"> fn new(txt: &str) -> Self {
|
||||
</span><span class="boring"> let a = String::from(txt);
|
||||
</span><span class="boring"> Test {
|
||||
</span><span class="boring"> a,
|
||||
</span><span class="boring"> b: std::ptr::null(),
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn init(&mut self) {
|
||||
</span><span class="boring"> let self_ref: *const String = &self.a;
|
||||
</span><span class="boring"> self.b = self_ref;
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn a(&self) -> &str {
|
||||
</span><span class="boring"> &self.a
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn b(&self) -> &String {
|
||||
</span><span class="boring"> unsafe {&*(self.b)}
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}
|
||||
</span></code></pre></pre>
|
||||
# use std::pin::Pin;
|
||||
# #[derive(Debug)]
|
||||
# struct Test {
|
||||
# a: String,
|
||||
# b: *const String,
|
||||
# }
|
||||
#
|
||||
# impl Test {
|
||||
# fn new(txt: &str) -> Self {
|
||||
# let a = String::from(txt);
|
||||
# Test {
|
||||
# a,
|
||||
# b: std::ptr::null(),
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# fn init(&mut self) {
|
||||
# let self_ref: *const String = &self.a;
|
||||
# self.b = self_ref;
|
||||
# }
|
||||
#
|
||||
# fn a(&self) -> &str {
|
||||
# &self.a
|
||||
# }
|
||||
#
|
||||
# fn b(&self) -> &String {
|
||||
# unsafe {&*(self.b)}
|
||||
# }
|
||||
# }
|
||||
</code></pre></pre>
|
||||
<p>That shouldn't happen. There is no serious error yet, but as you can imagine
|
||||
it's easy to create serious bugs using this code.</p>
|
||||
<p>I created a diagram to help visualize what's going on:</p>
|
||||
@@ -423,7 +421,7 @@ impl Test {
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>Now, what we've done here is pinning a stack address. That will always be
|
||||
<p>Now, what we've done here is pinning an object to the stack. That will always be
|
||||
<code>unsafe</code> if our type implements <code>!Unpin</code>.</p>
|
||||
<p>We use the same tricks here, including requiring an <code>init</code>. If we want to fix that
|
||||
and let users avoid <code>unsafe</code> we need to pin our data on the heap instead which
|
||||
@@ -443,42 +441,42 @@ we'll show in a second.</p>
|
||||
println!("a: {}, b: {}", Test::a(test1.as_ref()), Test::b(test1.as_ref()));
|
||||
println!("a: {}, b: {}", Test::a(test2.as_ref()), Test::b(test2.as_ref()));
|
||||
}
|
||||
<span class="boring">use std::pin::Pin;
|
||||
</span><span class="boring">use std::marker::PhantomPinned;
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">#[derive(Debug)]
|
||||
</span><span class="boring">struct Test {
|
||||
</span><span class="boring"> a: String,
|
||||
</span><span class="boring"> b: *const String,
|
||||
</span><span class="boring"> _marker: PhantomPinned,
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl Test {
|
||||
</span><span class="boring"> fn new(txt: &str) -> Self {
|
||||
</span><span class="boring"> let a = String::from(txt);
|
||||
</span><span class="boring"> Test {
|
||||
</span><span class="boring"> a,
|
||||
</span><span class="boring"> b: std::ptr::null(),
|
||||
</span><span class="boring"> // This makes our type `!Unpin`
|
||||
</span><span class="boring"> _marker: PhantomPinned,
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> fn init<'a>(self: Pin<&'a mut Self>) {
|
||||
</span><span class="boring"> let self_ptr: *const String = &self.a;
|
||||
</span><span class="boring"> let this = unsafe { self.get_unchecked_mut() };
|
||||
</span><span class="boring"> this.b = self_ptr;
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn a<'a>(self: Pin<&'a Self>) -> &'a str {
|
||||
</span><span class="boring"> &self.get_ref().a
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||
</span><span class="boring"> unsafe { &*(self.b) }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}
|
||||
</span></code></pre></pre>
|
||||
# use std::pin::Pin;
|
||||
# use std::marker::PhantomPinned;
|
||||
#
|
||||
# #[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>
|
||||
<p>Now, if we try to pull the same trick which got us in to trouble the last time
|
||||
you'll get a compilation error.</p>
|
||||
<pre><pre class="playpen"><code class="language-rust compile_fail">pub fn main() {
|
||||
@@ -494,50 +492,50 @@ you'll get a compilation error.</p>
|
||||
std::mem::swap(test1.get_mut(), test2.get_mut());
|
||||
println!("a: {}, b: {}", Test::a(test2.as_ref()), Test::b(test2.as_ref()));
|
||||
}
|
||||
<span class="boring">use std::pin::Pin;
|
||||
</span><span class="boring">use std::marker::PhantomPinned;
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">#[derive(Debug)]
|
||||
</span><span class="boring">struct Test {
|
||||
</span><span class="boring"> a: String,
|
||||
</span><span class="boring"> b: *const String,
|
||||
</span><span class="boring"> _marker: PhantomPinned,
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl Test {
|
||||
</span><span class="boring"> fn new(txt: &str) -> Self {
|
||||
</span><span class="boring"> Test {
|
||||
</span><span class="boring"> a: let a = String::from(txt),
|
||||
</span><span class="boring"> b: std::ptr::null(),
|
||||
</span><span class="boring"> _marker: PhantomPinned, // This makes our type `!Unpin`
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> fn init<'a>(self: Pin<&'a mut Self>) {
|
||||
</span><span class="boring"> let self_ptr: *const String = &self.a;
|
||||
</span><span class="boring"> let this = unsafe { self.get_unchecked_mut() };
|
||||
</span><span class="boring"> this.b = self_ptr;
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn a<'a>(self: Pin<&'a Self>) -> &'a str {
|
||||
</span><span class="boring"> &self.get_ref().a
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||
</span><span class="boring"> unsafe { &*(self.b) }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}
|
||||
</span></code></pre></pre>
|
||||
# use std::pin::Pin;
|
||||
# use std::marker::PhantomPinned;
|
||||
#
|
||||
# #[derive(Debug)]
|
||||
# struct Test {
|
||||
# a: String,
|
||||
# b: *const String,
|
||||
# _marker: PhantomPinned,
|
||||
# }
|
||||
#
|
||||
#
|
||||
# impl Test {
|
||||
# fn new(txt: &str) -> Self {
|
||||
# Test {
|
||||
# a: let a = String::from(txt),
|
||||
# b: std::ptr::null(),
|
||||
# _marker: PhantomPinned, // This makes our type `!Unpin`
|
||||
# }
|
||||
# }
|
||||
# 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>
|
||||
<p>As you see from the error you get by running the code the type system prevents
|
||||
us from swapping the pinned pointers.</p>
|
||||
<blockquote>
|
||||
<p>It's important to note that stack pinning will always depend on the current
|
||||
stack frame we're in, so we can't create a self referential object in one
|
||||
stack frame and return it since any pointers we take to "self" is invalidated.</p>
|
||||
<p>It also puts a lot of responsibility in your hands if you pin a value to the
|
||||
<p>It also puts a lot of responsibility in your hands if you pin an object to the
|
||||
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
|
||||
after it's initialized like this:</p>
|
||||
since you could drop the <code>Pin</code> and access the old value after it's initialized
|
||||
like this:</p>
|
||||
<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) };
|
||||
@@ -548,41 +546,41 @@ after it's initialized like this:</p>
|
||||
mem::swap(&mut test1, &mut test2);
|
||||
println!("Not self referential anymore: {:?}", test1.b);
|
||||
}
|
||||
<span class="boring">use std::pin::Pin;
|
||||
</span><span class="boring">use std::marker::PhantomPinned;
|
||||
</span><span class="boring">use std::mem;
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">#[derive(Debug)]
|
||||
</span><span class="boring">struct Test {
|
||||
</span><span class="boring"> a: String,
|
||||
</span><span class="boring"> b: *const String,
|
||||
</span><span class="boring"> _marker: PhantomPinned,
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl Test {
|
||||
</span><span class="boring"> fn new(txt: &str) -> Self {
|
||||
</span><span class="boring"> Test {
|
||||
</span><span class="boring"> a: String::from(txt),
|
||||
</span><span class="boring"> b: std::ptr::null(),
|
||||
</span><span class="boring"> _marker: PhantomPinned, // This makes our type `!Unpin`
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> fn init<'a>(self: Pin<&'a mut Self>) {
|
||||
</span><span class="boring"> let self_ptr: *const String = &self.a;
|
||||
</span><span class="boring"> let this = unsafe { self.get_unchecked_mut() };
|
||||
</span><span class="boring"> this.b = self_ptr;
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn a<'a>(self: Pin<&'a Self>) -> &'a str {
|
||||
</span><span class="boring"> &self.get_ref().a
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||
</span><span class="boring"> unsafe { &*(self.b) }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}
|
||||
</span></code></pre></pre>
|
||||
# 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 {
|
||||
# Test {
|
||||
# a: String::from(txt),
|
||||
# b: std::ptr::null(),
|
||||
# _marker: PhantomPinned, // This makes our type `!Unpin`
|
||||
# }
|
||||
# }
|
||||
# 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>
|
||||
<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
|
||||
@@ -629,7 +627,7 @@ pub fn main() {
|
||||
println!("a: {}, b: {}",test2.as_ref().a(), test2.as_ref().b());
|
||||
}
|
||||
</code></pre></pre>
|
||||
<p>The fact that it's safe to pin a heap allocated value even if it is <code>!Unpin</code>
|
||||
<p>The fact that it's safe to pin heap allocated data even if it is <code>!Unpin</code>
|
||||
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
|
||||
that the self-referential pointer stays valid.</p>
|
||||
@@ -660,8 +658,7 @@ exceptions.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The main use case for <code>Pin</code> is to allow self referential types, the whole
|
||||
justification for stabilizing them was to allow that. There are still corner
|
||||
cases in the API which are being explored.</p>
|
||||
justification for stabilizing them was to allow that.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The implementation behind objects that are <code>!Unpin</code> is most likely unsafe.
|
||||
@@ -674,13 +671,13 @@ this book, creating and reading fields of a self referential struct still requir
|
||||
by adding <code>std::marker::PhantomPinned</code> to your type on stable.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can either pin a value to memory on the stack or on the heap.</p>
|
||||
<p>You can either pin an object to the stack or to the heap.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Pinning a <code>!Unpin</code> pointer to the stack requires <code>unsafe</code></p>
|
||||
<p>Pinning a <code>!Unpin</code> object to the stack requires <code>unsafe</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Pinning a <code>!Unpin</code> pointer to the heap does not require <code>unsafe</code>. There is a shortcut for doing this using <code>Box::pin</code>.</p>
|
||||
<p>Pinning a <code>!Unpin</code> object to the heap does not require <code>unsafe</code>. There is a shortcut for doing this using <code>Box::pin</code>.</p>
|
||||
</li>
|
||||
</ol>
|
||||
<blockquote>
|
||||
@@ -709,11 +706,11 @@ use std::pin::Pin;
|
||||
pub fn main() {
|
||||
let gen1 = GeneratorA::start();
|
||||
let gen2 = GeneratorA::start();
|
||||
// Before we pin the pointers, this is safe to do
|
||||
// Before we pin the data, this is safe to do
|
||||
// std::mem::swap(&mut gen, &mut gen2);
|
||||
|
||||
// constructing a `Pin::new()` on a type which does not implement `Unpin` is
|
||||
// unsafe. A value pinned to heap can be constructed while staying in safe
|
||||
// unsafe. An object pinned to heap can be constructed while staying in safe
|
||||
// Rust so we can use that to avoid unsafe. You can also use crates like
|
||||
// `pin_utils` to pin to the stack safely, just remember that they use
|
||||
// unsafe under the hood so it's like using an already-reviewed unsafe
|
||||
@@ -770,9 +767,9 @@ impl GeneratorA {
|
||||
}
|
||||
}
|
||||
|
||||
// This tells us that the underlying pointer is not safe to move after pinning.
|
||||
// This tells us that this object is not safe to move after pinning.
|
||||
// In this case, only we as implementors "feel" this, however, if someone is
|
||||
// relying on our Pinned pointer this will prevent them from moving it. You need
|
||||
// relying on our Pinned data this will prevent them from moving it. You need
|
||||
// to enable the feature flag `#![feature(optin_builtin_traits)]` and use the
|
||||
// nightly compiler to implement `!Unpin`. Normally, you would use
|
||||
// `std::marker::PhantomPinned` to indicate that the struct is `!Unpin`.
|
||||
@@ -898,18 +895,6 @@ we want to be able to safely borrow across <code>yield/await</code> points.</p>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
window.playpen_line_numbers = true;
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
window.playpen_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
Reference in New Issue
Block a user