mirror of https://github.com/rust-lang/async-book
Merge branch 'rust-lang:master' into master
This commit is contained in:
commit
4dc5f4ef9e
|
@ -37,7 +37,7 @@ impl SimpleFuture for SocketRead<'_> {
|
|||
|
||||
fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
|
||||
if self.socket.has_data_to_read() {
|
||||
// The socket has data-- read it into a buffer and return it.
|
||||
// The socket has data -- read it into a buffer and return it.
|
||||
Poll::Ready(self.socket.read_buf())
|
||||
} else {
|
||||
// The socket does not yet have data.
|
||||
|
@ -89,7 +89,7 @@ where
|
|||
}
|
||||
|
||||
if self.a.is_none() && self.b.is_none() {
|
||||
// Both futures have completed-- we can return successfully
|
||||
// Both futures have completed -- we can return successfully
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
// One or both futures returned `Poll::Pending` and still have
|
||||
|
@ -121,7 +121,7 @@ where
|
|||
fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
|
||||
if let Some(first) = &mut self.first {
|
||||
match first.poll(wake) {
|
||||
// We've completed the first future-- remove it and start on
|
||||
// We've completed the first future -- remove it and start on
|
||||
// the second!
|
||||
Poll::Ready(()) => self.first.take(),
|
||||
// We couldn't yet complete the first future.
|
||||
|
|
|
@ -10,7 +10,7 @@ use {
|
|||
future::Future,
|
||||
sync::mpsc::{sync_channel, Receiver, SyncSender},
|
||||
sync::{Arc, Mutex},
|
||||
task::{Context, Poll},
|
||||
task::Context,
|
||||
time::Duration,
|
||||
},
|
||||
// The timer we wrote in the previous section:
|
||||
|
@ -97,7 +97,7 @@ impl Executor {
|
|||
// `Pin<Box<dyn Future<Output = T> + Send + 'static>>`.
|
||||
// We can get a `Pin<&mut dyn Future + Send + 'static>`
|
||||
// from it by calling the `Pin::as_mut` method.
|
||||
if let Poll::Pending = future.as_mut().poll(context) {
|
||||
if future.as_mut().poll(context).is_pending() {
|
||||
// We're not done processing the future, so put it
|
||||
// back in its task to be run again in the future.
|
||||
*future_slot = Some(future);
|
||||
|
|
|
@ -62,12 +62,12 @@ async fn blocks() {
|
|||
|
||||
let future_one = async {
|
||||
// ...
|
||||
println!("{}", my_string);
|
||||
println!("{my_string}");
|
||||
};
|
||||
|
||||
let future_two = async {
|
||||
// ...
|
||||
println!("{}", my_string);
|
||||
println!("{my_string}");
|
||||
};
|
||||
|
||||
// Run both futures to completion, printing "foo" twice:
|
||||
|
@ -84,7 +84,7 @@ fn move_block() -> impl Future<Output = ()> {
|
|||
let my_string = "foo".to_string();
|
||||
async move {
|
||||
// ...
|
||||
println!("{}", my_string);
|
||||
println!("{my_string}");
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: async_move_examples
|
||||
|
|
|
@ -112,7 +112,7 @@ async fn run_loop(
|
|||
}
|
||||
},
|
||||
new_num = get_new_num_fut => {
|
||||
// A new number has arrived-- start a new `run_on_new_num_fut`,
|
||||
// A new number has arrived -- start a new `run_on_new_num_fut`,
|
||||
// dropping the old one.
|
||||
run_on_new_num_fut.set(run_on_new_num(new_num).fuse());
|
||||
},
|
||||
|
@ -165,7 +165,7 @@ async fn run_loop(
|
|||
}
|
||||
},
|
||||
new_num = get_new_num_fut => {
|
||||
// A new number has arrived-- start a new `run_on_new_num_fut`.
|
||||
// A new number has arrived -- start a new `run_on_new_num_fut`.
|
||||
run_on_new_num_futs.push(run_on_new_num(new_num));
|
||||
},
|
||||
// Run the `run_on_new_num_futs` and check if any have completed
|
||||
|
|
|
@ -33,7 +33,7 @@ fn handle_connection(mut stream: TcpStream) {
|
|||
|
||||
// Write response back to the stream,
|
||||
// and flush the stream to ensure the response is sent back to the client
|
||||
let response = format!("{}{}", status_line, contents);
|
||||
stream.write(response.as_bytes()).unwrap();
|
||||
let response = format!("{status_line}{contents}");
|
||||
stream.write_all(response.as_bytes()).unwrap();
|
||||
stream.flush().unwrap();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ async fn handle_connection(mut stream: TcpStream) {
|
|||
};
|
||||
let contents = fs::read_to_string(filename).unwrap();
|
||||
|
||||
let response = format!("{}{}", status_line, contents);
|
||||
let response = format!("{status_line}{contents}");
|
||||
stream.write(response.as_bytes()).unwrap();
|
||||
stream.flush().unwrap();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ async fn handle_connection(mut stream: impl Read + Write + Unpin) {
|
|||
("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html")
|
||||
};
|
||||
let contents = fs::read_to_string(filename).unwrap();
|
||||
let response = format!("{}{}", status_line, contents);
|
||||
let response = format!("{status_line}{contents}");
|
||||
stream.write(response.as_bytes()).await.unwrap();
|
||||
stream.flush().await.unwrap();
|
||||
}
|
||||
|
@ -75,11 +75,14 @@ mod tests {
|
|||
buf: &[u8],
|
||||
) -> Poll<Result<usize, Error>> {
|
||||
self.write_data = Vec::from(buf);
|
||||
return Poll::Ready(Ok(buf.len()));
|
||||
|
||||
Poll::Ready(Ok(buf.len()))
|
||||
}
|
||||
|
||||
fn poll_flush(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn poll_close(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ For the sake of the example, we'll just spin up a new thread when the timer
|
|||
is created, sleep for the required time, and then signal the timer future
|
||||
when the time window has elapsed.
|
||||
|
||||
First, start a new project with `cargo new timer_future` and add the imports
|
||||
First, start a new project with `cargo new --lib timer_future` and add the imports
|
||||
we'll need to get started to `src/lib.rs`:
|
||||
|
||||
```rust
|
||||
|
|
|
@ -108,8 +108,6 @@ types in Rust.
|
|||
For now our example will look like this:
|
||||
|
||||
```rust, ignore
|
||||
use std::pin::Pin;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Test {
|
||||
a: String,
|
||||
|
@ -158,7 +156,6 @@ fn main() {
|
|||
println!("a: {}, b: {}", test2.a(), test2.b());
|
||||
|
||||
}
|
||||
# use std::pin::Pin;
|
||||
# #[derive(Debug)]
|
||||
# struct Test {
|
||||
# a: String,
|
||||
|
@ -210,7 +207,6 @@ fn main() {
|
|||
println!("a: {}, b: {}", test2.a(), test2.b());
|
||||
|
||||
}
|
||||
# use std::pin::Pin;
|
||||
# #[derive(Debug)]
|
||||
# struct Test {
|
||||
# a: String,
|
||||
|
@ -275,7 +271,6 @@ fn main() {
|
|||
println!("a: {}, b: {}", test2.a(), test2.b());
|
||||
|
||||
}
|
||||
# use std::pin::Pin;
|
||||
# #[derive(Debug)]
|
||||
# struct Test {
|
||||
# a: String,
|
||||
|
@ -318,8 +313,9 @@ It's easy to get this to show undefined behavior and fail in other spectacular w
|
|||
Let's see how pinning and the `Pin` type can help us solve this problem.
|
||||
|
||||
The `Pin` type wraps pointer types, guaranteeing that the values behind the
|
||||
pointer won't be moved. For example, `Pin<&mut T>`, `Pin<&T>`,
|
||||
`Pin<Box<T>>` all guarantee that `T` won't be moved even if `T: !Unpin`.
|
||||
pointer won't be moved if it is not implementing `Unpin`. For example, `Pin<&mut
|
||||
T>`, `Pin<&T>`, `Pin<Box<T>>` all guarantee that `T` won't be moved if `T:
|
||||
!Unpin`.
|
||||
|
||||
Most types don't have a problem being moved. These types implement a trait
|
||||
called `Unpin`. Pointers to `Unpin` types can be freely placed into or taken
|
||||
|
@ -354,17 +350,18 @@ impl Test {
|
|||
_marker: PhantomPinned, // This makes our type `!Unpin`
|
||||
}
|
||||
}
|
||||
fn init<'a>(self: Pin<&'a mut Self>) {
|
||||
|
||||
fn init(self: Pin<&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 {
|
||||
fn a(self: Pin<&Self>) -> &str {
|
||||
&self.get_ref().a
|
||||
}
|
||||
|
||||
fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||
fn b(self: Pin<&Self>) -> &String {
|
||||
assert!(!self.b.is_null(), "Test::b called without Test::init being called first");
|
||||
unsafe { &*(self.b) }
|
||||
}
|
||||
|
@ -412,17 +409,18 @@ pub fn main() {
|
|||
# _marker: PhantomPinned,
|
||||
# }
|
||||
# }
|
||||
# fn init<'a>(self: Pin<&'a mut Self>) {
|
||||
#
|
||||
# fn init(self: Pin<&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 {
|
||||
# fn a(self: Pin<&Self>) -> &str {
|
||||
# &self.get_ref().a
|
||||
# }
|
||||
#
|
||||
# fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||
# fn b(self: Pin<&Self>) -> &String {
|
||||
# assert!(!self.b.is_null(), "Test::b called without Test::init being called first");
|
||||
# unsafe { &*(self.b) }
|
||||
# }
|
||||
|
@ -464,17 +462,18 @@ pub fn main() {
|
|||
# _marker: PhantomPinned, // This makes our type `!Unpin`
|
||||
# }
|
||||
# }
|
||||
# fn init<'a>(self: Pin<&'a mut Self>) {
|
||||
#
|
||||
# fn init(self: Pin<&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 {
|
||||
# fn a(self: Pin<&Self>) -> &str {
|
||||
# &self.get_ref().a
|
||||
# }
|
||||
#
|
||||
# fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||
# fn b(self: Pin<&Self>) -> &String {
|
||||
# assert!(!self.b.is_null(), "Test::b called without Test::init being called first");
|
||||
# unsafe { &*(self.b) }
|
||||
# }
|
||||
|
@ -498,8 +497,10 @@ The type system prevents us from moving the data.
|
|||
> let mut test1 = Test::new("test1");
|
||||
> let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
|
||||
> Test::init(test1_pin.as_mut());
|
||||
>
|
||||
> drop(test1_pin);
|
||||
> println!(r#"test1.b points to "test1": {:?}..."#, test1.b);
|
||||
>
|
||||
> let mut test2 = Test::new("test2");
|
||||
> mem::swap(&mut test1, &mut test2);
|
||||
> println!("... and now it points nowhere: {:?}", test1.b);
|
||||
|
@ -525,6 +526,7 @@ The type system prevents us from moving the data.
|
|||
> # _marker: PhantomPinned,
|
||||
> # }
|
||||
> # }
|
||||
> #
|
||||
> # fn init<'a>(self: Pin<&'a mut Self>) {
|
||||
> # let self_ptr: *const String = &self.a;
|
||||
> # let this = unsafe { self.get_unchecked_mut() };
|
||||
|
@ -567,24 +569,24 @@ impl Test {
|
|||
_marker: PhantomPinned,
|
||||
};
|
||||
let mut boxed = Box::pin(t);
|
||||
let self_ptr: *const String = &boxed.as_ref().a;
|
||||
let self_ptr: *const String = &boxed.a;
|
||||
unsafe { boxed.as_mut().get_unchecked_mut().b = self_ptr };
|
||||
|
||||
boxed
|
||||
}
|
||||
|
||||
fn a<'a>(self: Pin<&'a Self>) -> &'a str {
|
||||
fn a(self: Pin<&Self>) -> &str {
|
||||
&self.get_ref().a
|
||||
}
|
||||
|
||||
fn b<'a>(self: Pin<&'a Self>) -> &'a String {
|
||||
fn b(self: Pin<&Self>) -> &String {
|
||||
unsafe { &*(self.b) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let mut test1 = Test::new("test1");
|
||||
let mut test2 = Test::new("test2");
|
||||
let test1 = Test::new("test1");
|
||||
let test2 = Test::new("test2");
|
||||
|
||||
println!("a: {}, b: {}",test1.as_ref().a(), test1.as_ref().b());
|
||||
println!("a: {}, b: {}",test2.as_ref().a(), test2.as_ref().b());
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# Appendix : Translations of the Book
|
||||
|
||||
For resources in languages other than English.
|
||||
|
||||
- [Русский](https://doc.rust-lang.ru/async-book/)
|
||||
- [Français](https://jimskapt.github.io/async-book-fr/)
|
|
@ -34,3 +34,4 @@
|
|||
- [TODO: Asynchronous Design Patterns: Solutions and Suggestions]()
|
||||
- [TODO: Modeling Servers and the Request/Response Pattern]()
|
||||
- [TODO: Managing Shared State]()
|
||||
- [Appendix: Translations of the Book](12_appendix/01_translations.md)
|
||||
|
|
Loading…
Reference in New Issue