Skip to content

Commit

Permalink
fix indent
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Shih authored and Brian Shih committed Feb 26, 2024
1 parent dc9c363 commit 2f44d55
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 38 deletions.
72 changes: 36 additions & 36 deletions mdbook/src/executor/async-await.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ To gain a better intuition for how asynchronous code gets converted into a state
async fn notify_user(user_id: u32) {
let user = async_fetch_user(user_id).await;
if user.group == 1 {
async_send_email(&user).await;
async_send_email(&user).await;
}
}
```
Expand Down Expand Up @@ -72,7 +72,7 @@ Now that we have a state machine, let’s implement the `Future` trait:
```rust
impl Future for NotifyUser {
type Output = ();

fn poll(&mut self, cx: &mut Context) -> Poll<()> {
loop {
match self.state {
Expand All @@ -90,46 +90,46 @@ The `poll` method starts a `loop` because in the case that one of the states isn

Now, let’s look at how each state performs the state transition.

When we initialize `NotifyUser`, its `state` is `State::Unpolled`, which represents the starting state. When we `poll` `NotifyUser` for the first time, it calls `async_fetch_user` to instantiate and store the `fetch_user_fut` state machine.
When we initialize `NotifyUser`, its `state` is `State::Unpolled`, which represents the starting state. When we `poll` `NotifyUser` for the first time, it calls `async_fetch_user` to instantiate and store the `fetch_user_fut` state machine.

It then transitions its `state` to `State::FetchingUser`. Note that this code block doesn’t return `Poll::Pending`. This is because none of the executed code is blocking, so we can go ahead and execute the handle for the next state transition.

```rust
State::Unpolled => {
self.fetch_user_fut = Some(async_fetch_user(self.user_id));
self.state = State::FetchingUser;
self.fetch_user_fut = Some(async_fetch_user(self.user_id));
self.state = State::FetchingUser;
}
```

When we get to the `FetchinUser` state, it `poll`s the `fetch_user_fut` to see if it’s ready. If it’s `Pending`, we return `Poll::Pending`. Otherwise, `NotifyUser` can perform its next state transition. If `self.user.group == 1`, it needs to create and store the `fetch_user_fut` state machine and transition the state to `State::SendingEmail`. Otherwise, it can transition its state to `State::Ready`.

```rust
State::FetchingUser => {
match self.fetch_user_fut.unwrap().poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(user) => {
self.user = Some(user);
if self.user.group == 1 {
self.fetch_user_fut = Some(async_send_email(&self.user));
self.state = State::SendingEmail;
} else {
self.state = State::Ready;
}
}
match self.fetch_user_fut.unwrap().poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(user) => {
self.user = Some(user);
if self.user.group == 1 {
self.fetch_user_fut = Some(async_send_email(&self.user));
self.state = State::SendingEmail;
} else {
self.state = State::Ready;
}
}
}
}
```

If the state is `SendingEmail`, it polls `send_email_fut` to check if it’s ready. If it is, it transitions the state to `State::Ready`. Otherwise, it returns `Poll::Pending`.

```rust
State::SendingEmail => {
match self.send_email_fut.unwrap().poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(()) => {
self.state = State::Ready;
}
match self.send_email_fut.unwrap().poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(()) => {
self.state = State::Ready;
}
}
}
```

Expand Down Expand Up @@ -159,7 +159,7 @@ struct NotifyUser {

impl Future for NotifyUser {
type Output = ();

fn poll(&mut self, cx: &mut Context) -> Poll<()> {
loop {
match self.state {
Expand All @@ -169,25 +169,25 @@ impl Future for NotifyUser {
},
State::FetchingUser => {
match self.fetch_user_fut.unwrap().poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(user) => {
self.user = Some(user);
if self.user.group == 1 {
self.fetch_user_fut = Some(async_send_email(&self.user));
self.state = State::SendingEmail;
} else {
self.state = State::Ready;
}
Poll::Pending => return Poll::Pending,
Poll::Ready(user) => {
self.user = Some(user);
if self.user.group == 1 {
self.fetch_user_fut = Some(async_send_email(&self.user));
self.state = State::SendingEmail;
} else {
self.state = State::Ready;
}
}
}
},
State::SendingEmail => {
match self.send_email_fut.unwrap().poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(()) => {
self.state = State::Ready;
}
match self.send_email_fut.unwrap().poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(()) => {
self.state = State::Ready;
}
}
},
State::Ready => return Poll::Ready(());
}
Expand Down
4 changes: 2 additions & 2 deletions mdbook/src/executor/local_executor.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn run<T>(&self, future: impl Future<Output = T>) -> T {
"There is already an LocalExecutor running on this thread"
);
LOCAL_EX.set(self, || {
let join_handle = self.spawn(async move { future.await });
let join_handle = self.spawn(async move { future.await });
let waker = dummy_waker();
let cx = &mut Context::from_waker(&waker);
pin!(join_handle);
Expand All @@ -76,7 +76,7 @@ Let’s break down `run` line by line. First, `run` makes sure that no other exe
scoped_tls::scoped_thread_local!(static LOCAL_EX: LocalExecutor);
```

Next, it calls `spawn` to create and schedule the task onto the `TaskQueue`.
Next, it calls `spawn` to create and schedule the task onto the `TaskQueue`.

It then loops until the `future` is completed. It’s super important to understand that the `poll` method here doesn’t actually `poll` the user-provided future. It simply `poll`s the `JoinHandle`, which checks if the `COMPLETED` flag on the task’s `state` is set.

Expand Down

0 comments on commit 2f44d55

Please sign in to comment.