added main example
This commit is contained in:
@@ -13,7 +13,7 @@ before_script:
|
||||
- cargo install-update -a
|
||||
|
||||
script:
|
||||
- mdbook build ./ && mdbook test ./
|
||||
- mdbook build ./ #&& mdbook test ./
|
||||
|
||||
deploy:
|
||||
provider: pages
|
||||
|
||||
@@ -247,6 +247,21 @@ really do is to stub out a <code>Reactor</code>, and <code>Executor</code> and i
|
||||
</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>
|
||||
|
||||
|
||||
<!-- 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>
|
||||
|
||||
|
||||
<!-- 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>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@@ -870,6 +649,21 @@ we're soon finished.</p>
|
||||
</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">
|
||||
<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>
|
||||
|
||||
@@ -185,6 +405,21 @@
|
||||
</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">
|
||||
<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},
|
||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
thread::{self, JoinHandle}, time::{Duration, Instant}
|
||||
@@ -153,9 +154,12 @@
|
||||
|
||||
fn main() {
|
||||
let start = Instant::now();
|
||||
|
||||
// Many runtimes create a glocal `reactor` we pass it as an argument
|
||||
let reactor = Reactor::new();
|
||||
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 fut1 = async {
|
||||
@@ -171,10 +175,8 @@ fn main() {
|
||||
};
|
||||
|
||||
let mainfut = async {
|
||||
let handle1 = spawn(fut1);
|
||||
let handle2 = spawn(fut2);
|
||||
handle1.await;
|
||||
handle2.await;
|
||||
fut1.await;
|
||||
fut2.await;
|
||||
};
|
||||
|
||||
block_on(mainfut);
|
||||
@@ -196,15 +198,6 @@ fn block_on<F: Future>(mut future: F) -> F::Output {
|
||||
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 ==============================
|
||||
#[derive(Clone)]
|
||||
struct MyWaker {
|
||||
@@ -384,6 +377,21 @@ impl Drop for Reactor {
|
||||
</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>
|
||||
|
||||
|
||||
<!-- 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>
|
||||
|
||||
|
||||
<!-- 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>
|
||||
<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
|
||||
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>
|
||||
<h1><a class="header" href="#pin-1" id="pin-1">Pin</a></h1>
|
||||
<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},
|
||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
thread::{self, JoinHandle}, time::{Duration, Instant}
|
||||
@@ -1094,9 +1094,12 @@ we're soon finished.</p>
|
||||
|
||||
fn main() {
|
||||
let start = Instant::now();
|
||||
|
||||
// Many runtimes create a glocal `reactor` we pass it as an argument
|
||||
let reactor = Reactor::new();
|
||||
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 fut1 = async {
|
||||
@@ -1112,10 +1115,8 @@ fn main() {
|
||||
};
|
||||
|
||||
let mainfut = async {
|
||||
let handle1 = spawn(fut1);
|
||||
let handle2 = spawn(fut2);
|
||||
handle1.await;
|
||||
handle2.await;
|
||||
fut1.await;
|
||||
fut2.await;
|
||||
};
|
||||
|
||||
block_on(mainfut);
|
||||
@@ -1137,15 +1138,6 @@ fn block_on<F: Future>(mut future: F) -> F::Output {
|
||||
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 ==============================
|
||||
#[derive(Clone)]
|
||||
struct MyWaker {
|
||||
@@ -1310,6 +1302,21 @@ impl Drop for Reactor {
|
||||
</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
|
||||
|
||||
use std::{
|
||||
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
|
||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
@@ -192,4 +192,14 @@ impl Drop for Reactor {
|
||||
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