diff --git a/astro.config.mjs b/astro.config.mjs index 828e795b5..a64bd08dc 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -141,8 +141,8 @@ export default defineConfig({ { label: "Crates TUI", link: "/tutorials/crates-tui/" }, { label: "Main", link: "/tutorials/crates-tui/main" }, { - label: "crates_io_api Helper", - link: "/tutorials/crates-tui/crates_io_api_helper", + label: "Helper", + link: "/tutorials/crates-tui/crates-io-api-helper", }, { label: "Tui", link: "/tutorials/crates-tui/tui" }, { label: "Errors", link: "/tutorials/crates-tui/errors" }, diff --git a/code/crates-tui-tutorial-app/src/bin/part-helper.rs b/code/crates-tui-tutorial-app/src/bin/part-helper.rs index a98be7312..18e364acb 100644 --- a/code/crates-tui-tutorial-app/src/bin/part-helper.rs +++ b/code/crates-tui-tutorial-app/src/bin/part-helper.rs @@ -108,7 +108,9 @@ async fn fetch_crates_and_metadata( .await // ANCHOR_END: crates_query .map_err(|err| format!("API Client Error: {err:#?}"))?; + // ANCHOR: crates_response let crates = page_result.crates; + // ANCHOR_END: crates_response Ok(crates) } @@ -116,10 +118,10 @@ async fn fetch_crates_and_metadata( /// actions. fn update_state_with_fetched_crates( crates: Vec, - params: &SearchParameters, + search_params: &SearchParameters, ) { // ANCHOR: update_state - let mut app_crates = params.crates.lock().unwrap(); + let mut app_crates = search_params.crates.lock().unwrap(); app_crates.clear(); app_crates.extend(crates); // ANCHOR_END: update_state diff --git a/src/content/docs/tutorials/crates-tui/crates_io_api_helper.md b/src/content/docs/tutorials/crates-tui/crates-io-api-helper.md similarity index 74% rename from src/content/docs/tutorials/crates-tui/crates_io_api_helper.md rename to src/content/docs/tutorials/crates-tui/crates-io-api-helper.md index 38b5eb87b..894900af8 100644 --- a/src/content/docs/tutorials/crates-tui/crates_io_api_helper.md +++ b/src/content/docs/tutorials/crates-tui/crates-io-api-helper.md @@ -1,16 +1,17 @@ --- -title: Crates IO API +title: Crates IO API Helper --- In this tutorial, we are going to use the `crates_io_api` crate's [`AsyncClient`] to retrieve -results from a search query to crates.io. +results from a search query to crates.io, and make a helper module to simplify handling of the +request and response for the purposes of the tutorial. [`AsyncClient`]: https://docs.rs/crates_io_api/latest/crates_io_api/struct.AsyncClient.html#method.new In order to initialize the client, you have to provide an email as the user agent. In the source code of this tutorial, we read this email from the environment variable -`CRATES_TUI_TUTORIAL_APP_MYEMAIL` at run time. +`CRATES_TUI_TUTORIAL_APP_MYEMAIL`. ```rust let email = env!("CRATES_TUI_TUTORIAL_APP_MYEMAIL"); @@ -29,28 +30,33 @@ You can set up a environment variable for the current session by exporting a var export CRATES_TUI_TUTORIAL_APP_MYEMAIL=your-email-address@foo.com ``` -Or just hardcode your email into your working copy. +Or just hardcode your email into your working copy of the source code + +```rust +let email = "your-email-address@foo.com"; +``` ::: -Once you have created a client, you can make a query using the [`crates`] function: +Once you have created a client, you can make a query using the [`AsyncClient::crates`] function: -[`crates`]: https://docs.rs/crates_io_api/latest/crates_io_api/struct.AsyncClient.html#method.crates +[`AsyncClient::crates`]: + https://docs.rs/crates_io_api/latest/crates_io_api/struct.AsyncClient.html#method.crates ```rust {{#include @code/crates-tui-tutorial-app/src/crates_io_api_helper.rs:crates_query}} ``` -This `crates` method takes a [`CratesQuery`] object that you need to construct. +This `crates` method takes a [`CratesQuery`] object that you will need to construct. [`CratesQuery`]: https://docs.rs/crates_io_api/latest/crates_io_api/struct.CratesQuery.html This `CratesQuery` object can be built with the following parameters -- Search query string -- Page number -- Page size -- Sort order +- Search query: `String` +- Page number: `u64` +- Page size: `u64` +- Sort order: `crates_io_api::Sort` To make the code easier to manage, we'll store everything we need to construct a `CratesQuery` in a `SearchParameters` struct: @@ -68,8 +74,10 @@ pub struct SearchParameters { } ``` -A clone of `Arc>>` will be passed into the `async` task within which -it will be populated with the results of the query after it is complete. +You'll notice that we also added a `crates` field to the `SearchParameters`. This `crates` field +will hold a clone of `Arc>>` that will be passed into the `async` +task. Inside this `async` task it will be populated with the results of the query once the query is +completed. You can construct the query using `crates_io_api`'s [`CratesQueryBuilder`]: @@ -80,8 +88,14 @@ You can construct the query using `crates_io_api`'s [`CratesQueryBuilder`]: {{#include @code/crates-tui-tutorial-app/src/bin/part-helper.rs:create_query}} ``` -Once the request is completed, you can update the `Arc>>` with the -response: +```rust +{{#include @code/crates-tui-tutorial-app/src/bin/part-helper.rs:crates_query}} + +{{#include @code/crates-tui-tutorial-app/src/bin/part-helper.rs:crates_response}} +``` + +Once the request is completed, you can clear the existing results and update the +`Arc>>` (i.e. the `search_params.crates` field) with the response: ```rust {{#include @code/crates-tui-tutorial-app/src/bin/part-helper.rs:update_state}} diff --git a/src/content/docs/tutorials/crates-tui/index.md b/src/content/docs/tutorials/crates-tui/index.md index 7f850b867..b5989cef2 100644 --- a/src/content/docs/tutorials/crates-tui/index.md +++ b/src/content/docs/tutorials/crates-tui/index.md @@ -2,8 +2,9 @@ title: Crates TUI --- -In the previous counter app, we had a purely sequential blocking application. There are times when -you may be interested in running IO operations or compute asynchronously. +In the previous counter app, we had a purely sequential blocking application. However, there are +times when you may be interested in running IO operations or computations asynchronously in between +rendering frames. This tutorial will lead you through creating an async TUI app that lists crates from crates.io based on a user search request in an `async` manner. @@ -32,10 +33,6 @@ needed for writing network applications. We recommend you read the Here's an example of all the dependencies in the `Cargo.toml` file required for this tutorial: -```toml -{{#include @code/crates-tui-tutorial-app/Cargo.toml:7:}} -``` - Run the following to setup a new project: ```bash @@ -53,3 +50,9 @@ This is what your folder structure should look like: ``` Let's go through making these files one by one, starting with `main.rs`. + +```rust +{{#include @code/crates-tui-tutorial-app/src/bin/part-helper.rs:crates_query}} + +{{#include @code/crates-tui-tutorial-app/src/bin/part-helper.rs:crates_response}} +``` diff --git a/src/content/docs/tutorials/crates-tui/main.md b/src/content/docs/tutorials/crates-tui/main.md index 836294881..e895960ae 100644 --- a/src/content/docs/tutorials/crates-tui/main.md +++ b/src/content/docs/tutorials/crates-tui/main.md @@ -24,11 +24,15 @@ Sleeping for 5 seconds... $ ``` -:::note[Homework] +:::tip + +Use `time cargo run` to see how long a process takes to run. + +::: -We recommend you experiment with `main` and `tokio` before moving forward. +:::note[Homework] -Hint: use `time cargo run` to see how long a process takes to run. +Experiment with `main` and `tokio` before moving forward. For example, try to predicate what happens if you spawn multiple tokio tasks like so? @@ -40,12 +44,15 @@ In the above example, if you change `#[tokio::main]` to `#[tokio::main(flavor = can you predict what would happen? Run it to confirm. Do you understand why it behaves the way it does? -Now, what happens if you run the following instead? +Now, what happens if you run the following with `#[tokio::main]` instead? ```rust {{#include @code/crates-tui-tutorial-app/src/bin/part-main-tasks-sequential.rs}} ``` +Do you understand the different between creating a future and `await`ing on it later versus spawning +a future and `await`ing on the `JoinHandle` later? + :::