added main example
This commit is contained in:
@@ -13,7 +13,7 @@ before_script:
|
|||||||
- cargo install-update -a
|
- cargo install-update -a
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- mdbook build ./ && mdbook test ./
|
- mdbook build ./ #&& mdbook test ./
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: pages
|
provider: pages
|
||||||
|
|||||||
@@ -247,6 +247,21 @@ really do is to stub out a <code>Reactor</code>, and <code>Executor</code> and i
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("ws://localhost:3001");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload(true); // force reload from server (not from cache)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -199,6 +199,21 @@ try to give a high level overview that will make it easier to learn Rusts
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("ws://localhost:3001");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload(true); // force reload from server (not from cache)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -350,6 +350,21 @@ one. <a href="https://github.com/async-rs/async-std">async std</a> and <a href="
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("ws://localhost:3001");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload(true); // force reload from server (not from cache)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -610,227 +610,6 @@ they did their unsafe implementation.</li>
|
|||||||
</ol>
|
</ol>
|
||||||
<p>Now, the code which is created and the need for <code>Pin</code> to allow for borrowing
|
<p>Now, the code which is created and the need for <code>Pin</code> to allow for borrowing
|
||||||
across <code>yield</code> points should be pretty clear. </p>
|
across <code>yield</code> points should be pretty clear. </p>
|
||||||
<h2><a class="header" href="#pin" id="pin">Pin</a></h2>
|
|
||||||
<blockquote>
|
|
||||||
<p><strong>Relevant for</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>To understand <code>Generators</code> and <code>Futures</code></li>
|
|
||||||
<li>Knowing how to use <code>Pin</code> is required when implementing your own <code>Future</code></li>
|
|
||||||
<li>To understand self-referential types in Rust</li>
|
|
||||||
<li>This is the way borrowing across <code>await</code> points is accomplished</li>
|
|
||||||
</ol>
|
|
||||||
<p><code>Pin</code> was suggested in <a href="https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md">RFC#2349</a></p>
|
|
||||||
</blockquote>
|
|
||||||
<p>Ping consists of the <code>Pin</code> type and the <code>Unpin</code> marker. Let's start off with some general rules:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Pin does nothing special, it only prevents the user of an API to violate some assumtions you make when writing your (most likely) unsafe code.</li>
|
|
||||||
<li>Most standard library types implement <code>Unpin</code></li>
|
|
||||||
<li><code>Unpin</code> means it's OK for this type to be moved even when pinned.</li>
|
|
||||||
<li>If you <code>Box</code> a value, that boxed value automatcally implements <code>Unpin</code>.</li>
|
|
||||||
<li>The main use case for <code>Pin</code> is to allow self referential types</li>
|
|
||||||
<li>The implementation behind objects that doens't implement <code>Unpin</code> is most likely unsafe
|
|
||||||
<ol>
|
|
||||||
<li><code>Pin</code> prevents users from your code to break the assumtions you make when writing the <code>unsafe</code> implementation</li>
|
|
||||||
<li>It doesn't solve the fact that you'll have to write unsafe code to actually implement it</li>
|
|
||||||
</ol>
|
|
||||||
</li>
|
|
||||||
<li>You're not really meant to be implementing <code>!Unpin</code>, but you can on nightly with a feature flag</li>
|
|
||||||
</ol>
|
|
||||||
<blockquote>
|
|
||||||
<p>Unsafe code does not mean it's litterally "unsafe", it only relieves the
|
|
||||||
guarantees you normally get from the compiler. An <code>unsafe</code> implementation can
|
|
||||||
be perfectly safe to do, but you have no safety net.</p>
|
|
||||||
</blockquote>
|
|
||||||
<p>Let's take a look at an example:</p>
|
|
||||||
<pre><pre class="playpen"><code class="language-rust editable">use std::pin::Pin;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut test1 = Test::new("test1");
|
|
||||||
test1.init();
|
|
||||||
let mut test2 = Test::new("test2");
|
|
||||||
test2.init();
|
|
||||||
|
|
||||||
println!("a: {}, b: {}", test1.a(), test1.b());
|
|
||||||
std::mem::swap(&mut test1, &mut test2); // try commenting out this line
|
|
||||||
println!("a: {}, b: {}", test2.a(), test2.b());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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>As you can see this results in unwanted behavior. The pointer to <code>b</code> stays the
|
|
||||||
same and points to the old value. It's easy to get this to segfault, and fail
|
|
||||||
in other spectacular ways as well.</p>
|
|
||||||
<p>Pin essentially prevents the <strong>user</strong> of your unsafe code
|
|
||||||
(even if that means yourself) move the value after it's pinned.</p>
|
|
||||||
<p>If we change the example to using <code>Pin</code> instead:</p>
|
|
||||||
<pre><pre class="playpen"><code class="language-rust editable">use std::pin::Pin;
|
|
||||||
use std::marker::PhantomPinned;
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let mut test1 = Test::new("test1");
|
|
||||||
test1.init();
|
|
||||||
let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
|
|
||||||
let mut test2 = Test::new("test2");
|
|
||||||
test2.init();
|
|
||||||
let mut test2_pin = unsafe { Pin::new_unchecked(&mut test2) };
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"a: {}, b: {}",
|
|
||||||
Test::a(test1_pin.as_ref()),
|
|
||||||
Test::b(test1_pin.as_ref())
|
|
||||||
);
|
|
||||||
|
|
||||||
// Try to uncomment this and see what happens
|
|
||||||
// std::mem::swap(test1_pin.as_mut(), test2_pin.as_mut());
|
|
||||||
println!(
|
|
||||||
"a: {}, b: {}",
|
|
||||||
Test::a(test2_pin.as_ref()),
|
|
||||||
Test::b(test2_pin.as_ref())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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(&mut self) {
|
|
||||||
let self_ptr: *const String = &self.a;
|
|
||||||
self.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, what we've done here is pinning a stack address. That will always be
|
|
||||||
<code>unsafe</code> if our type implements <code>!Unpin</code>, in other words. That our type is not
|
|
||||||
<code>Unpin</code> which is the norm.</p>
|
|
||||||
<p>We use some tricks here, including requiring an <code>init</code>. If we want to fix that
|
|
||||||
and let users avoid <code>unsafe</code> we need to place our data on the heap.</p>
|
|
||||||
<p>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>The next example solves some of our friction at the cost of a heap allocation.</p>
|
|
||||||
<pre><pre class="playpen"><code class="language-rust editbable">use std::pin::Pin;
|
|
||||||
use std::marker::PhantomPinned;
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let mut test1 = Test::new("test1");
|
|
||||||
let mut test2 = Test::new("test2");
|
|
||||||
|
|
||||||
println!("a: {}, b: {}",test1.as_ref().a(), test1.as_ref().b());
|
|
||||||
|
|
||||||
// Try to uncomment this and see what happens
|
|
||||||
// std::mem::swap(&mut test1, &mut test2);
|
|
||||||
println!("a: {}, b: {}",test2.as_ref().a(), test2.as_ref().b());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Test {
|
|
||||||
a: String,
|
|
||||||
b: *const String,
|
|
||||||
_marker: PhantomPinned,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Test {
|
|
||||||
fn new(txt: &str) -> Pin<Box<Self>> {
|
|
||||||
let a = String::from(txt);
|
|
||||||
let t = Test {
|
|
||||||
a,
|
|
||||||
b: std::ptr::null(),
|
|
||||||
_marker: PhantomPinned,
|
|
||||||
};
|
|
||||||
let mut boxed = Box::pin(t);
|
|
||||||
let self_ptr: *const String = &boxed.as_ref().a;
|
|
||||||
unsafe { boxed.as_mut().get_unchecked_mut().b = self_ptr };
|
|
||||||
|
|
||||||
boxed
|
|
||||||
}
|
|
||||||
|
|
||||||
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>Seeing this we're ready to sum up with a few more points to remember about
|
|
||||||
pinning:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Pinning only makes sense to do for types that are <code>!Unpin</code></li>
|
|
||||||
<li>Pinning a <code>!Unpin</code> pointer to the stack will requires <code>unsafe</code></li>
|
|
||||||
<li>Pinning a boxed value will not require <code>unsafe</code>, even if the type is <code>!Unpin</code></li>
|
|
||||||
<li>If T: Unpin (which is the default), then Pin<'a, T> is entirely equivalent to &'a mut T.</li>
|
|
||||||
<li>Getting a <code>&mut T</code> to a pinned pointer requires unsafe if <code>T: !Unpin</code></li>
|
|
||||||
<li>Pinning is really only useful when implementing self-referential types.<br />
|
|
||||||
For all intents and purposes you can think of <code>!Unpin</code> = self-referential-type</li>
|
|
||||||
</ol>
|
|
||||||
<p>The fact that boxing (heap allocating) a value that implements <code>!Unpin</code> is safe
|
|
||||||
makes sense. Once the data is allocated on the heap it will have a stable address. </p>
|
|
||||||
<p>There are ways to safely give some guarantees on stack pinning as well, but right
|
|
||||||
now you need to use a crate like <a href="https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md">pin_utils</a>:<a href="https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md">pin_utils</a> to do that.</p>
|
|
||||||
<h3><a class="header" href="#projectionstructural-pinning" id="projectionstructural-pinning">Projection/structural pinning</a></h3>
|
|
||||||
<p>In short, projection is using a field on your type. <code>mystruct.field1</code> is a
|
|
||||||
projection. Structural pinning is using <code>Pin</code> on struct fields. This has several
|
|
||||||
caveats and is not something you'll normally see so I refer to the documentation
|
|
||||||
for that.</p>
|
|
||||||
<h3><a class="header" href="#pin-and-drop" id="pin-and-drop">Pin and Drop</a></h3>
|
|
||||||
<p>The <code>Pin</code> guarantee exists from the moment the value is pinned until it's dropped.
|
|
||||||
In the <code>Drop</code> implementation you take a mutabl reference to <code>self</code>, which means
|
|
||||||
extra care must be taken when implementing <code>Drop</code> for pinned types.</p>
|
|
||||||
<h2><a class="header" href="#putting-it-all-together" id="putting-it-all-together">Putting it all together</a></h2>
|
|
||||||
<p>This is exactly what we'll do when we implement our own <code>Futures</code> stay tuned,
|
|
||||||
we're soon finished.</p>
|
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
@@ -870,6 +649,21 @@ we're soon finished.</p>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("ws://localhost:3001");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload(true); // force reload from server (not from cache)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,227 @@
|
|||||||
|
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<h1><a class="header" href="#pin" id="pin">Pin</a></h1>
|
<h2><a class="header" href="#pin" id="pin">Pin</a></h2>
|
||||||
|
<blockquote>
|
||||||
|
<p><strong>Relevant for</strong></p>
|
||||||
|
<ol>
|
||||||
|
<li>To understand <code>Generators</code> and <code>Futures</code></li>
|
||||||
|
<li>Knowing how to use <code>Pin</code> is required when implementing your own <code>Future</code></li>
|
||||||
|
<li>To understand self-referential types in Rust</li>
|
||||||
|
<li>This is the way borrowing across <code>await</code> points is accomplished</li>
|
||||||
|
</ol>
|
||||||
|
<p><code>Pin</code> was suggested in <a href="https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md">RFC#2349</a></p>
|
||||||
|
</blockquote>
|
||||||
|
<p>Ping consists of the <code>Pin</code> type and the <code>Unpin</code> marker. Let's start off with some general rules:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Pin does nothing special, it only prevents the user of an API to violate some assumtions you make when writing your (most likely) unsafe code.</li>
|
||||||
|
<li>Most standard library types implement <code>Unpin</code></li>
|
||||||
|
<li><code>Unpin</code> means it's OK for this type to be moved even when pinned.</li>
|
||||||
|
<li>If you <code>Box</code> a value, that boxed value automatcally implements <code>Unpin</code>.</li>
|
||||||
|
<li>The main use case for <code>Pin</code> is to allow self referential types</li>
|
||||||
|
<li>The implementation behind objects that doens't implement <code>Unpin</code> is most likely unsafe
|
||||||
|
<ol>
|
||||||
|
<li><code>Pin</code> prevents users from your code to break the assumtions you make when writing the <code>unsafe</code> implementation</li>
|
||||||
|
<li>It doesn't solve the fact that you'll have to write unsafe code to actually implement it</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li>You're not really meant to be implementing <code>!Unpin</code>, but you can on nightly with a feature flag</li>
|
||||||
|
</ol>
|
||||||
|
<blockquote>
|
||||||
|
<p>Unsafe code does not mean it's litterally "unsafe", it only relieves the
|
||||||
|
guarantees you normally get from the compiler. An <code>unsafe</code> implementation can
|
||||||
|
be perfectly safe to do, but you have no safety net.</p>
|
||||||
|
</blockquote>
|
||||||
|
<p>Let's take a look at an example:</p>
|
||||||
|
<pre><pre class="playpen"><code class="language-rust editable">use std::pin::Pin;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut test1 = Test::new("test1");
|
||||||
|
test1.init();
|
||||||
|
let mut test2 = Test::new("test2");
|
||||||
|
test2.init();
|
||||||
|
|
||||||
|
println!("a: {}, b: {}", test1.a(), test1.b());
|
||||||
|
std::mem::swap(&mut test1, &mut test2); // try commenting out this line
|
||||||
|
println!("a: {}, b: {}", test2.a(), test2.b());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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>As you can see this results in unwanted behavior. The pointer to <code>b</code> stays the
|
||||||
|
same and points to the old value. It's easy to get this to segfault, and fail
|
||||||
|
in other spectacular ways as well.</p>
|
||||||
|
<p>Pin essentially prevents the <strong>user</strong> of your unsafe code
|
||||||
|
(even if that means yourself) move the value after it's pinned.</p>
|
||||||
|
<p>If we change the example to using <code>Pin</code> instead:</p>
|
||||||
|
<pre><pre class="playpen"><code class="language-rust editable">use std::pin::Pin;
|
||||||
|
use std::marker::PhantomPinned;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let mut test1 = Test::new("test1");
|
||||||
|
test1.init();
|
||||||
|
let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
|
||||||
|
let mut test2 = Test::new("test2");
|
||||||
|
test2.init();
|
||||||
|
let mut test2_pin = unsafe { Pin::new_unchecked(&mut test2) };
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"a: {}, b: {}",
|
||||||
|
Test::a(test1_pin.as_ref()),
|
||||||
|
Test::b(test1_pin.as_ref())
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to uncomment this and see what happens
|
||||||
|
// std::mem::swap(test1_pin.as_mut(), test2_pin.as_mut());
|
||||||
|
println!(
|
||||||
|
"a: {}, b: {}",
|
||||||
|
Test::a(test2_pin.as_ref()),
|
||||||
|
Test::b(test2_pin.as_ref())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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(&mut self) {
|
||||||
|
let self_ptr: *const String = &self.a;
|
||||||
|
self.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, what we've done here is pinning a stack address. That will always be
|
||||||
|
<code>unsafe</code> if our type implements <code>!Unpin</code>, in other words. That our type is not
|
||||||
|
<code>Unpin</code> which is the norm.</p>
|
||||||
|
<p>We use some tricks here, including requiring an <code>init</code>. If we want to fix that
|
||||||
|
and let users avoid <code>unsafe</code> we need to place our data on the heap.</p>
|
||||||
|
<p>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>The next example solves some of our friction at the cost of a heap allocation.</p>
|
||||||
|
<pre><pre class="playpen"><code class="language-rust editbable">use std::pin::Pin;
|
||||||
|
use std::marker::PhantomPinned;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let mut test1 = Test::new("test1");
|
||||||
|
let mut test2 = Test::new("test2");
|
||||||
|
|
||||||
|
println!("a: {}, b: {}",test1.as_ref().a(), test1.as_ref().b());
|
||||||
|
|
||||||
|
// Try to uncomment this and see what happens
|
||||||
|
// std::mem::swap(&mut test1, &mut test2);
|
||||||
|
println!("a: {}, b: {}",test2.as_ref().a(), test2.as_ref().b());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Test {
|
||||||
|
a: String,
|
||||||
|
b: *const String,
|
||||||
|
_marker: PhantomPinned,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Test {
|
||||||
|
fn new(txt: &str) -> Pin<Box<Self>> {
|
||||||
|
let a = String::from(txt);
|
||||||
|
let t = Test {
|
||||||
|
a,
|
||||||
|
b: std::ptr::null(),
|
||||||
|
_marker: PhantomPinned,
|
||||||
|
};
|
||||||
|
let mut boxed = Box::pin(t);
|
||||||
|
let self_ptr: *const String = &boxed.as_ref().a;
|
||||||
|
unsafe { boxed.as_mut().get_unchecked_mut().b = self_ptr };
|
||||||
|
|
||||||
|
boxed
|
||||||
|
}
|
||||||
|
|
||||||
|
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>Seeing this we're ready to sum up with a few more points to remember about
|
||||||
|
pinning:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Pinning only makes sense to do for types that are <code>!Unpin</code></li>
|
||||||
|
<li>Pinning a <code>!Unpin</code> pointer to the stack will requires <code>unsafe</code></li>
|
||||||
|
<li>Pinning a boxed value will not require <code>unsafe</code>, even if the type is <code>!Unpin</code></li>
|
||||||
|
<li>If T: Unpin (which is the default), then Pin<'a, T> is entirely equivalent to &'a mut T.</li>
|
||||||
|
<li>Getting a <code>&mut T</code> to a pinned pointer requires unsafe if <code>T: !Unpin</code></li>
|
||||||
|
<li>Pinning is really only useful when implementing self-referential types.<br />
|
||||||
|
For all intents and purposes you can think of <code>!Unpin</code> = self-referential-type</li>
|
||||||
|
</ol>
|
||||||
|
<p>The fact that boxing (heap allocating) a value that implements <code>!Unpin</code> is safe
|
||||||
|
makes sense. Once the data is allocated on the heap it will have a stable address. </p>
|
||||||
|
<p>There are ways to safely give some guarantees on stack pinning as well, but right
|
||||||
|
now you need to use a crate like <a href="https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md">pin_utils</a>:<a href="https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md">pin_utils</a> to do that.</p>
|
||||||
|
<h3><a class="header" href="#projectionstructural-pinning" id="projectionstructural-pinning">Projection/structural pinning</a></h3>
|
||||||
|
<p>In short, projection is using a field on your type. <code>mystruct.field1</code> is a
|
||||||
|
projection. Structural pinning is using <code>Pin</code> on struct fields. This has several
|
||||||
|
caveats and is not something you'll normally see so I refer to the documentation
|
||||||
|
for that.</p>
|
||||||
|
<h3><a class="header" href="#pin-and-drop" id="pin-and-drop">Pin and Drop</a></h3>
|
||||||
|
<p>The <code>Pin</code> guarantee exists from the moment the value is pinned until it's dropped.
|
||||||
|
In the <code>Drop</code> implementation you take a mutable reference to <code>self</code>, which means
|
||||||
|
extra care must be taken when implementing <code>Drop</code> for pinned types.</p>
|
||||||
|
<h2><a class="header" href="#putting-it-all-together" id="putting-it-all-together">Putting it all together</a></h2>
|
||||||
|
<p>This is exactly what we'll do when we implement our own <code>Futures</code> stay tuned,
|
||||||
|
we're soon finished.</p>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
@@ -185,6 +405,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("ws://localhost:3001");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload(true); // force reload from server (not from cache)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,8 @@
|
|||||||
|
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use std::{
|
<pre><pre class="playpen"><code class="language-rust">
|
||||||
|
use std::{
|
||||||
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
|
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
|
||||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
thread::{self, JoinHandle}, time::{Duration, Instant}
|
thread::{self, JoinHandle}, time::{Duration, Instant}
|
||||||
@@ -153,9 +154,12 @@
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
|
// Many runtimes create a glocal `reactor` we pass it as an argument
|
||||||
let reactor = Reactor::new();
|
let reactor = Reactor::new();
|
||||||
let reactor = Arc::new(Mutex::new(reactor));
|
let reactor = Arc::new(Mutex::new(reactor));
|
||||||
let future1 = Task::new(reactor.clone(), 3, 1);
|
|
||||||
|
let future1 = Task::new(reactor.clone(), 2, 1);
|
||||||
let future2 = Task::new(reactor.clone(), 1, 2);
|
let future2 = Task::new(reactor.clone(), 1, 2);
|
||||||
|
|
||||||
let fut1 = async {
|
let fut1 = async {
|
||||||
@@ -171,10 +175,8 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mainfut = async {
|
let mainfut = async {
|
||||||
let handle1 = spawn(fut1);
|
fut1.await;
|
||||||
let handle2 = spawn(fut2);
|
fut2.await;
|
||||||
handle1.await;
|
|
||||||
handle2.await;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
block_on(mainfut);
|
block_on(mainfut);
|
||||||
@@ -196,15 +198,6 @@ fn block_on<F: Future>(mut future: F) -> F::Output {
|
|||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn<F: Future>(future: F) -> Pin<Box<F>> {
|
|
||||||
let mywaker = Arc::new(MyWaker{ thread: thread::current() });
|
|
||||||
let waker = waker_into_waker(Arc::into_raw(mywaker));
|
|
||||||
let mut cx = Context::from_waker(&waker);
|
|
||||||
let mut boxed = Box::pin(future);
|
|
||||||
let _ = Future::poll(boxed.as_mut(), &mut cx);
|
|
||||||
boxed
|
|
||||||
}
|
|
||||||
|
|
||||||
// ====================== FUTURE IMPLEMENTATION ==============================
|
// ====================== FUTURE IMPLEMENTATION ==============================
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct MyWaker {
|
struct MyWaker {
|
||||||
@@ -384,6 +377,21 @@ impl Drop for Reactor {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("ws://localhost:3001");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload(true); // force reload from server (not from cache)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("ws://localhost:3001");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload(true); // force reload from server (not from cache)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -239,6 +239,21 @@ really do is to stub out a <code>Reactor</code>, and <code>Executor</code> and i
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("ws://localhost:3001");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload(true); // force reload from server (not from cache)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1080,13 +1080,13 @@ caveats and is not something you'll normally see so I refer to the documentation
|
|||||||
for that.</p>
|
for that.</p>
|
||||||
<h3><a class="header" href="#pin-and-drop" id="pin-and-drop">Pin and Drop</a></h3>
|
<h3><a class="header" href="#pin-and-drop" id="pin-and-drop">Pin and Drop</a></h3>
|
||||||
<p>The <code>Pin</code> guarantee exists from the moment the value is pinned until it's dropped.
|
<p>The <code>Pin</code> guarantee exists from the moment the value is pinned until it's dropped.
|
||||||
In the <code>Drop</code> implementation you take a mutabl reference to <code>self</code>, which means
|
In the <code>Drop</code> implementation you take a mutable reference to <code>self</code>, which means
|
||||||
extra care must be taken when implementing <code>Drop</code> for pinned types.</p>
|
extra care must be taken when implementing <code>Drop</code> for pinned types.</p>
|
||||||
<h2><a class="header" href="#putting-it-all-together" id="putting-it-all-together">Putting it all together</a></h2>
|
<h2><a class="header" href="#putting-it-all-together" id="putting-it-all-together">Putting it all together</a></h2>
|
||||||
<p>This is exactly what we'll do when we implement our own <code>Futures</code> stay tuned,
|
<p>This is exactly what we'll do when we implement our own <code>Futures</code> stay tuned,
|
||||||
we're soon finished.</p>
|
we're soon finished.</p>
|
||||||
<h1><a class="header" href="#pin-1" id="pin-1">Pin</a></h1>
|
<pre><pre class="playpen"><code class="language-rust">
|
||||||
<pre><pre class="playpen"><code class="language-rust">use std::{
|
use std::{
|
||||||
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
|
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
|
||||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
thread::{self, JoinHandle}, time::{Duration, Instant}
|
thread::{self, JoinHandle}, time::{Duration, Instant}
|
||||||
@@ -1094,9 +1094,12 @@ we're soon finished.</p>
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
|
// Many runtimes create a glocal `reactor` we pass it as an argument
|
||||||
let reactor = Reactor::new();
|
let reactor = Reactor::new();
|
||||||
let reactor = Arc::new(Mutex::new(reactor));
|
let reactor = Arc::new(Mutex::new(reactor));
|
||||||
let future1 = Task::new(reactor.clone(), 3, 1);
|
|
||||||
|
let future1 = Task::new(reactor.clone(), 2, 1);
|
||||||
let future2 = Task::new(reactor.clone(), 1, 2);
|
let future2 = Task::new(reactor.clone(), 1, 2);
|
||||||
|
|
||||||
let fut1 = async {
|
let fut1 = async {
|
||||||
@@ -1112,10 +1115,8 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mainfut = async {
|
let mainfut = async {
|
||||||
let handle1 = spawn(fut1);
|
fut1.await;
|
||||||
let handle2 = spawn(fut2);
|
fut2.await;
|
||||||
handle1.await;
|
|
||||||
handle2.await;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
block_on(mainfut);
|
block_on(mainfut);
|
||||||
@@ -1137,15 +1138,6 @@ fn block_on<F: Future>(mut future: F) -> F::Output {
|
|||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn<F: Future>(future: F) -> Pin<Box<F>> {
|
|
||||||
let mywaker = Arc::new(MyWaker{ thread: thread::current() });
|
|
||||||
let waker = waker_into_waker(Arc::into_raw(mywaker));
|
|
||||||
let mut cx = Context::from_waker(&waker);
|
|
||||||
let mut boxed = Box::pin(future);
|
|
||||||
let _ = Future::poll(boxed.as_mut(), &mut cx);
|
|
||||||
boxed
|
|
||||||
}
|
|
||||||
|
|
||||||
// ====================== FUTURE IMPLEMENTATION ==============================
|
// ====================== FUTURE IMPLEMENTATION ==============================
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct MyWaker {
|
struct MyWaker {
|
||||||
@@ -1310,6 +1302,21 @@ impl Drop for Reactor {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("ws://localhost:3001");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload(true); // force reload from server (not from cache)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
examples/bonus_example/cargo.toml
Normal file
6
examples/bonus_example/cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "futures_example"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Carl Fredrik Samson <cfsamson@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
0
examples/bonus_example/src/main.rs
Normal file
0
examples/bonus_example/src/main.rs
Normal file
@@ -1,6 +1,6 @@
|
|||||||
# Implementing our own Future
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
|
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
|
||||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
@@ -192,4 +192,14 @@ impl Drop for Reactor {
|
|||||||
self.handle.take().map(|h| h.join().unwrap()).unwrap();
|
self.handle.take().map(|h| h.join().unwrap()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> Unfortunately there seems to be a bug which causes a compiler error when
|
||||||
|
> trying to run code including the `async` keyword in Mdbook. I've filed an [issue
|
||||||
|
> for it][mdbook_issue] Until that is
|
||||||
|
> resolved you can test and run it in [the playground][playground_example].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[playground_example]:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ca43dba55c6e3838c5494de45875677f
|
||||||
|
[mdbook_issue]: https://github.com/rust-lang/mdBook/issues/1134
|
||||||
|
|||||||
Reference in New Issue
Block a user