Full Code of google/comprehensive-rust for AI

main 646605edf379 cached
824 files
18.2 MB
4.1M tokens
84 symbols
1 requests
Copy disabled (too large) Download .txt
Showing preview only (16,191K chars total). Download the full file to get everything.
Repository: google/comprehensive-rust
Branch: main
Commit: 646605edf379
Files: 824
Total size: 18.2 MB

Directory structure:
gitextract_wyjk7nt0/

├── .cargo/
│   └── config.toml
├── .github/
│   ├── CODEOWNERS
│   ├── dependabot.yml
│   ├── labeler.yml
│   ├── pandoc/
│   │   ├── README.md
│   │   ├── ja.yaml
│   │   ├── ko.yaml
│   │   ├── zh-CN.yaml
│   │   └── zh-TW.yaml
│   ├── typos.toml
│   └── workflows/
│       ├── apt-get-install/
│       │   └── action.yml
│       ├── build.sh
│       ├── build.yml
│       ├── check-msgid-changes.py
│       ├── check-msgid-changes.yml
│       ├── install-mdbook/
│       │   └── action.yml
│       ├── labeler.yml
│       ├── lint.yml
│       ├── publish.yml
│       └── setup-rust-cache/
│           └── action.yml
├── .gitignore
├── CONTRIBUTING.md
├── Cargo.toml
├── GEMINI.md
├── LICENSE
├── LICENSE-CC-BY
├── README.md
├── STYLE.md
├── TRANSLATIONS.md
├── book.toml
├── dprint.json
├── mdbook-course/
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── bin/
│       │   ├── course-content.rs
│       │   ├── course-schedule.rs
│       │   └── mdbook-course.rs
│       ├── course.rs
│       ├── frontmatter.rs
│       ├── lib.rs
│       ├── markdown.rs
│       ├── replacements.rs
│       └── timing_info.rs
├── mdbook-exerciser/
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── lib.rs
│       └── main.rs
├── po/
│   ├── ar.po
│   ├── bn.po
│   ├── da.po
│   ├── de.po
│   ├── el.po
│   ├── es.po
│   ├── fa.po
│   ├── fr.po
│   ├── id.po
│   ├── it.po
│   ├── ja.po
│   ├── ko.po
│   ├── pl.po
│   ├── pt-BR.po
│   ├── ro.po
│   ├── ru.po
│   ├── tr.po
│   ├── uk.po
│   ├── vi.po
│   ├── zh-CN.po
│   └── zh-TW.po
├── rustfmt.toml
├── src/
│   ├── README.md
│   ├── SUMMARY.md
│   ├── android/
│   │   ├── aidl/
│   │   │   ├── birthday-service.md
│   │   │   ├── birthday_service/
│   │   │   │   ├── Android.bp
│   │   │   │   ├── aidl/
│   │   │   │   │   ├── Android.bp
│   │   │   │   │   └── com/
│   │   │   │   │       └── example/
│   │   │   │   │           └── birthdayservice/
│   │   │   │   │               ├── BirthdayInfo.aidl
│   │   │   │   │               ├── IBirthdayInfoProvider.aidl
│   │   │   │   │               └── IBirthdayService.aidl
│   │   │   │   └── src/
│   │   │   │       ├── client.rs
│   │   │   │       ├── lib.rs
│   │   │   │       └── server.rs
│   │   │   ├── example-service/
│   │   │   │   ├── changing-definition.md
│   │   │   │   ├── changing-implementation.md
│   │   │   │   ├── client.md
│   │   │   │   ├── deploy.md
│   │   │   │   ├── implementation.md
│   │   │   │   ├── interface.md
│   │   │   │   ├── server.md
│   │   │   │   ├── service-bindings.md
│   │   │   │   └── service.md
│   │   │   ├── types/
│   │   │   │   ├── arrays.md
│   │   │   │   ├── file-descriptor.md
│   │   │   │   ├── objects.md
│   │   │   │   ├── parcelables.md
│   │   │   │   └── primitives.md
│   │   │   └── types.md
│   │   ├── aidl.md
│   │   ├── bpfmt.sh
│   │   ├── build-rules/
│   │   │   ├── binary/
│   │   │   │   ├── Android.bp
│   │   │   │   └── src/
│   │   │   │       └── main.rs
│   │   │   ├── binary.md
│   │   │   ├── library/
│   │   │   │   ├── Android.bp
│   │   │   │   └── src/
│   │   │   │       ├── lib.rs
│   │   │   │       └── main.rs
│   │   │   └── library.md
│   │   ├── build-rules.md
│   │   ├── build_all.sh
│   │   ├── interoperability/
│   │   │   ├── cpp/
│   │   │   │   ├── android-build-cpp.md
│   │   │   │   ├── android-build-rust.md
│   │   │   │   ├── android-cpp-genrules.md
│   │   │   │   ├── bridge.md
│   │   │   │   ├── cpp-bridge.md
│   │   │   │   ├── cpp-exception.md
│   │   │   │   ├── generated-cpp.md
│   │   │   │   ├── rust-bridge.md
│   │   │   │   ├── rust-result.md
│   │   │   │   ├── shared-enums.md
│   │   │   │   ├── shared-types.md
│   │   │   │   └── type-mapping.md
│   │   │   ├── cpp.md
│   │   │   ├── java/
│   │   │   │   ├── Android.bp
│   │   │   │   ├── HelloWorld.java
│   │   │   │   └── src/
│   │   │   │       └── lib.rs
│   │   │   ├── java.md
│   │   │   ├── with-c/
│   │   │   │   ├── bindgen/
│   │   │   │   │   ├── Android.bp
│   │   │   │   │   ├── c-library.md
│   │   │   │   │   ├── libbirthday.c
│   │   │   │   │   ├── libbirthday.h
│   │   │   │   │   ├── libbirthday_wrapper.h
│   │   │   │   │   └── main.rs
│   │   │   │   ├── bindgen.md
│   │   │   │   ├── c-library.md
│   │   │   │   ├── hand-written.md
│   │   │   │   ├── run-our-binary.md
│   │   │   │   ├── rust/
│   │   │   │   │   ├── analyze/
│   │   │   │   │   │   ├── Android.bp
│   │   │   │   │   │   └── main.c
│   │   │   │   │   └── libanalyze/
│   │   │   │   │       ├── Android.bp
│   │   │   │   │       ├── analyze.h
│   │   │   │   │       └── analyze.rs
│   │   │   │   ├── rust-library.md
│   │   │   │   └── rust.md
│   │   │   └── with-c.md
│   │   ├── interoperability.md
│   │   ├── logging/
│   │   │   ├── Android.bp
│   │   │   └── src/
│   │   │       └── main.rs
│   │   ├── logging.md
│   │   ├── setup.md
│   │   ├── testing/
│   │   │   ├── Android.bp
│   │   │   ├── Cargo.toml
│   │   │   ├── googletest.md
│   │   │   ├── googletest.rs
│   │   │   ├── mockall.rs
│   │   │   ├── mocking.md
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   └── testing.md
│   ├── android.md
│   ├── bare-metal/
│   │   ├── alloc-example/
│   │   │   ├── .cargo/
│   │   │   │   └── config.toml
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── main.rs
│   │   ├── alloc.md
│   │   ├── android/
│   │   │   └── vmbase.md
│   │   ├── android.md
│   │   ├── aps/
│   │   │   ├── aarch64-rt/
│   │   │   │   └── exceptions.md
│   │   │   ├── aarch64-rt.md
│   │   │   ├── better-uart/
│   │   │   │   ├── bitflags.md
│   │   │   │   ├── driver.md
│   │   │   │   └── registers.md
│   │   │   ├── better-uart.md
│   │   │   ├── entry-point.md
│   │   │   ├── examples/
│   │   │   │   ├── .cargo/
│   │   │   │   │   └── config.toml
│   │   │   │   ├── Cargo.toml
│   │   │   │   ├── Makefile
│   │   │   │   ├── image.ld
│   │   │   │   └── src/
│   │   │   │       ├── asm.rs
│   │   │   │       ├── entry.S
│   │   │   │       ├── exceptions.S
│   │   │   │       ├── exceptions.rs
│   │   │   │       ├── exceptions_rt.rs
│   │   │   │       ├── idmap.S
│   │   │   │       ├── logger.rs
│   │   │   │       ├── main_improved.rs
│   │   │   │       ├── main_logger.rs
│   │   │   │       ├── main_minimal.rs
│   │   │   │       ├── main_psci.rs
│   │   │   │       ├── main_rt.rs
│   │   │   │       ├── main_safemmio.rs
│   │   │   │       ├── pl011.rs
│   │   │   │       ├── pl011_minimal.rs
│   │   │   │       └── pl011_struct.rs
│   │   │   ├── exceptions.md
│   │   │   ├── inline-assembly.md
│   │   │   ├── logging/
│   │   │   │   └── using.md
│   │   │   ├── logging.md
│   │   │   ├── mmio.md
│   │   │   ├── other-projects.md
│   │   │   ├── safemmio/
│   │   │   │   ├── driver.md
│   │   │   │   ├── registers.md
│   │   │   │   └── using.md
│   │   │   ├── uart/
│   │   │   │   ├── traits.md
│   │   │   │   └── using.md
│   │   │   └── uart.md
│   │   ├── aps.md
│   │   ├── microcontrollers/
│   │   │   ├── board-support.md
│   │   │   ├── debugging.md
│   │   │   ├── embedded-hal.md
│   │   │   ├── examples/
│   │   │   │   ├── .cargo/
│   │   │   │   │   └── config.toml
│   │   │   │   ├── Cargo.toml
│   │   │   │   ├── Embed.toml
│   │   │   │   └── src/
│   │   │   │       └── bin/
│   │   │   │           ├── board_support.rs
│   │   │   │           ├── hal.rs
│   │   │   │           ├── interrupts/
│   │   │   │           │   └── mod.rs
│   │   │   │           ├── minimal.rs
│   │   │   │           ├── mmio.rs
│   │   │   │           ├── pac.rs
│   │   │   │           └── typestate.rs
│   │   │   ├── hals.md
│   │   │   ├── mmio.md
│   │   │   ├── other-projects.md
│   │   │   ├── pacs.md
│   │   │   ├── probe-rs.md
│   │   │   └── type-state.md
│   │   ├── microcontrollers.md
│   │   ├── minimal.md
│   │   ├── no_std.md
│   │   ├── useful-crates/
│   │   │   ├── aarch64-paging.md
│   │   │   ├── allocator-example/
│   │   │   │   ├── Cargo.toml
│   │   │   │   └── src/
│   │   │   │       └── main.rs
│   │   │   ├── buddy_system_allocator.md
│   │   │   ├── spin.md
│   │   │   ├── tinyvec.md
│   │   │   ├── zerocopy-example/
│   │   │   │   ├── Cargo.toml
│   │   │   │   └── src/
│   │   │   │       └── main.rs
│   │   │   └── zerocopy.md
│   │   └── useful-crates.md
│   ├── bare-metal.md
│   ├── borrowing/
│   │   ├── Cargo.toml
│   │   ├── borrowck.md
│   │   ├── examples.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── interior-mutability/
│   │   │   ├── cell.md
│   │   │   └── refcell.md
│   │   ├── interior-mutability.md
│   │   ├── shared.md
│   │   └── solution.md
│   ├── borrowing.md
│   ├── cargo/
│   │   ├── code-samples.md
│   │   ├── running-locally.md
│   │   └── rust-ecosystem.md
│   ├── cargo.md
│   ├── chromium/
│   │   ├── adding-third-party-crates/
│   │   │   ├── checking-in.md
│   │   │   ├── configuring-cargo-toml.md
│   │   │   ├── configuring-gnrt-config-toml.md
│   │   │   ├── depending-on-a-crate.md
│   │   │   ├── downloading-crates.md
│   │   │   ├── generating-gn-build-rules.md
│   │   │   ├── keeping-up-to-date.md
│   │   │   ├── resolving-problems/
│   │   │   │   ├── build-scripts-which-generate-code.md
│   │   │   │   └── build-scripts-which-take-arbitrary-actions.md
│   │   │   ├── resolving-problems.md
│   │   │   └── reviews-and-audits.md
│   │   ├── adding-third-party-crates.md
│   │   ├── build-rules/
│   │   │   ├── depending.md
│   │   │   ├── unsafe.md
│   │   │   └── vscode.md
│   │   ├── build-rules.md
│   │   ├── cargo.md
│   │   ├── interoperability-with-cpp/
│   │   │   ├── error-handling-png.md
│   │   │   ├── error-handling-qr.md
│   │   │   ├── error-handling.md
│   │   │   ├── example-bindings.md
│   │   │   ├── limitations-of-cxx.md
│   │   │   └── using-cxx-in-chromium.md
│   │   ├── interoperability-with-cpp.md
│   │   ├── policy.md
│   │   ├── setup.md
│   │   ├── testing/
│   │   │   ├── build-gn.md
│   │   │   ├── chromium-import-macro.md
│   │   │   └── rust-gtest-interop.md
│   │   └── testing.md
│   ├── chromium.md
│   ├── closures/
│   │   ├── capturing.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── solution.md
│   │   ├── syntax.md
│   │   └── traits.md
│   ├── closures.md
│   ├── concurrency/
│   │   ├── async/
│   │   │   ├── async-await.md
│   │   │   ├── futures.md
│   │   │   ├── runtimes/
│   │   │   │   └── tokio.md
│   │   │   ├── runtimes.md
│   │   │   ├── state-machine.md
│   │   │   └── tasks.md
│   │   ├── async-control-flow/
│   │   │   ├── channels.md
│   │   │   ├── join.md
│   │   │   └── select.md
│   │   ├── async-control-flow.md
│   │   ├── async-exercises/
│   │   │   ├── afternoon.md
│   │   │   ├── chat-app.md
│   │   │   ├── chat-async/
│   │   │   │   ├── Cargo.toml
│   │   │   │   └── src/
│   │   │   │       └── bin/
│   │   │   │           ├── client.rs
│   │   │   │           └── server.rs
│   │   │   ├── dining-philosophers.md
│   │   │   ├── dining-philosophers.rs
│   │   │   └── solutions.md
│   │   ├── async-exercises.md
│   │   ├── async-pitfalls/
│   │   │   ├── async-traits.md
│   │   │   ├── blocking-executor.md
│   │   │   ├── cancellation.md
│   │   │   └── pin.md
│   │   ├── async-pitfalls.md
│   │   ├── async.md
│   │   ├── channels/
│   │   │   ├── bounded.md
│   │   │   ├── senders-receivers.md
│   │   │   └── unbounded.md
│   │   ├── channels.md
│   │   ├── send-sync/
│   │   │   ├── examples.md
│   │   │   ├── marker-traits.md
│   │   │   ├── send.md
│   │   │   └── sync.md
│   │   ├── send-sync.md
│   │   ├── shared-state/
│   │   │   ├── arc.md
│   │   │   ├── example.md
│   │   │   └── mutex.md
│   │   ├── shared-state.md
│   │   ├── sync-exercises/
│   │   │   ├── Cargo.toml
│   │   │   ├── dining-philosophers.md
│   │   │   ├── dining-philosophers.rs
│   │   │   ├── link-checker.md
│   │   │   ├── link-checker.rs
│   │   │   └── solutions.md
│   │   ├── sync-exercises.md
│   │   ├── threads/
│   │   │   ├── plain.md
│   │   │   └── scoped.md
│   │   ├── threads.md
│   │   ├── welcome-async.md
│   │   └── welcome.md
│   ├── control-flow-basics/
│   │   ├── Cargo.toml
│   │   ├── blocks-and-scopes.md
│   │   ├── break-continue/
│   │   │   └── labels.md
│   │   ├── break-continue.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── functions.md
│   │   ├── if.md
│   │   ├── loops/
│   │   │   ├── for.md
│   │   │   └── loop.md
│   │   ├── loops.md
│   │   ├── macros.md
│   │   ├── match.md
│   │   └── solution.md
│   ├── control-flow-basics.md
│   ├── credits.md
│   ├── error-handling/
│   │   ├── Cargo.toml
│   │   ├── anyhow.md
│   │   ├── error.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── panics.md
│   │   ├── result.md
│   │   ├── solution.md
│   │   ├── thiserror.md
│   │   ├── try-conversions.md
│   │   └── try.md
│   ├── error-handling.md
│   ├── exercises/
│   │   ├── bare-metal/
│   │   │   ├── afternoon.md
│   │   │   ├── compass/
│   │   │   │   ├── .cargo/
│   │   │   │   │   └── config.toml
│   │   │   │   ├── Cargo.toml
│   │   │   │   ├── Embed.toml
│   │   │   │   └── src/
│   │   │   │       └── main.rs
│   │   │   ├── compass.md
│   │   │   ├── morning.md
│   │   │   ├── rtc/
│   │   │   │   ├── .cargo/
│   │   │   │   │   └── config.toml
│   │   │   │   ├── Cargo.toml
│   │   │   │   ├── Makefile
│   │   │   │   ├── build.rs
│   │   │   │   ├── memory.ld
│   │   │   │   └── src/
│   │   │   │       ├── exceptions.rs
│   │   │   │       ├── logger.rs
│   │   │   │       ├── main.rs
│   │   │   │       └── pl031.rs
│   │   │   ├── rtc.md
│   │   │   ├── solutions-afternoon.md
│   │   │   └── solutions-morning.md
│   │   └── chromium/
│   │       ├── bringing-it-together.md
│   │       ├── build-rules.md
│   │       ├── interoperability-with-cpp.md
│   │       ├── solutions.md
│   │       ├── testing.md
│   │       └── third-party.md
│   ├── generics/
│   │   ├── Cargo.toml
│   │   ├── dyn-trait.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── generic-data.md
│   │   ├── generic-functions.md
│   │   ├── generic-traits.md
│   │   ├── impl-trait.md
│   │   ├── solution.md
│   │   └── trait-bounds.md
│   ├── generics.md
│   ├── glossary.md
│   ├── hello-world/
│   │   ├── benefits.md
│   │   ├── playground.md
│   │   └── what-is-rust.md
│   ├── hello-world.md
│   ├── idiomatic/
│   │   ├── foundations-api-design/
│   │   │   ├── meaningful-doc-comments/
│   │   │   │   ├── anatomy-of-a-doc-comment.md
│   │   │   │   ├── avoid-redundancy.md
│   │   │   │   ├── exercise.md
│   │   │   │   ├── library-vs-application-docs.md
│   │   │   │   ├── name-drop-signpost.md
│   │   │   │   ├── what-isnt-docs.md
│   │   │   │   ├── what-why-not-how-where.md
│   │   │   │   └── who-are-you-writing-for.md
│   │   │   ├── meaningful-doc-comments.md
│   │   │   ├── predictable-api/
│   │   │   │   ├── common-traits/
│   │   │   │   │   ├── clone.md
│   │   │   │   │   ├── copy.md
│   │   │   │   │   ├── debug.md
│   │   │   │   │   ├── display.md
│   │   │   │   │   ├── from-into.md
│   │   │   │   │   ├── hash.md
│   │   │   │   │   ├── partialeq-eq.md
│   │   │   │   │   ├── partialord-ord.md
│   │   │   │   │   ├── serde.md
│   │   │   │   │   └── try-from-into.md
│   │   │   │   ├── common-traits.md
│   │   │   │   ├── naming-conventions/
│   │   │   │   │   ├── as-and-ref.md
│   │   │   │   │   ├── by.md
│   │   │   │   │   ├── exercise.md
│   │   │   │   │   ├── from.md
│   │   │   │   │   ├── get.md
│   │   │   │   │   ├── into.md
│   │   │   │   │   ├── into_inner.md
│   │   │   │   │   ├── is.md
│   │   │   │   │   ├── mut.md
│   │   │   │   │   ├── new.md
│   │   │   │   │   ├── push.md
│   │   │   │   │   ├── raw_parts.md
│   │   │   │   │   ├── to.md
│   │   │   │   │   ├── try.md
│   │   │   │   │   ├── unchecked.md
│   │   │   │   │   ├── with-closure.md
│   │   │   │   │   ├── with-constructor.md
│   │   │   │   │   ├── with-copy-setter.md
│   │   │   │   │   └── with-word.md
│   │   │   │   └── naming-conventions.md
│   │   │   └── predictable-api.md
│   │   ├── foundations-api-design.md
│   │   ├── leveraging-the-type-system/
│   │   │   ├── borrow-checker-invariants/
│   │   │   │   ├── aliasing-xor-mutability.md
│   │   │   │   ├── generalizing-ownership.md
│   │   │   │   ├── phantomdata-01-types.md
│   │   │   │   ├── phantomdata-02-types-implemented.md
│   │   │   │   ├── phantomdata-03-lifetimes.md
│   │   │   │   ├── phantomdata-04-borrowedfd.md
│   │   │   │   └── single-use-values.md
│   │   │   ├── borrow-checker-invariants.md
│   │   │   ├── extension-traits/
│   │   │   │   ├── extending-foreign-types.md
│   │   │   │   ├── extending-other-traits.md
│   │   │   │   ├── method-resolution-conflicts.md
│   │   │   │   ├── should-i-define-an-extension-trait.md
│   │   │   │   └── trait-method-conflicts.md
│   │   │   ├── extension-traits.md
│   │   │   ├── newtype-pattern/
│   │   │   │   ├── is-it-encapsulated.md
│   │   │   │   ├── parse-don-t-validate.md
│   │   │   │   └── semantic-confusion.md
│   │   │   ├── newtype-pattern.md
│   │   │   ├── raii/
│   │   │   │   ├── drop_bomb.md
│   │   │   │   ├── drop_bomb_forget.md
│   │   │   │   ├── drop_guards.md
│   │   │   │   ├── drop_option.md
│   │   │   │   ├── drop_skipped.md
│   │   │   │   ├── forget_and_drop.md
│   │   │   │   ├── mutex.md
│   │   │   │   └── scope_guard.md
│   │   │   ├── raii.md
│   │   │   ├── token-types/
│   │   │   │   ├── branded-01-motivation.md
│   │   │   │   ├── branded-02-phantomdata.md
│   │   │   │   ├── branded-03-impl.md
│   │   │   │   ├── branded-04-in-action.md
│   │   │   │   ├── mutex-guard.md
│   │   │   │   └── permission-tokens.md
│   │   │   ├── token-types.md
│   │   │   ├── typestate-pattern/
│   │   │   │   ├── typestate-advanced.md
│   │   │   │   ├── typestate-example.md
│   │   │   │   ├── typestate-generics/
│   │   │   │   │   ├── complete.md
│   │   │   │   │   ├── property.md
│   │   │   │   │   ├── root.md
│   │   │   │   │   └── struct.md
│   │   │   │   ├── typestate-generics.md
│   │   │   │   └── typestate-generics.rs
│   │   │   └── typestate-pattern.md
│   │   ├── leveraging-the-type-system.md
│   │   ├── polymorphism/
│   │   │   ├── from-oop-to-rust/
│   │   │   │   ├── composition.md
│   │   │   │   ├── dynamic-dispatch/
│   │   │   │   │   ├── any-trait.md
│   │   │   │   │   ├── dyn-compatible.md
│   │   │   │   │   ├── dyn-trait.md
│   │   │   │   │   ├── dyn-vs-generics.md
│   │   │   │   │   ├── heterogeneous.md
│   │   │   │   │   ├── limits.md
│   │   │   │   │   └── pitfalls.md
│   │   │   │   ├── inheritance.md
│   │   │   │   ├── problem-solving.md
│   │   │   │   ├── sealed-traits.md
│   │   │   │   ├── sealing-with-enums.md
│   │   │   │   ├── sticking-with-traits.md
│   │   │   │   ├── supertraits.md
│   │   │   │   ├── switch-perspective.md
│   │   │   │   └── why-no-inheritance.md
│   │   │   ├── from-oop-to-rust.md
│   │   │   ├── refresher/
│   │   │   │   ├── blanket-impls.md
│   │   │   │   ├── conditional-methods.md
│   │   │   │   ├── default-impls.md
│   │   │   │   ├── deriving-traits.md
│   │   │   │   ├── monomorphization.md
│   │   │   │   ├── orphan-rule.md
│   │   │   │   ├── sized.md
│   │   │   │   ├── supertraits.md
│   │   │   │   ├── trait-bounds.md
│   │   │   │   └── traits.md
│   │   │   └── refresher.md
│   │   ├── polymorphism.md
│   │   └── welcome.md
│   ├── index.md
│   ├── iterators/
│   │   ├── Cargo.toml
│   │   ├── collect.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── helpers.md
│   │   ├── intoiterator.md
│   │   ├── iterator.md
│   │   ├── motivation.md
│   │   └── solution.md
│   ├── iterators.md
│   ├── lifetimes/
│   │   ├── Cargo.toml
│   │   ├── borrow-both.md
│   │   ├── borrow-one.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── lifetime-elision.md
│   │   ├── multiple-borrows.md
│   │   ├── returning-borrows.md
│   │   ├── simple-borrows.md
│   │   ├── solution.md
│   │   └── struct-lifetimes.md
│   ├── lifetimes.md
│   ├── memory-management/
│   │   ├── Cargo.toml
│   │   ├── approaches.md
│   │   ├── clone.md
│   │   ├── copy-types.md
│   │   ├── drop.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── move.md
│   │   ├── ownership.md
│   │   ├── review.md
│   │   └── solution.md
│   ├── memory-management.md
│   ├── methods-and-traits/
│   │   ├── Cargo.toml
│   │   ├── deriving.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── methods.md
│   │   ├── solution.md
│   │   ├── traits/
│   │   │   ├── associated-types.md
│   │   │   ├── implementing.md
│   │   │   └── supertraits.md
│   │   └── traits.md
│   ├── methods-and-traits.md
│   ├── modules/
│   │   ├── Cargo.toml
│   │   ├── encapsulation.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── filesystem.md
│   │   ├── modules.md
│   │   ├── paths.md
│   │   ├── solution.md
│   │   └── visibility.md
│   ├── modules.md
│   ├── other-resources.md
│   ├── pattern-matching/
│   │   ├── Cargo.toml
│   │   ├── destructuring-enums.md
│   │   ├── destructuring-structs.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── infallible.md
│   │   ├── let-control-flow/
│   │   │   ├── if-let.md
│   │   │   ├── let-else.md
│   │   │   └── while-let.md
│   │   ├── let-control-flow.md
│   │   ├── match.md
│   │   └── solution.md
│   ├── pattern-matching.md
│   ├── references/
│   │   ├── Cargo.toml
│   │   ├── dangling.md
│   │   ├── exclusive.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── shared.md
│   │   ├── slices.md
│   │   ├── solution.md
│   │   └── strings.md
│   ├── references.md
│   ├── running-the-course/
│   │   ├── course-structure.md
│   │   ├── keyboard-shortcuts.md
│   │   └── translations.md
│   ├── running-the-course.md
│   ├── smart-pointers/
│   │   ├── Cargo.toml
│   │   ├── box.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── rc.md
│   │   ├── solution.md
│   │   └── trait-objects.md
│   ├── smart-pointers.md
│   ├── std-traits/
│   │   ├── Cargo.toml
│   │   ├── casting.md
│   │   ├── comparisons.md
│   │   ├── default.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── from-and-into.md
│   │   ├── operators.md
│   │   ├── read-and-write.md
│   │   └── solution.md
│   ├── std-traits.md
│   ├── std-types/
│   │   ├── Cargo.toml
│   │   ├── docs.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── hashmap.md
│   │   ├── option.md
│   │   ├── result.md
│   │   ├── solution.md
│   │   ├── std.md
│   │   ├── string.md
│   │   └── vec.md
│   ├── std-types.md
│   ├── testing/
│   │   ├── Cargo.toml
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── lints.md
│   │   ├── other.md
│   │   ├── solution.md
│   │   └── unit-tests.md
│   ├── testing.md
│   ├── thanks.md
│   ├── tuples-and-arrays/
│   │   ├── Cargo.toml
│   │   ├── arrays.md
│   │   ├── destructuring.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── iteration.md
│   │   ├── solution.md
│   │   └── tuples.md
│   ├── tuples-and-arrays.md
│   ├── types-and-values/
│   │   ├── Cargo.toml
│   │   ├── arithmetic.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── hello-world.md
│   │   ├── inference.md
│   │   ├── solution.md
│   │   ├── values.md
│   │   └── variables.md
│   ├── types-and-values.md
│   ├── unsafe-deep-dive/
│   │   ├── Cargo.toml
│   │   ├── case-studies/
│   │   │   └── intrusive-linked-list.md
│   │   ├── case-studies.md
│   │   ├── ffi/
│   │   │   ├── README.md
│   │   │   ├── abs.md
│   │   │   ├── c-library-example.md
│   │   │   ├── cpp-library-example.md
│   │   │   ├── language-differences/
│   │   │   │   ├── cpp-and-c.md
│   │   │   │   ├── representations.md
│   │   │   │   ├── rust-and-c.md
│   │   │   │   ├── rust-and-cpp.md
│   │   │   │   └── semantics.md
│   │   │   ├── language-differences.md
│   │   │   ├── language-interop.md
│   │   │   ├── rand.md
│   │   │   ├── strategies.md
│   │   │   └── type-safety.md
│   │   ├── ffi.md
│   │   ├── initialization/
│   │   │   ├── how-to-initialize-memory.md
│   │   │   ├── maybeuninit/
│   │   │   │   ├── arrays.md
│   │   │   │   ├── write-vs-assignment.md
│   │   │   │   └── zeroed-method.md
│   │   │   ├── maybeuninit.md
│   │   │   └── partial-initialization.md
│   │   ├── initialization.md
│   │   ├── introduction/
│   │   │   ├── characteristics-of-unsafe-rust/
│   │   │   │   ├── dangerous.md
│   │   │   │   ├── sometimes-necessary.md
│   │   │   │   └── sometimes-useful.md
│   │   │   ├── characteristics-of-unsafe-rust.md
│   │   │   ├── defining-unsafe-rust.md
│   │   │   ├── definition.md
│   │   │   ├── impact-on-workflow.md
│   │   │   ├── may_overflow.md
│   │   │   ├── purpose.md
│   │   │   ├── responsibility-shift.md
│   │   │   ├── two-roles.md
│   │   │   ├── warm-up/
│   │   │   │   ├── unsafe-block.md
│   │   │   │   ├── unsafe-fn.md
│   │   │   │   ├── unsafe-impl.md
│   │   │   │   └── unsafe-trait.md
│   │   │   └── warm-up.md
│   │   ├── introduction.md
│   │   ├── memory-lifecycle.md
│   │   ├── motivations.md
│   │   ├── pinning/
│   │   │   ├── README.md
│   │   │   ├── definition-of-pin.md
│   │   │   ├── drop-and-not-unpin-worked-example.md
│   │   │   ├── phantompinned.md
│   │   │   ├── pin-and-drop.md
│   │   │   ├── self-referential-buffer/
│   │   │   │   ├── cpp.md
│   │   │   │   ├── rust-offset.md
│   │   │   │   ├── rust-pin.md
│   │   │   │   ├── rust-raw-pointers.md
│   │   │   │   └── rust.md
│   │   │   ├── self-referential-buffer.md
│   │   │   ├── unpin-trait.md
│   │   │   ├── what-a-move-is.md
│   │   │   ├── what-pinning-is.md
│   │   │   └── why-difficult.md
│   │   ├── pinning.md
│   │   ├── rules-of-the-game/
│   │   │   ├── 3-shapes-of-sound-rust.md
│   │   │   ├── copying-memory/
│   │   │   │   ├── crying-wolf.md
│   │   │   │   ├── documented-safety-preconditions.md
│   │   │   │   ├── encapsulated-unsafe.md
│   │   │   │   ├── exposed-unsafe.md
│   │   │   │   └── safe.md
│   │   │   ├── copying-memory.md
│   │   │   ├── rust-is-sound.md
│   │   │   ├── soundness-proof/
│   │   │   │   ├── corollary.md
│   │   │   │   ├── soundness.md
│   │   │   │   └── unsoundness.md
│   │   │   └── soundness-proof.md
│   │   ├── rules-of-the-game.md
│   │   ├── safety-preconditions/
│   │   │   ├── ascii.md
│   │   │   ├── common-preconditions.md
│   │   │   ├── defining.md
│   │   │   ├── determining.md
│   │   │   ├── getter.md
│   │   │   ├── references.md
│   │   │   ├── semantic-preconditions.md
│   │   │   └── u8-to-bool.md
│   │   ├── safety-preconditions.md
│   │   ├── setup.md
│   │   └── welcome.md
│   ├── unsafe-rust/
│   │   ├── Cargo.toml
│   │   ├── dereferencing.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── mutable-static.md
│   │   ├── solution.md
│   │   ├── unions.md
│   │   ├── unsafe-functions/
│   │   │   ├── calling.md
│   │   │   ├── extern-c.md
│   │   │   └── rust.md
│   │   ├── unsafe-functions.md
│   │   ├── unsafe-traits.md
│   │   └── unsafe.md
│   ├── unsafe-rust.md
│   ├── user-defined-types/
│   │   ├── Cargo.toml
│   │   ├── aliases.md
│   │   ├── const.md
│   │   ├── enums.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── named-structs.md
│   │   ├── solution.md
│   │   ├── static.md
│   │   └── tuple-structs.md
│   ├── user-defined-types.md
│   ├── welcome-day-1-afternoon.md
│   ├── welcome-day-1.md
│   ├── welcome-day-2-afternoon.md
│   ├── welcome-day-2.md
│   ├── welcome-day-3-afternoon.md
│   ├── welcome-day-3.md
│   ├── welcome-day-4-afternoon.md
│   └── welcome-day-4.md
├── tests/
│   ├── README.md
│   ├── package.json
│   ├── src/
│   │   ├── generic-page.test.ts
│   │   ├── objects/
│   │   │   ├── playground.ts
│   │   │   └── slide.ts
│   │   ├── playground.test.ts
│   │   ├── redbox.test.ts
│   │   ├── slide-style-guide.test.ts
│   │   ├── slides/
│   │   │   ├── slide-exemptions.list.ts
│   │   │   └── slides.list.ts
│   │   └── speaker-notes.test.ts
│   ├── tsconfig.json
│   ├── wdio.conf-mdbook.ts
│   └── wdio.conf.ts
├── theme/
│   ├── book.js
│   ├── css/
│   │   ├── language-picker.css
│   │   ├── redbox.css
│   │   ├── rtl.css
│   │   ├── speaker-notes.css
│   │   └── svgbob.css
│   ├── head.hbs
│   ├── index.hbs
│   ├── redbox.js
│   ├── save-playgrounds.js
│   └── speaker-notes.js
├── third_party/
│   ├── README.md
│   ├── cxx/
│   │   ├── LICENSE-APACHE
│   │   ├── LICENSE-MIT
│   │   ├── README.md
│   │   ├── blobstore/
│   │   │   ├── Android.bp
│   │   │   ├── BUILD
│   │   │   ├── Cargo.toml
│   │   │   ├── build.rs
│   │   │   ├── include/
│   │   │   │   └── blobstore.h
│   │   │   └── src/
│   │   │       ├── blobstore.cc
│   │   │       └── main.rs
│   │   └── book/
│   │       ├── snippets.cc
│   │       └── snippets.rs
│   └── mdbook/
│       ├── LICENSE
│       └── README.md
└── xtask/
    ├── Cargo.toml
    ├── README.md
    └── src/
        └── main.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .cargo/config.toml
================================================
[alias]
xtask = "run --package xtask --"

[env]
# To provide an anchor to the root of the workspace when working with paths.
# See https://github.com/rust-lang/cargo/issues/3946#issuecomment-973132993
CARGO_WORKSPACE_DIR = { value = "", relative = true }


================================================
FILE: .github/CODEOWNERS
================================================
# Translations
po/ar.po @younies
po/bn.po @mirwasi @sudiptachatterjee
po/da.po @mgeisler @voss @thedataking
po/de.po @ronaldfw @fechu
po/el.po @Mandragorian
po/es.po @deavid @vzz1x2
po/fa.po @DannyRavi @hamidrezakp @moaminsharifi @mehrad77 @javad-jafari
po/fr.po @sakex
po/it.po @detro @nicomazz
po/ja.po @keiichiw @chikoski @kantasv @HidenoriKobayashi
po/ko.po @jiyongp @jooyunghan @namhyung
po/pl.po @jkotur @dyeroshenko
po/pt-BR.po @rastringer @hugojacob @henrif75 @joaovicmendes @azevedoalice
po/ro.po @AlexandraImbrisca @razvanm
po/ru.po @istolga @baltuky @zvonden @dyeroshenko
po/tr.po @alerque @Enes1313 @rexoplans1
po/uk.po @dyeroshenko
po/vi.po @daivinhtran @qu-ngx
po/zh-CN.po @wnghl @anlunx @kongy @noahdragon @superwhd @emmali01 @candysonya @AgainstEntropy
po/zh-TW.po @edong @hueich @kuanhungchen @victorhsieh @mingyc

# Dependency changes (mostly dependabot PRs)
Cargo.toml @djmitche @mgeisler @qwandor
Cargo.lock @djmitche @mgeisler @qwandor
src/bare-metal/alloc-example/Cargo.toml @djmitche @mgeisler @qwandor
src/bare-metal/alloc-example/Cargo.lock @djmitche @mgeisler @qwandor
src/bare-metal/aps/examples/Cargo.toml @djmitche @mgeisler @qwandor
src/bare-metal/aps/examples/Cargo.lock @djmitche @mgeisler @qwandor
src/bare-metal/microcontrollers/examples/Cargo.toml @djmitche @mgeisler @qwandor
src/bare-metal/microcontrollers/examples/Cargo.lock @djmitche @mgeisler @qwandor
src/exercises/bare-metal/compass/Cargo.toml @djmitche @mgeisler @qwandor
src/exercises/bare-metal/compass/Cargo.lock @djmitche @mgeisler @qwandor
src/exercises/bare-metal/rtc/Cargo.toml @djmitche @mgeisler @qwandor
src/exercises/bare-metal/rtc/Cargo.lock @djmitche @mgeisler @qwandor
.github/workflows @djmitche @mgeisler @qwandor


================================================
FILE: .github/dependabot.yml
================================================
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
  - package-ecosystem: cargo
    directory: /
    schedule:
      interval: monthly
    commit-message:
      prefix: cargo
    groups:
      minor:
        update-types:
          - minor
      patch:
        update-types:
          - patch
  - package-ecosystem: cargo
    directory: /src/bare-metal/alloc-example/
    schedule:
      interval: monthly
    commit-message:
      prefix: cargo
    groups:
      minor:
        update-types:
          - minor
      patch:
        update-types:
          - patch
  - package-ecosystem: cargo
    directory: /src/bare-metal/aps/examples/
    schedule:
      interval: monthly
    commit-message:
      prefix: cargo
    groups:
      minor:
        update-types:
          - minor
      patch:
        update-types:
          - patch
  - package-ecosystem: cargo
    directory: /src/bare-metal/microcontrollers/examples/
    schedule:
      interval: monthly
    commit-message:
      prefix: cargo
    groups:
      minor:
        update-types:
          - minor
      patch:
        update-types:
          - patch
  - package-ecosystem: cargo
    directory: /src/exercises/bare-metal/compass/
    schedule:
      interval: monthly
    commit-message:
      prefix: cargo
    groups:
      minor:
        update-types:
          - minor
      patch:
        update-types:
          - patch
  - package-ecosystem: cargo
    directory: /src/exercises/bare-metal/rtc/
    schedule:
      interval: monthly
    commit-message:
      prefix: cargo
    groups:
      minor:
        update-types:
          - minor
      patch:
        update-types:
          - patch
  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: monthly


================================================
FILE: .github/labeler.yml
================================================
translation:
  - changed-files:
      - any-glob-to-any-file: po/*.po

"translation/ar":
  - changed-files:
      - any-glob-to-any-file: po/ar.po

"translation/bn":
  - changed-files:
      - any-glob-to-any-file: po/bn.po

"translation/da":
  - changed-files:
      - any-glob-to-any-file: po/da.po

"translation/de":
  - changed-files:
      - any-glob-to-any-file: po/de.po

"translation/el":
  - changed-files:
      - any-glob-to-any-file: po/el.po

"translation/es":
  - changed-files:
      - any-glob-to-any-file: po/es.po

"translation/fa":
  - changed-files:
      - any-glob-to-any-file: po/fa.po

"translation/fr":
  - changed-files:
      - any-glob-to-any-file: po/fr.po

"translation/id":
  - changed-files:
      - any-glob-to-any-file: po/id.po

"translation/it":
  - changed-files:
      - any-glob-to-any-file: po/it.po

"translation/ja":
  - changed-files:
      - any-glob-to-any-file: po/ja.po

"translation/ko":
  - changed-files:
      - any-glob-to-any-file: po/ko.po

"translation/pl":
  - changed-files:
      - any-glob-to-any-file: po/pl.po

"translation/pt-BR":
  - changed-files:
      - any-glob-to-any-file: po/pt-BR.po

"translation/ro":
  - changed-files:
      - any-glob-to-any-file: po/ro.po

"translation/ru":
  - changed-files:
      - any-glob-to-any-file: po/ru.po

"translation/tr":
  - changed-files:
      - any-glob-to-any-file: po/tr.po

"translation/uk":
  - changed-files:
      - any-glob-to-any-file: po/uk.po

"translation/vi":
  - changed-files:
      - any-glob-to-any-file: po/vi.po

"translation/zh-CN":
  - changed-files:
      - any-glob-to-any-file: po/zh-CN.po

"translation/zh-TW":
  - changed-files:
      - any-glob-to-any-file: po/zh-TW.po


================================================
FILE: .github/pandoc/README.md
================================================
# Config Overrides for `mdbook-pandoc`

The configuration file fragments here are used to override the configuration in
`book.toml`. See `.github/workflows/build.sh` for details.


================================================
FILE: .github/pandoc/ja.yaml
================================================
variables:
  CJKmainfont: "Noto Serif CJK JP"
  CJKsansfont: "Noto Sans CJK JP"
  CJKmonofont: "Noto Sans Mono CJK JP"


================================================
FILE: .github/pandoc/ko.yaml
================================================
variables:
  CJKmainfont: "Noto Serif CJK KR"
  CJKsansfont: "Noto Sans CJK KR"
  CJKmonofont: "Noto Sans Mono CJK KR"


================================================
FILE: .github/pandoc/zh-CN.yaml
================================================
variables:
  CJKmainfont: "Noto Serif CJK SC"
  CJKsansfont: "Noto Sans CJK SC"
  CJKmonofont: "Noto Sans Mono CJK SC"


================================================
FILE: .github/pandoc/zh-TW.yaml
================================================
variables:
  CJKmainfont: "Noto Serif CJK TC"
  CJKsansfont: "Noto Sans CJK TC"
  CJKmonofont: "Noto Sans Mono CJK TC"


================================================
FILE: .github/typos.toml
================================================
[default.extend-identifiers]
# False positives.
mis = "mis"
MIS = "MIS"
inout = "inout"
esource = "esource"
BARs = "BARs"

[type.po]
# Localized content should not be checked for typos. English
# in these files should be validated manually.
extend-glob = ["*.po"]
check-file = false

[files]
# Typos in third party packages should be fixed upstream.
extend-exclude = ["third_party/*", "theme/book.js"]


================================================
FILE: .github/workflows/apt-get-install/action.yml
================================================
name: Setup Apt and Install Packages
description: Configures apt, runs update once per job, and installs packages.

inputs:
  packages:
    description: A space-separated list of packages to install.
    required: true

runs:
  using: composite
  steps:
    - name: Configure dpkg and apt for CI
      shell: bash
      run: |
        # Avoid time-consuming man-db updates.
        sudo tee /etc/dpkg/dpkg.cfg.d/99-no-doc > /dev/null <<EOF
        path-exclude /usr/share/doc/*
        path-exclude /usr/share/man/*
        path-exclude /usr/share/info/*
        EOF

        # Exclude translations.
        sudo tee /etc/apt/apt.conf.d/99-no-translations > /dev/null <<EOF
        Acquire::Languages "none";
        EOF

        # Exclude command-not-found utility.
        sudo rm -f /etc/apt/apt.conf.d/50command-not-found

        # Remove unnecessary repository lists (we don't install Azure
        # utilities)
        sudo rm -f /etc/apt/sources.list.d/microsoft-prod.* /etc/apt/sources.list.d/azure-cli.*

    - name: Run apt-get update
      if: env.APT_UPDATED != 'true'
      shell: bash
      run: |
        sudo apt-get update
        echo "APT_UPDATED=true" >> $GITHUB_ENV

    - name: Installing ${{ inputs.packages }}
      shell: bash
      run: |
        sudo apt-get install --quiet --yes --no-install-recommends ${{ inputs.packages }}


================================================
FILE: .github/workflows/build.sh
================================================
#!/usr/bin/env bash
set -Eeuo pipefail

# Usage: build.sh <book-lang> <dest-dir>
#
# Build the course as of the date specified specified in the
# POT-Creation-Date header of po/$book_lang.po. The output can be
# found in $dest_dir.
#
# The src/ and third_party/ directories are left in a dirty state so
# you can run `mdbook test` and other commands afterwards.
#
# See also TRANSLATIONS.md.

book_lang=${1:?"Usage: $0 <book-lang> <dest-dir>"}
dest_dir=${2:?"Usage: $0 <book-lang> <dest-dir>"}

if [ "$book_lang" = "en" ]; then
    echo "::group::Building English course"
else
    pot_creation_date=$(grep --max-count 1 '^"POT-Creation-Date:' "po/$book_lang.po" | sed -E 's/".*: (.*)\\n"/\1/')
    pot_creation_date=${pot_creation_date:-now}
    echo "::group::Building $book_lang translation as of $pot_creation_date"

    # Back-date the sources to POT-Creation-Date. The content lives in two
    # directories:
    rm -r src/ third_party/
    git restore --source "$(git rev-list -n 1 --before "$pot_creation_date" @)" src/ third_party/ book.toml
    # Set language and adjust site URL. Clear the redirects since they are
    # in sync with the source files, not the translation.
    export MDBOOK_BOOK__LANGUAGE=$book_lang
    export MDBOOK_OUTPUT__HTML__SITE_URL=/comprehensive-rust/$book_lang/
    export MDBOOK_OUTPUT__HTML__REDIRECT='{}'

    # Include language-specific Pandoc configuration
    if [ -f ".github/pandoc/$book_lang.yaml" ]; then
        export MDBOOK_OUTPUT__PANDOC__PROFILE__PDF__DEFAULTS=".github/pandoc/$book_lang.yaml"
    fi
fi

# Enable mdbook-pandoc to build PDF version of the course
export MDBOOK_OUTPUT__PANDOC__DISABLED=false

mdbook build -d "$dest_dir"

mv "$dest_dir/pandoc/pdf/comprehensive-rust.pdf" "$dest_dir/html/"
(cd "$dest_dir/exerciser" && zip --recurse-paths ../html/comprehensive-rust-exercises.zip comprehensive-rust-exercises/)

echo "::endgroup::"


================================================
FILE: .github/workflows/build.yml
================================================
name: Test
permissions:
  contents: read

on:
  pull_request:
  push:
    branches:
      - main
  workflow_dispatch:

env:
  CARGO_TERM_COLOR: always

jobs:
  cargo:
    strategy:
      matrix:
        os:
          - ubuntu-latest
          - macos-latest
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Update Rust
        run: rustup update

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache

      - name: Build Rust code
        run: cargo build

      - name: Test Rust code
        run: cargo test

  bare-metal:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        include:
          - directory: src/bare-metal/alloc-example
            target: aarch64-unknown-none
          - directory: src/bare-metal/aps/examples
            target: aarch64-unknown-none
          - directory: src/bare-metal/microcontrollers/examples
            target: thumbv7em-none-eabihf
          - directory: src/exercises/bare-metal/compass
            target: thumbv7em-none-eabihf
          - directory: src/exercises/bare-metal/rtc
            target: aarch64-unknown-none
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install toolchain
        run: |
          rustup update
          rustup target add ${{ matrix.target }}

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache

      - name: Install dependencies
        uses: ./.github/workflows/apt-get-install
        with:
          packages: gcc-aarch64-linux-gnu

      - name: Build Rust code
        working-directory: ${{ matrix.directory }}
        run: cargo build

  find-languages:
    runs-on: ubuntu-latest
    outputs:
      languages: ${{ steps.find-languages.outputs.languages }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Find languages
        id: find-languages
        shell: python
        run: |
          import os, json, pathlib
          languages = ["en"] + [p.stem for p in pathlib.Path("po").iterdir() if p.suffix == ".po"]
          github_output = open(os.environ["GITHUB_OUTPUT"], "a")
          github_output.write("languages=")
          json.dump(sorted(languages), github_output)

  build:
    runs-on: ubuntu-latest
    needs:
      - find-languages
    strategy:
      matrix:
        language: ${{ fromJSON(needs.find-languages.outputs.languages) }}
      fail-fast: false
    env:
      # Opt-in for checking links in translations - add the language below.
      LINK_CHECKED_LANGUAGES: '["en", "fa"]'
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0 # We need the full history for build.sh below.

      - name: Update Rust
        run: rustup update

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache
        with:
          key: ${{ contains(fromJSON(env.LINK_CHECKED_LANGUAGES), matrix.language) }}

      - name: Install dependencies
        uses: ./.github/workflows/apt-get-install
        with:
          packages: gettext

      - name: Install mdbook
        uses: ./.github/workflows/install-mdbook

      - name: Test format of ${{ matrix.language }} translation
        if: matrix.language != 'en'
        run: msgfmt --statistics -o /dev/null po/${{ matrix.language }}.po

      - name: Test extracting English strings
        if: matrix.language == 'en'
        run: |
          MDBOOK_OUTPUT='{"xgettext": {"pot-file": "messages.pot"}}' mdbook build -d po
          msgfmt -o /dev/null --statistics po/messages.pot

      - name: Build ${{ matrix.language }} translation
        run: |
          .github/workflows/build.sh ${{ matrix.language }} book/comprehensive-rust-${{ matrix.language }}

      # Upload the book now to retain it in case mdbook test fails.
      - name: Upload book
        uses: actions/upload-artifact@v7
        with:
          name: comprehensive-rust-${{ matrix.language }}
          path: book/

      - name: Test code snippets
        env:
          MDBOOK_BOOK__LANGUAGE: ${{ matrix.language }}
        run: mdbook test

  web-tests:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup Node
        uses: actions/setup-node@v6
        with:
          node-version: 22
          cache: "npm"
          cache-dependency-path: "tests/package-lock.json"
      - name: Install test framework
        run: npm install
        working-directory: ./tests
      - name: Download english book
        uses: actions/download-artifact@v8
        with:
          name: comprehensive-rust-en
          path: book/
      - name: Test Javascript
        run: cargo xtask web-tests --dir book/comprehensive-rust-en/html

  po-diff:
    name: Translation diff
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Update Rust
        run: rustup update

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache

      - name: Install mdbook
        uses: ./.github/workflows/install-mdbook

      - name: Copy latest version of translations
        run: cp -r po new-po

      - name: Checkout base version
        run: git checkout ${{ github.event.pull_request.base.sha }}

      - name: Translation diff
        run: i18n-report diff po/ new-po/ > $GITHUB_STEP_SUMMARY


================================================
FILE: .github/workflows/check-msgid-changes.py
================================================
# Copyright 2023 Google LLC
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Find changed msgid fields without a change in POT-Creation-Date.

When following the instructions in
https://github.com/google/comprehensive-rust/blob/main/TRANSLATIONS.md,
one of two things should happen:

- The `msgid` fields change because `msgmerge --update` was used. This
  will also update the POT-Creation-Date field since a new timestamp
  is merged in from the messages.pot file.

- Translations are added or updated. This should not change the
  `msgid` fields: only the `msgstr` fields should change. If the PO
  editor being used inadvertently changes the wrapping of both `msgid`
  and `msgstr` fields, then `dprint fmt` can be used to normalize them
  all.

The code here detects if both of these happen at the same time: if one
or more `msgid` fields changed without a corresponding change to the
POT-Creation-Date field. If this happens, the translator should fix it
by running:

  dprint fmt

Commit and push to the branch again.
"""

import os

# TODO: move the `git reset` from the action code to here. Infact, we
# should be able to determine this with read-only operations.

# TODO: use Git plumbing commands instead of porcelain, see
# https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git.html.
for filename in os.popen("git diff --name-only").read().split():
    if not filename.endswith(".po"):
        continue

    # If POT-Creation-Date has changed, then we assume that the commit
    # is the result of `msgmerge --update`. It is expected that the
    # `msgid` fields change when `msgmerge` is run, so there is
    # nothing to check.
    if "POT-Creation-Date" in os.popen(
            f"git diff --unified=0 {filename}").read():
        print(
            f"Assuming {filename} was changed automatically, skipping msgid check"
        )
        continue

    changed_lines = {
        i + 1
        for i, line in enumerate(
            os.popen(f"git blame {filename}").readlines())
        if line.startswith("00000000")
    }

    # Look for a changed line between `msgid` and `msgstr`.
    saw_msgid = False
    with open(filename, "r") as f:
        line = f.readline()
        line_number = 1

        while line:
            if line.startswith("msgid"):
                saw_msgid = True
            elif line.startswith("msgstr"):
                saw_msgid = False

            if saw_msgid and line_number in changed_lines:
                print(f"Changed msgid in file {filename}:{line_number}!")
                print(
                    "Please read https://github.com/google/comprehensive-rust/blob/main/TRANSLATIONS.md#creating-and-updating-translations."
                )
                exit(1)

            line_number += 1
            line = f.readline()


================================================
FILE: .github/workflows/check-msgid-changes.yml
================================================
name: Prevent unintended msgid changes
permissions:
  contents: read

on:
  pull_request:
    paths:
      - "po/*.po"

jobs:
  check-msgid-changes:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Reset git
        run: git reset origin/main

      - name: Check po file changes
        run: python3 .github/workflows/check-msgid-changes.py


================================================
FILE: .github/workflows/install-mdbook/action.yml
================================================
name: Install mdbook and dependencies

description: Install mdbook with the dependencies we need.

runs:
  using: composite
  steps:
    - name: Ensure cargo-binstall is installed
      uses: cargo-bins/cargo-binstall@main

    - name: Install mdbook
      run: cargo xtask install-tools --binstall
      shell: bash

    - name: Install mdbook-pandoc dependencies
      uses: ./.github/workflows/apt-get-install
      with:
        packages: >
          fonts-noto
          fonts-noto-cjk
          fonts-noto-color-emoji
          fonts-noto-extra
          fonts-symbola
          librsvg2-bin
          texlive
          texlive-fonts-recommended
          texlive-lang-arabic
          texlive-lang-cjk
          texlive-lang-japanese
          texlive-luatex

    - name: Install mdbook-pandoc
      run: |
        curl -LsSf https://github.com/jgm/pandoc/releases/download/3.7.0.1/pandoc-3.7.0.1-linux-amd64.tar.gz | tar zxf -
        echo "$PWD/pandoc-3.7.0.1/bin" >> $GITHUB_PATH
      shell: bash


================================================
FILE: .github/workflows/labeler.yml
================================================
name: "Pull Request Labeler"
on:
  - pull_request_target

jobs:
  triage:
    permissions:
      contents: read
      pull-requests: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/labeler@v6
        with:
          sync-labels: true


================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint
permissions:
  contents: read

on:
  pull_request:
  push:
    branches:
      - main

env:
  CARGO_TERM_COLOR: always

jobs:
  clippy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache

      - name: Clippy
        run: cargo clippy -- -Dwarnings

  format:
    runs-on: ubuntu-latest
    env:
      NIGHTLY_VERSION: nightly-2025-09-01
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install formatting dependencies
        uses: ./.github/workflows/apt-get-install
        with:
          packages: gettext yapf3

      - name: Install pinned nightly for rustfmt
        run: |
          rustup toolchain install --profile minimal "$NIGHTLY_VERSION"
          rustup component add rustfmt --toolchain "$NIGHTLY_VERSION"

      - name: Check formatting
        uses: dprint/check@v2.3

  typos:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Check for typos
        uses: crate-ci/typos@v1.44.0
        with:
          config: ./.github/typos.toml


================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish

# See also TRANSLATIONS.md.

on:
  push:
    branches:
      - main
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

# Allow one concurrent deployment
concurrency:
  group: pages
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always
  # Update the language picker in index.hbs to link new languages.
  LANGUAGES: ar bn da de el es fa fr id it ja ko pl pt-BR ro ru tr uk vi zh-CN zh-TW

jobs:
  publish:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0 # We need the full history for build.sh below.

      - name: Update Rust
        run: rustup update

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache

      - name: Install Gettext
        uses: ./.github/workflows/apt-get-install
        with:
          packages: gettext

      - name: Install mdbook
        uses: ./.github/workflows/install-mdbook

      - name: Build course in English
        run: .github/workflows/build.sh en book

      - name: Build all translations
        run: |
          for po_lang in ${{ env.LANGUAGES }}; do
              .github/workflows/build.sh $po_lang book/$po_lang
              mv book/$po_lang/html book/html/$po_lang
          done

      - name: Build translation report
        run: i18n-report report book/html/translation-report.html po/*.po

      - name: Build synced translation report
        run: |
          cp -r po synced-po
          MDBOOK_OUTPUT='{"xgettext": {"pot-file": "messages.pot", "granularity": 0}}' mdbook build -d synced-po
          for file in synced-po/*.po; do msgmerge --update $file synced-po/messages.pot ; done
          i18n-report report book/html/synced-translation-report.html synced-po/*.po

      - name: Setup Pages
        uses: actions/configure-pages@v5

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v4
        with:
          path: book/html

      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4


================================================
FILE: .github/workflows/setup-rust-cache/action.yml
================================================
name: Setup Rust cache

description: Configure the rust-cache workflow.

inputs:
  key:
    description: Additional caching key
    required: false
    default:

runs:
  using: composite
  steps:
    - name: Setup Rust cache
      uses: Swatinem/rust-cache@v2
      with:
        # Only save the cache on the main branch to avoid PRs filling
        # up the cache.
        save-if: ${{ github.ref == 'refs/heads/main' }}
        # Further, save the cache per key - e.g. language grouping.
        key: ${{ inputs.key }}


================================================
FILE: .gitignore
================================================
# Build artifacts
/book/
target/
*.bin

# Translation artifacts
po/*.mo
po/*.po~

# macOS artifacts
.DS_Store

# Jetbrains IDEs project files
.idea/
.iml
.iws
count.dat

# Nodejs Files (dprint)
node_modules/
package.json
!tests/package.json
pnpm-lock.yaml

# Crowdin Config (Contains API Keys)
crowdin.yml

# Google's Project IDX files and VSCode
.idx/
.vscode/

# Python virtualenv (for mdbook-slide-evaluator local installation)
.venv/

# tests/ framework artifacts
tests/src/slide/slides/slides.list.ts


================================================
FILE: CONTRIBUTING.md
================================================
# How to Contribute

We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.

Make sure you can build the book with `mdbook build`, that `mdbook serve` works,
and that `dprint fmt` formats the code. Please use `cargo xtask install-tools`
to install the necessary dependencies, following the
[instructions in the README].

[instructions in the README]: README.md#building

## Writing Exercises

Each segment ends with an exercise. Exercises are typically structured as an
`exercise.rs` containing the problem and solution. This is referenced from
`exercise.md` and `solution.md`, using `{{#include exercise.rs:anchor_name}}` to
match ANCHOR comments in the `exercise.rs` file. Each segment also has a
`Cargo.toml` file containing a `[[bin]]` or `[lib]` section referring to
`exercise.rs`, and that Cargo package is referenced from the workspace the root
`Cargo.toml`. The result is that `exercise.rs` is built and tested by
`cargo test`.

For segments on day 1, exercises should use `fn main() { .. }` and `dbg!` or
`println!`, with students visually verifying the correct output. On subsequent
days, prefer tests and omit `fn main() { .. }`. However, where tests would be
difficult and visual verification is more natural (such as in the Logger
exercise), using `fn main { .. }` is OK.

Especially for exercises without tests, consider including tests in
`exercise.rs` that do not appear in either `exercise.md` or `solution.md`, as
these can ensure the solution is correct.

## Testing

We test the course material in several ways:

- `mdbook test`: This will test the code samples. Some code samples are marked
  with `ignore` in the Markdown file because the Playground is missing some of
  the crates we use. For this we have
- `cargo test`: This will build and test the Rust code found in our tooling, as
  well as the code samples which cannot be tested using the Playground.
- `npm test`: This will test the functionality of the rendered web pages. See
  the [testing README](tests/README.md) for details.

## Formatting

Please ensure that your files are formatted consistently. We use a few tools for
this:

- [`dprint`] for driving the formatting.
- [`rustfmt`] for formatting Rust code.
- [`yapf`] for formatting Python code.
- [`msgcat`] for formatting PO files.

Run `dprint fmt` to automatically format all files.

**Note:** To make sure you have the correct version of `rustfmt` installed,
please run:

```bash
cargo xtask install-tools
```

This will install the pinned nightly toolchain and add the `rustfmt` component,
so your local formatting will match the CI.

### Linux

Install `dprint` using their
[installation instructions](https://dprint.dev/install/) and install `rustfmt`
via `rustup`.

Install [pandoc 3.7.0.1](https://github.com/jgm/pandoc/releases/tag/3.7.0.1).

On Debian, you can install the other tools using:

```sh
sudo apt install yapf3 gettext texlive texlive-luatex texlive-lang-cjk texlive-lang-arabic librsvg2-bin fonts-noto
```

### MacOS

On MacOS with [Homebrew], you can install the necessary tools with:

```shell
brew install dprint yapf gettext
```

### Windows

On Windows, you can should install [Gettext tools for Windows].

Install `dprint` using their
[installation instructions](https://dprint.dev/install/) and install `rustfmt`
via `rustup`.

> _TODO: fill in how to install `yapf` on Windows._

[`dprint`]: https://dprint.dev/
[`rustfmt`]: https://github.com/rust-lang/rustfmt
[`yapf`]: https://github.com/google/yapf
[`msgcat`]: https://www.gnu.org/software/gettext/manual/html_node/msgcat-Invocation.html
[Homebrew]: https://brew.sh/
[Gettext tools for Windows]: https://github.com/vslavik/gettext-tools-windows/releases

## Contributor License Agreement

Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.

You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.

## Code Reviews

All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.

## Community Guidelines

This project follows
[Google's Open Source Community Guidelines](https://opensource.google/conduct/).


================================================
FILE: Cargo.toml
================================================
[workspace]
# Please keep the workspace members sorted.
members = [
  "mdbook-course",
  "mdbook-exerciser",
  "src/android/testing",
  "src/bare-metal/useful-crates/allocator-example",
  "src/bare-metal/useful-crates/zerocopy-example",
  "src/borrowing",
  "src/concurrency/async-exercises/chat-async",
  "src/concurrency/sync-exercises",
  "src/control-flow-basics",
  "src/error-handling",
  "src/generics",
  "src/iterators",
  "src/lifetimes",
  "src/memory-management",
  "src/methods-and-traits",
  "src/modules",
  "src/pattern-matching",
  "src/references",
  "src/smart-pointers",
  "src/std-traits",
  "src/std-types",
  "src/testing",
  "src/tuples-and-arrays",
  "src/types-and-values",
  "src/unsafe-rust",
  "src/user-defined-types",
  "third_party/cxx/blobstore",
  "xtask",
]
resolver = "2"


================================================
FILE: GEMINI.md
================================================
# Project Overview

This repository contains the source code for Comprehensive Rust, a family of
courses on Rust developed by Google, starting with Rust foundations, and
including deep dives into specialized topics like Android, Chromium, bare-metal
development, and concurrency. The project is a Rust workspace that leverages
`mdbook` to generate a course website.

## Key Technologies

- **Rust:** The primary programming language for the course subject, custom
  tools, and examples.
- **mdbook:** A command-line tool to create books from Markdown files, used for
  generating the course website.
- **Custom mdbook Preprocessors:** `mdbook-course` and `mdbook-exerciser` are
  Rust binaries that extend `mdbook`'s functionality, for example, to extract
  exercise starter code.
- **`cargo xtask`:** A custom binary within the workspace used for project
  automation, simplifying common development tasks.

# Building and Running

The project uses `cargo xtask` for project-specific automation, like builds,
tests, and managing translations.

## Setup

1. **Install Rust:** Follow the instructions on
   [https://rustup.rs/](https://rustup.rs/).
2. **Clone Repository:**
   ```bash
   git clone https://github.com/google/comprehensive-rust/
   cd comprehensive-rust
   ```
3. **Install Project Tools:**
   ```bash
   cargo xtask install-tools
   ```
   This is a necessary first step for working with this repository. It will
   install the correct versions of all tools used by the project.

## Commands

All commands are run using `cargo xtask`. Run `cargo xtask --help` for a full
list of options.

- **Serve the Course Locally:** Starts a web server to view the course content.
  ```bash
  cargo xtask serve [--language <ISO_639_language_code>] [--output <output_directory>]
  ```
  (e.g., `cargo xtask serve -l da` for the Danish translation)

- **Build the Course:** Creates a static version of the course in the `book/`
  directory.
  ```bash
  cargo xtask build [--language <ISO_639_language_code>] [--output <output_directory>]
  ```

- **Run Rust Snippet Tests:** Tests all Rust code snippets included in the
  course material.
  ```bash
  cargo xtask rust-tests
  ```

- **Run Web Driver Tests:** Executes web driver tests located in the `tests/`
  directory.
  ```bash
  cargo xtask web-tests [--dir <book_html_directory>]
  ```

# Development Conventions

- **Project Automation:** `cargo xtask` is the primary interface for common
  development tasks.
- **Course Content:** Markdown files in the `src/` directory, structured
  according to `src/SUMMARY.md`.
- **Code Formatting:** `dprint fmt` is used to format all source files according
  to `rustfmt.toml` and `dprint.json`. Note that you must first install the
  project tools with `cargo xtask install-tools`.
- **Contributions:** Refer to `CONTRIBUTING.md` for guidelines on contributing
  to the project.
- **Style:** Refer to `STYLE.md` for style guidelines. When making changes to
  Markdown files in `src/`, always first read `STYLE.md` and follow its
  conventions.
- **GitHub Actions:** The project uses composite GitHub Actions to simplify CI
  workflows. These actions should be preferred over hand-written commands.
  - **`apt-get-install`:** This action efficiently installs Debian packages. It
    configures `dpkg` and `apt` to skip documentation and translations, and
    ensures that `apt-get update` is run only once per job. This significantly
    speeds up CI runs.
  - **`install-mdbook`:** A composite action to install `mdbook` and its
    dependencies, including `pandoc` and `texlive`.
  - **`setup-rust-cache`:** A composite action that configures the
    `Swatinem/rust-cache` action.

## Developing Exercises

Exercises allow students to practice what they have learned. When adding or
updating exercises, follow these structural conventions:

- **File Structure:**
  - `exercise.md`: Contains the problem description and a code block with
    placeholders.
  - `exercise.rs`: Contains the full solution code, including a license header
    and `ANCHOR` tags to delimit sections.
  - `solution.md`: Includes the full solution code from `exercise.rs`.
  - `Cargo.toml`: Must define a `[[bin]]` target pointing to `exercise.rs` so
    that the solution code is compiled and tested.

- **Content Inclusion:**
  - Use `{{#include exercise.rs:anchor_name}}` in `exercise.md` to show specific
    parts of the code (e.g., setup, main).
  - Use `{{#include exercise.rs:solution}}` in `solution.md` to show the
    solution code _without_ the license header. Ensure `exercise.rs` has a
    `// ANCHOR: solution` line before the first line of the solution. It is
    unnecessary to add a `// ANCHOR_END: solution` line at the bottom of the
    file.

- **Testing:**
  - Run `cargo xtask rust-tests` to ensure the solution code compiles and runs
    correctly.
  - Run `cargo check -p <crate_name>` to verify the specific exercise crate.

## Markdown Conventions

- **Headings:**
  - **H1 (`#`):** Used for the main title of each page. Each slide has exactly
    one title.
  - **H2 (`##`):** Used for major sections. Slides do not use H2 headings to
    save vertical space; more slides are created instead.
  - **H3 (`###`):** Used for sub-sections, but not on slides.

- **Emphasis:**
  - **Bold (`**...**`):** Used to highlight key terms, commands, and for notes
    (e.g., `**Note:**`). The colon (`:`) is included inside the bold text for
    notes.
  - **Italic (`_..._`):** Used for general emphasis, titles of external
    articles, and for terms being defined.

- **Code:**
  - **Inline Code (`` `...` ``):** Used for code snippets, file names, commands,
    type names, and language keywords. Rust fragments are formatted as `rustfmt`
    would.
  - **Code Blocks (`` ```...``` ``):** Fenced code blocks are used for
    multi-line code examples, annotated with a language identifier (e.g.,
    `rust`, `c`, `ignore`).
  - **Interactive Code Blocks:** Rust examples are made interactive with
    `editable`. Examples that fail to compile are marked with `compile_fail` or
    `should_panic`.
  - **Diagrams:** The `bob` language identifier is used in code blocks to
    generate ASCII art diagrams.
  - **Formatting Control:** The `#[rustfmt::skip]` attribute is used to prevent
    `rustfmt` from formatting specific code blocks, though it is used rarely.

- **Lists:**
  - **Bulleted Lists:** Unordered lists are the primary way to lay out key
    points on slides.
  - **Glossary Format:** The glossary uses a specific format with a colon and
    backslash (`:\`) after each term to create a hard line break for visual
    formatting.

- **Other Markdown Elements:**
  - **Block Quotes (`> ...`):** Used sparingly for important notes, warnings, or
    supplementary information to draw attention.
  - **Links:** Both standard (`[text](url)`) and reference-style
    (`[text][label]`) links are used.
  - **Tables:** Markdown tables are used to present structured data.
  - **Horizontal Rules (`---`):** Not used on slides.

- **HTML Tags:**
  - **`<details>`:** Used for collapsible "speaker notes".
  - **`<kbd>`:** Used to denote keyboard keys. Each key in a combination must be
    wrapped in its own tag, e.g., `<kbd>Ctrl</kbd> + <kbd>S</kbd>`.
  - **`<style>`:** Used rarely for targeted custom CSS.
  - **`<img>`:** Used to embed images.

- **Project-Specific Conventions:**
  - **mdbook Includes:** The `{{#include ...}}` helper is used to include
    snippets from other files.
  - **mdbook Segments:** The `{{%segment ...%}}` and `{{%session ...%}}` helpers
    are used for course structuring.
  - **Frontmatter:** Files start with YAML frontmatter (enclosed in `---`) to
    provide metadata.
  - **Doc Comments:** Standard Rust doc comments (`///`, `//!`) are used.
    `/// # Safety` is used to document safety preconditions for `unsafe` code.
  - **Comments:** HTML comments (`<!-- ... -->`) are used for editor/translator
    instructions and content control (e.g., `mdbook-xgettext: skip`).

# Project-Specific Technical Context

This section contains critical, non-obvious technical details about this
project's tooling and environment that an AI assistant needs to know to perform
its tasks correctly.

## `mdbook` Behavior

- **Isolated Code Snippets:** `mdbook` treats each fenced Rust code block (e.g.,
  `` ```rust ... ``` ``) as a separate compilation unit. When analyzing a code
  snippet, treat it as a self-contained program. Do not assume it shares a scope
  or context with other snippets in the same file unless the surrounding text
  explicitly states otherwise.

## Interacting with the `mdbook` Theme

The `mdbook` theme has several interactive elements. Here's how to interact with
them:

- **Sidebar Toggle:** The sidebar can be opened and closed by clicking the
  "hamburger" button in the top-left of the body text. This button has the ID
  `sidebar-toggle`. You can use the following JavaScript to toggle the sidebar:

  ```javascript
  const button = document.getElementById("sidebar-toggle");
  button.click();
  ```

## WebdriverIO Testing

This project uses WebdriverIO for browser-based integration tests. Here are some
key findings about the test environment:

### Test Environments

The `tests/` directory contains two primary configurations:

- `npm test` (runs `wdio.conf.ts`): This is the standard for self-contained
  integration tests. It uses `@wdio/static-server-service` to create a temporary
  web server on port 8080.
- `npm run test-mdbook` (runs `wdio.conf-mdbook.ts`): This is for testing
  against a live `mdbook serve` instance, which typically runs on port 3000.

It is important to use the standard `npm test` command for most test development
to ensure the tests are self-contained.

### Writing Stable Tests

Tests can be flaky if they don't correctly handle the asynchronous nature of the
web browser and the test environment's state management.

- **State Leakage Between Tests:** Despite what the WebdriverIO documentation
  might suggest, `browser.url()` is not always sufficient to guarantee a clean
  slate between tests. Lingering state, such as inline CSS styles applied by
  JavaScript, can leak from one test into the next, causing unexpected failures.
  The most effective solution found for this project is to add
  `await browser.refresh();` to the `beforeEach` hook. This forces a full page
  reload that properly clears the old state.

- **Race Conditions with Dynamic Elements:** Many elements in this project are
  created dynamically by JavaScript after the initial page load. If a test tries
  to access an element immediately after navigation, it may fail because the
  script hasn't finished running and the element doesn't exist in the DOM yet.
  This creates a race condition. To prevent this, always use
  `await element.waitForExist()` to ensure the element is present before trying
  to interact with it or assert its state (e.g., `toBeDisplayed()`).

### Handling Redirects

`mdbook` uses a redirect map defined in `book.toml` under the
`[output.html.redirect]` section. When writing tests, it is crucial to use the
final, non-redirecting URL for navigation. Navigating to a URL that is a
redirect will cause the browser to follow it, but this process can strip URL
query parameters, leading to test failures for features that depend on them.

### Running and Debugging Tests

To run a single test file, use the `--spec` flag with the a string matching the
file name:

```bash
npm test -- --spec redbox
```

To check for flakiness, you can repeat a test multiple times using the
`--repeat` flag:

```bash
npm test -- --spec redbox --repeat 100
```

Use `--mochaOpts.grep` to run a single test within a file:

```bash
npm test -- --spec redbox --mochaOpts.grep "should be hidden by default"
```


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: LICENSE-CC-BY
================================================
Attribution 4.0 International

=======================================================================

Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.

Using Creative Commons Public Licenses

Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.

     Considerations for licensors: Our public licenses are
     intended for use by those authorized to give the public
     permission to use material in ways otherwise restricted by
     copyright and certain other rights. Our licenses are
     irrevocable. Licensors should read and understand the terms
     and conditions of the license they choose before applying it.
     Licensors should also secure all rights necessary before
     applying our licenses so that the public can reuse the
     material as expected. Licensors should clearly mark any
     material not subject to the license. This includes other CC-
     licensed material, or material used under an exception or
     limitation to copyright. More considerations for licensors:
    wiki.creativecommons.org/Considerations_for_licensors

     Considerations for the public: By using one of our public
     licenses, a licensor grants the public permission to use the
     licensed material under specified terms and conditions. If
     the licensor's permission is not necessary for any reason--for
     example, because of any applicable exception or limitation to
     copyright--then that use is not regulated by the license. Our
     licenses grant only permissions under copyright and certain
     other rights that a licensor has authority to grant. Use of
     the licensed material may still be restricted for other
     reasons, including because others have copyright or other
     rights in the material. A licensor may make special requests,
     such as asking that all changes be marked or described.
     Although not required by our licenses, you are encouraged to
     respect those requests where reasonable. More considerations
     for the public:
    wiki.creativecommons.org/Considerations_for_licensees

=======================================================================

Creative Commons Attribution 4.0 International Public License

By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution 4.0 International Public License ("Public License"). To the
extent this Public License may be interpreted as a contract, You are
granted the Licensed Rights in consideration of Your acceptance of
these terms and conditions, and the Licensor grants You such rights in
consideration of benefits the Licensor receives from making the
Licensed Material available under these terms and conditions.


Section 1 -- Definitions.

  a. Adapted Material means material subject to Copyright and Similar
     Rights that is derived from or based upon the Licensed Material
     and in which the Licensed Material is translated, altered,
     arranged, transformed, or otherwise modified in a manner requiring
     permission under the Copyright and Similar Rights held by the
     Licensor. For purposes of this Public License, where the Licensed
     Material is a musical work, performance, or sound recording,
     Adapted Material is always produced where the Licensed Material is
     synched in timed relation with a moving image.

  b. Adapter's License means the license You apply to Your Copyright
     and Similar Rights in Your contributions to Adapted Material in
     accordance with the terms and conditions of this Public License.

  c. Copyright and Similar Rights means copyright and/or similar rights
     closely related to copyright including, without limitation,
     performance, broadcast, sound recording, and Sui Generis Database
     Rights, without regard to how the rights are labeled or
     categorized. For purposes of this Public License, the rights
     specified in Section 2(b)(1)-(2) are not Copyright and Similar
     Rights.

  d. Effective Technological Measures means those measures that, in the
     absence of proper authority, may not be circumvented under laws
     fulfilling obligations under Article 11 of the WIPO Copyright
     Treaty adopted on December 20, 1996, and/or similar international
     agreements.

  e. Exceptions and Limitations means fair use, fair dealing, and/or
     any other exception or limitation to Copyright and Similar Rights
     that applies to Your use of the Licensed Material.

  f. Licensed Material means the artistic or literary work, database,
     or other material to which the Licensor applied this Public
     License.

  g. Licensed Rights means the rights granted to You subject to the
     terms and conditions of this Public License, which are limited to
     all Copyright and Similar Rights that apply to Your use of the
     Licensed Material and that the Licensor has authority to license.

  h. Licensor means the individual(s) or entity(ies) granting rights
     under this Public License.

  i. Share means to provide material to the public by any means or
     process that requires permission under the Licensed Rights, such
     as reproduction, public display, public performance, distribution,
     dissemination, communication, or importation, and to make material
     available to the public including in ways that members of the
     public may access the material from a place and at a time
     individually chosen by them.

  j. Sui Generis Database Rights means rights other than copyright
     resulting from Directive 96/9/EC of the European Parliament and of
     the Council of 11 March 1996 on the legal protection of databases,
     as amended and/or succeeded, as well as other essentially
     equivalent rights anywhere in the world.

  k. You means the individual or entity exercising the Licensed Rights
     under this Public License. Your has a corresponding meaning.


Section 2 -- Scope.

  a. License grant.

       1. Subject to the terms and conditions of this Public License,
          the Licensor hereby grants You a worldwide, royalty-free,
          non-sublicensable, non-exclusive, irrevocable license to
          exercise the Licensed Rights in the Licensed Material to:

            a. reproduce and Share the Licensed Material, in whole or
               in part; and

            b. produce, reproduce, and Share Adapted Material.

       2. Exceptions and Limitations. For the avoidance of doubt, where
          Exceptions and Limitations apply to Your use, this Public
          License does not apply, and You do not need to comply with
          its terms and conditions.

       3. Term. The term of this Public License is specified in Section
          6(a).

       4. Media and formats; technical modifications allowed. The
          Licensor authorizes You to exercise the Licensed Rights in
          all media and formats whether now known or hereafter created,
          and to make technical modifications necessary to do so. The
          Licensor waives and/or agrees not to assert any right or
          authority to forbid You from making technical modifications
          necessary to exercise the Licensed Rights, including
          technical modifications necessary to circumvent Effective
          Technological Measures. For purposes of this Public License,
          simply making modifications authorized by this Section 2(a)
          (4) never produces Adapted Material.

       5. Downstream recipients.

            a. Offer from the Licensor -- Licensed Material. Every
               recipient of the Licensed Material automatically
               receives an offer from the Licensor to exercise the
               Licensed Rights under the terms and conditions of this
               Public License.

            b. No downstream restrictions. You may not offer or impose
               any additional or different terms or conditions on, or
               apply any Effective Technological Measures to, the
               Licensed Material if doing so restricts exercise of the
               Licensed Rights by any recipient of the Licensed
               Material.

       6. No endorsement. Nothing in this Public License constitutes or
          may be construed as permission to assert or imply that You
          are, or that Your use of the Licensed Material is, connected
          with, or sponsored, endorsed, or granted official status by,
          the Licensor or others designated to receive attribution as
          provided in Section 3(a)(1)(A)(i).

  b. Other rights.

       1. Moral rights, such as the right of integrity, are not
          licensed under this Public License, nor are publicity,
          privacy, and/or other similar personality rights; however, to
          the extent possible, the Licensor waives and/or agrees not to
          assert any such rights held by the Licensor to the limited
          extent necessary to allow You to exercise the Licensed
          Rights, but not otherwise.

       2. Patent and trademark rights are not licensed under this
          Public License.

       3. To the extent possible, the Licensor waives any right to
          collect royalties from You for the exercise of the Licensed
          Rights, whether directly or through a collecting society
          under any voluntary or waivable statutory or compulsory
          licensing scheme. In all other cases the Licensor expressly
          reserves any right to collect such royalties.


Section 3 -- License Conditions.

Your exercise of the Licensed Rights is expressly made subject to the
following conditions.

  a. Attribution.

       1. If You Share the Licensed Material (including in modified
          form), You must:

            a. retain the following if it is supplied by the Licensor
               with the Licensed Material:

                 i. identification of the creator(s) of the Licensed
                    Material and any others designated to receive
                    attribution, in any reasonable manner requested by
                    the Licensor (including by pseudonym if
                    designated);

                ii. a copyright notice;

               iii. a notice that refers to this Public License;

                iv. a notice that refers to the disclaimer of
                    warranties;

                 v. a URI or hyperlink to the Licensed Material to the
                    extent reasonably practicable;

            b. indicate if You modified the Licensed Material and
               retain an indication of any previous modifications; and

            c. indicate the Licensed Material is licensed under this
               Public License, and include the text of, or the URI or
               hyperlink to, this Public License.

       2. You may satisfy the conditions in Section 3(a)(1) in any
          reasonable manner based on the medium, means, and context in
          which You Share the Licensed Material. For example, it may be
          reasonable to satisfy the conditions by providing a URI or
          hyperlink to a resource that includes the required
          information.

       3. If requested by the Licensor, You must remove any of the
          information required by Section 3(a)(1)(A) to the extent
          reasonably practicable.

       4. If You Share Adapted Material You produce, the Adapter's
          License You apply must not prevent recipients of the Adapted
          Material from complying with this Public License.


Section 4 -- Sui Generis Database Rights.

Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:

  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
     to extract, reuse, reproduce, and Share all or a substantial
     portion of the contents of the database;

  b. if You include all or a substantial portion of the database
     contents in a database in which You have Sui Generis Database
     Rights, then the database in which You have Sui Generis Database
     Rights (but not its individual contents) is Adapted Material; and

  c. You must comply with the conditions in Section 3(a) if You Share
     all or a substantial portion of the contents of the database.

For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.


Section 5 -- Disclaimer of Warranties and Limitation of Liability.

  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.

  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.

  c. The disclaimer of warranties and limitation of liability provided
     above shall be interpreted in a manner that, to the extent
     possible, most closely approximates an absolute disclaimer and
     waiver of all liability.


Section 6 -- Term and Termination.

  a. This Public License applies for the term of the Copyright and
     Similar Rights licensed here. However, if You fail to comply with
     this Public License, then Your rights under this Public License
     terminate automatically.

  b. Where Your right to use the Licensed Material has terminated under
     Section 6(a), it reinstates:

       1. automatically as of the date the violation is cured, provided
          it is cured within 30 days of Your discovery of the
          violation; or

       2. upon express reinstatement by the Licensor.

     For the avoidance of doubt, this Section 6(b) does not affect any
     right the Licensor may have to seek remedies for Your violations
     of this Public License.

  c. For the avoidance of doubt, the Licensor may also offer the
     Licensed Material under separate terms or conditions or stop
     distributing the Licensed Material at any time; however, doing so
     will not terminate this Public License.

  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
     License.


Section 7 -- Other Terms and Conditions.

  a. The Licensor shall not be bound by any additional or different
     terms or conditions communicated by You unless expressly agreed.

  b. Any arrangements, understandings, or agreements regarding the
     Licensed Material not stated herein are separate from and
     independent of the terms and conditions of this Public License.


Section 8 -- Interpretation.

  a. For the avoidance of doubt, this Public License does not, and
     shall not be interpreted to, reduce, limit, restrict, or impose
     conditions on any use of the Licensed Material that could lawfully
     be made without permission under this Public License.

  b. To the extent possible, if any provision of this Public License is
     deemed unenforceable, it shall be automatically reformed to the
     minimum extent necessary to make it enforceable. If the provision
     cannot be reformed, it shall be severed from this Public License
     without affecting the enforceability of the remaining terms and
     conditions.

  c. No term or condition of this Public License will be waived and no
     failure to comply consented to unless expressly agreed to by the
     Licensor.

  d. Nothing in this Public License constitutes or may be interpreted
     as a limitation upon, or waiver of, any privileges and immunities
     that apply to the Licensor or You, including from the legal
     processes of any jurisdiction or authority.


=======================================================================

Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.

Creative Commons may be contacted at creativecommons.org.



================================================
FILE: README.md
================================================
# Comprehensive Rust 🦀

[![Build workflow](https://img.shields.io/github/actions/workflow/status/google/comprehensive-rust/build.yml?style=flat-square)](https://github.com/google/comprehensive-rust/actions/workflows/build.yml?query=branch%3Amain)
[![GitHub contributors](https://img.shields.io/github/contributors/google/comprehensive-rust?style=flat-square)](https://github.com/google/comprehensive-rust/graphs/contributors)
[![GitHub stars](https://img.shields.io/github/stars/google/comprehensive-rust?style=flat-square)](https://github.com/google/comprehensive-rust/stargazers)

This repository has the source code for Comprehensive Rust 🦀, a multi-day Rust
course developed by the Android team. The course covers all aspects of Rust,
from basic syntax to generics and error handling. It also includes deep dives on
[Android], [Chromium], [bare-metal], and [concurrency].

[Android]: https://google.github.io/comprehensive-rust/android.html
[Chromium]: https://google.github.io/comprehensive-rust/chromium.html
[bare-metal]: https://google.github.io/comprehensive-rust/bare-metal.html
[concurrency]: https://google.github.io/comprehensive-rust/concurrency.html

Read the course at **https://google.github.io/comprehensive-rust/**.

## Course Format and Target Audience

The course is used internally at Google to teach Rust to experienced software
engineers, typically with a background in C++ or Java.

The course is taught in a classroom setting, and we hope it will be useful for
others who want to teach Rust to their team. The course is less ideal for
self-study, since you would miss out on classroom discussions. You would not see
the questions and answers, nor the compiler errors we trigger when going through
the code samples. We hope to improve the self-study experience via
[speaker notes](https://github.com/google/comprehensive-rust/issues/53) and by
[publishing videos](https://github.com/google/comprehensive-rust/issues/52).

## Press

Articles and blog posts from around the web which cover Comprehensive Rust:

- 2023-09-08:
  _[Teaching Rust in 5 days](https://mo8it.com/blog/teaching-rust/)_.
  Comprehensive Rust was used as a base for a 5-day university class on Rust.
- 2023-09-21:
  _[Scaling Rust Adoption Through Training](https://security.googleblog.com/2023/09/scaling-rust-adoption-through-training.html)_.
  We published a blog post with details on the development of the course.
- 2023-10-02:
  _[In Search of Rust Developers, Companies Turn to In-House Training](https://www.darkreading.com/application-security/seeking-rust-developers-in-house-training)_.
  About how Microsoft, Google, and others are training people in Rust.
- 2024-10-18:
  _[Rust Training at Scale | Rust Global @ RustConf 2024](https://youtu.be/7h5KyMqt2-Q?si=4M99HdWWxMaqN8Zr)_.
  What Google learned from teaching Comprehensive Rust for more than two years.

## Setup

The course is built using a few tools:

- [mdbook](https://github.com/rust-lang/mdBook)
- [mdbook-svgbob](https://github.com/boozook/mdbook-svgbob)
- [mdbook-i18n-helpers and i18n-report](https://github.com/google/mdbook-i18n-helpers)
- [mdbook-exerciser](mdbook-exerciser/)
- [mdbook-course](mdbook-course/)
- [mdbook-linkcheck2](https://github.com/marxin/mdbook-linkcheck2)

First, install Rust by following the instructions on https://rustup.rs/. Then
clone this repository:

```shell
git clone https://github.com/google/comprehensive-rust/
cd comprehensive-rust
```

Then run the following command to install the correct versions of all tools
mentioned above:

```shell
cargo xtask install-tools
```

This uses `cargo install` to install the tools, so you will find them in your
`~/.cargo/bin/` directory afterwards.

## Commands

Here are some of the commonly used commands you can run in the project. Run
`cargo xtask` to view all available commands.

| Command                     | Description                                                                                                                                                                                                                                                                                                                                                                                                                            |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cargo xtask install-tools` | Install all the tools the project depends on.                                                                                                                                                                                                                                                                                                                                                                                          |
| `cargo xtask serve`         | Start a web server with the course. You'll find the content on http://localhost:3000. To serve any of the translated versions of the course, add the language flag (--language or -l) followed by xx, where xx is the ISO 639 language code (e.g. cargo xtask serve -l da for the Danish translation).                                                                                                                                 |
| `cargo xtask rust-tests`    | Test the included Rust snippets.                                                                                                                                                                                                                                                                                                                                                                                                       |
| `cargo xtask web-tests`     | Run the web driver tests in the tests directory.                                                                                                                                                                                                                                                                                                                                                                                       |
| `cargo xtask build`         | Create a static version of the course in the `book/` directory. Note that you have to separately build and zip exercises and add them to book/html. To build any of the translated versions of the course, add the language flag (--language or -l) followed by xx, where xx is the ISO 639 language code (e.g. cargo xtask build -l da for the Danish translation). [TRANSLATIONS.md](TRANSLATIONS.md) contains further instructions. |

> **Note** On Windows, you need to enable symlinks
> (`git config --global core.symlinks true`) and Developer Mode.

## Contributing

We welcome contributions. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for
details.

## License

This project is licensed under a mix of the Apache License 2.0 and the Creative
Commons Attribution 4.0 International License.

- **Source Code:** All source code files and code examples embedded in the
  documentation are licensed under the [Apache License, Version 2.0](LICENSE).

- **Documentation & Content:** All non-source code assets—specifically Markdown
  (`.md`) files, documentation, and images—are licensed under the
  [Creative Commons Attribution 4.0 International License](LICENSE-CC-BY).

## Contact

For questions or comments, please contact
[Martin Geisler](mailto:mgeisler@google.com) or start a
[discussion on GitHub](https://github.com/google/comprehensive-rust/discussions).
We would love to hear from you.


================================================
FILE: STYLE.md
================================================
# Comprehensive Rust 🦀 Style Guide

The course has been expanded and improved by tons of volunteers like you! Thank
you for that! To help ensure a consistent style throughout the course, we have
written down some guidelines for you to follow.

## Course Philosophy and Design

To contribute effectively, it's helpful to understand the core design principles
of Comprehensive Rust. This is not a self-study book; it is a set of slides and
notes for an **instructor-led course**.

### Target Audience

The course is designed for an audience of experienced software engineers who are
new to Rust. We assume they have 2-3 years of experience in an imperative
language like C, C++11+, Java 7+, Python, or Go.

We **do not** assume familiarity with functional programming concepts or
features from more modern languages like Swift or Kotlin. Course material should
build upon the concepts that are likely to be familiar to this audience.

### Goals

The goal of the course is to provide a solid foundation in Rust within a bounded
time frame. This prepares students to continue learning effectively as they
begin to apply their new skills on the job.

### Pedagogical Principles

We follow a few key principles to make the material effective for learning:

- **Build on a Foundation:** New Rust concepts should be connected to what a
  learner already knows, either from their prior language experience or from
  earlier parts of this course.
- **Provide a Working Mental Model (The "No Magic" Rule):** As much as possible,
  avoid telling students to accept syntax or behavior that will be explained
  later. For everything that appears on the slides or in exercises, we must
  provide a working mental model that allows the student to understand and use
  the concept.
- **Use a [Spiral Approach](https://en.wikipedia.org/wiki/Spiral_approach):** To
  avoid overwhelming the learner, it is highly encouraged to introduce a concept
  by first providing basic facts and a simplified mental model. The topic can
  then be revisited later to provide more detail. For example, very early in the
  course we explain the basics of `println!`, mention that it is a macro so the
  usage syntax is a bit unusual, but we don't go into details of format strings
  or macros. We explain details of format strings later, once we have covered
  traits and can mention the `Debug` and `Display` traits.
- **Live, Interactive Instruction:** The instructor is expected to run and
  modify the code on the slides, and use compiler errors as a teaching tool. The
  audience is expected to frequently interrupt with questions, and the
  instructor would often experiment with the code on the slide to illustrate the
  answer.

### Pacing and Structure

The course is designed for approximately 5 hours of teaching per day, typically
split into a 3-hour morning session and a 2-hour afternoon session.

This pacing is important context for contributors. Material should be structured
to fit this rhythm, with clear sections that can be taught in roughly 45-50
minute blocks to accommodate short breaks and Q&A.

Each slide must include a `minutes` field in its frontmatter, which specifies
the estimated teaching time for that slide. This helps ensure the overall pacing
of the course remains consistent.

### Course Structure

The course starts with a core **Rust Fundamentals** curriculum, followed by a
collection of specialized **deep dives**. All students take the Fundamentals
course and can then opt into any deep dives that are relevant to them.

#### The Rust Fundamentals Course

The **Rust Fundamentals** course provides a solid foundation in a strictly
bounded, four-day time frame. This duration is firm, and its scope is carefully
managed to focus on the most essential concepts for new Rust programmers.

The overall progression of the course starts with the parts of the Rust language
that should be conceptually familiar to most students from other languages. Then
we move on to more difficult parts (for example, enums with payloads and
generics), and parts that are unique to Rust (lifetimes and the borrow checker).

Contributors should keep this structure in mind. The four-day schedule for the
Fundamentals course is completely full, leaving no time slack for new topics.
Proposals to add material to the Rust Fundamentals course must also include a
plan to shorten or remove existing content. Refinements to existing topics are
always welcome. Topics that are not essential for all new Rust programmers
should be proposed as new deep dives.

#### Deep Dives

Specialized material can be added to _deep dives_. These cover things like Rust
in Android, Bare-Metal Rust, etc., which are not necessarily something every
Rust developer should know. More deep dives can be added in the future.

## Course Slides

Please take the following into account when updating the course material.

### Vertical Space

What looks like pages in a browser, are actually slides in a presentation. It is
important to keep this in mind when adding content: we only have limited
vertical space. Scrolling up and down should be avoided since it is very jarring
for people who attend the class.

You can test the amount of space available using a simple tool. This tool can be
used by clicking a toggle button next to the search button on left side of the
navbar.

The rectangle has an aspect ratio similar to what you can see when you share
your screen on a 16:9 display or projector.

Use the rectangle as a rough guide for how much you can fit on a single slide.
If you find yourself adding too much detail, move the details to the speaker
notes (see below).

### One Core Idea Per Slide

Ideally, each slide should focus on a single, clear takeaway. If a slide
introduces a core concept and then explores an important but distinct tangent
(e.g., a limitation or an advanced use case), that tangent should be moved to
its own slide. This keeps the presentation focused and easier to follow.

Consider the instructor's workflow. If the speaker notes require a long or
complex series of live edits, it can be difficult for the instructor to execute
well every time. It may be better to add a new slide that presents the desired
state of the code.

### Pedagogical Flow

When introducing a new concept, start with a simple, relatable, and concrete
example. A good opening example grounds the concept for the learner and provides
motivation for the more detailed explanation that will follow.

### Use Meaningful Examples

Code samples on the slides should be short and do something meaningful. Avoid
using generic placeholders like `Foo`, `Bar`, and `Baz`. Using descriptive names
from a real-world, even if simplified, domain makes the code easier to
understand and relate to.

### Plan Interactive Code Snippets

All Rust code blocks in the course are not static text but are live, editable
playgrounds. An important teaching method is for the instructor to edit these
snippets live to demonstrate concepts, introduce and fix errors, and explore
variations based on student questions.

Contributors should design their slides with this interactivity in mind. The
initial state of the code should be a good starting point for a live
demonstration.

### `mdbook` and `mdbook-course` Conventions

The project uses `mdbook` features in specific ways, as well as a custom
preprocessor, `mdbook-course`. The following conventions are mandatory:

- **YAML Frontmatter:** Every slide file **must** include YAML frontmatter at
  the top. At a minimum, this must include the `minutes` field to specify the
  estimated teaching time.
- **Outline Helpers:** Pages that serve as an index for a session or segment
  **must** use the `{{%session outline%}}` or `{{%segment outline%}}` helpers.
- **File Includes:** Code for exercises and their solutions **must** be included
  from external files using the standard `mdbook` `{{#include ...}}` helper.
- **Translation Directives:** To prevent an element (such as a paragraph, code
  block, or list item) from being translated, place a
  `<!-- mdbook-xgettext: skip -->` comment on a line by itself, followed by a
  blank line, immediately before the element.

For a complete explanation of the custom helpers and all available frontmatter
fields, please refer to the [`mdbook-course` README](mdbook-course/README.md).

### Language and Tone

The courses are written in American English, so write "initialize", not
"initialise".

Use an informal, friendly, and concise tone. Remember that the courses are meant
to be taught by an experienced programmer to other experienced programmers. When
possible, prefer terminology used in
[the official Rust Book](https://doc.rust-lang.org/book/). If a less common but
necessary term is used, provide a brief definition.

#### Glossary

The `src/glossary.md` file contains definitions for key Rust terms used
throughout the course. When editing course content, use the glossary to anchor
concepts and ensure consistency in terminology. Terms should be defined and used
consistently with their glossary entries.

### Precision

Avoid ["weasel words"](https://en.wikipedia.org/wiki/Weasel_word) (e.g.,
"likely", "probably", "maybe", "usually") when a definite statement can be made.
The course material should be clear, concise, and authoritative. If a behavior
is conditional, explain the condition precisely rather than hedging.

When describing conventions or standard behavior, prefer "typically" (implies a
norm or design characteristic) over "usually" (implies statistical frequency).

## Exercises

At the end of some sections, learners will actively engage with the material by
completing a small exercise. The goal of an exercise is to provide hands-on
practice with the concepts just taught.

Please keep the following principles in mind when creating or updating
exercises:

- **Focused Scope:** An exercise should focus on the topic of the preceding
  section. It should not require knowledge of concepts that have not yet been
  taught.
- **Short Duration:** An exercise should be solvable by the target audience in
  approximately 10-15 minutes. The goal is a quick, successful application of
  knowledge, not a complex project.
- **Clear Instructions:** The problem description should be clear and
  unambiguous.

## Speaker Notes

We have extended `mdbook` with support for speaker notes: content added between
`<details> ... </details>` tags is rendered in a special box that can be
collapsed or removed entirely from the slide.

- Speaker notes suggest a narrative structure for the instructor.

- The speaker notes should expand on the topic of the slide. Use them to provide
  interesting background information for both the instructor and for students
  who look at the material outside of a class. Remember that many more people
  will read the course by themselves, so make the notes complete and useful even
  when there is no Rust expert around.

- For slides with evolving code examples, the notes provide a clear,
  step-by-step flow for how the code is modified and presented. This is a
  suggested flow for the instructor's live-coding session within the slide's
  interactive playground. This includes:

  - The order in which to introduce concepts, how to motivate them.

  - Framing of the code example: the problem it tries to solve, if not obvious.

  - How to demonstrate variations of the code example (e.g., code that does not
    compile or illustrates a bug).

  - How to change the code on the slide to illustrate the concepts being taught.

  - Where to pause and engage the class with questions.

- Speaker notes should serve as a quick reference for instructors, not a
  verbatim script. Because instructors have limited time to glance at notes, the
  content should be concise and easy to scan.

  **Avoid** long, narrative paragraphs meant to be read aloud:
  > **Bad:** _"In this example, we define a trait named `StrExt`. This trait has
  > a single method, `is_palindrome`, which takes a `&self` receiver and returns
  > a boolean value indicating if the string is the same forwards and
  > backwards..."_

  **Instead, prefer** bullet points with background information or actionable
  **teaching prompts**:
  > **Good:**
  >
  > - Note: The `Ext` suffix is a common convention.
  > - Ask: What happens if the `use` statement is removed?
  > - Demo: Comment out the `use` statement to show the compiler error.

- Nevertheless, include all of the necessary teaching prompts for the instructor
  in the speaker notes. Unlike the main content, the speaker notes don't have to
  fit on a single slide.

### More to Explore

Use the "More to Explore" section for valuable topics that are outside the main
scope of the class. The content should be placed within the `<details>` block as
shown below:

```markdown
<details>

...

## More to Explore

...

</details>
```

This section can contain a deeper explanation of a concept or provide specific
pointers to external resources. A link should be accompanied by a brief
explanation of what the resource contains and why it is relevant. A vague
reference is not helpful, but a specific one can be a great tool for
self-learners.

## Code Blocks Mechanics

Code blocks are a critical part of the course. To ensure they are consistent and
behave as expected, please follow these conventions.

### Language Identifiers

Use the following language identifiers for fenced code blocks:

- **`rust`**: For Rust code examples.
- **`shell`**: For shell commands. Use a `$` prompt for consistency. Omit the
  prompt for multi-line commands or when the output is shown.
- **`bob`**: For ASCII art diagrams generated by `mdbook-bob`.
- **`ignore`**: For code snippets that are not complete, self-contained programs
  or are for illustrative purposes only and should not be compiled.

### mdbook Annotations

You can add annotations to Rust code blocks to control how they are tested and
displayed:

- **`editable`**: Makes the code block an interactive playground where users can
  edit and run the code. This should be used for most Rust examples.
- **`compile_fail`**: Indicates that the code is expected to fail compilation.
  This is used to demonstrate specific compiler errors.
- **`should_panic`**: Indicates that the code is expected to panic when run.
- **`warnunused`**: Re-enables `unused` lints for a code block. By default, the
  course's test runner disables lints for unused variables, imports, etc., to
  avoid distracting warnings. Use this annotation only when a warning is part of
  the lesson.

### Rust Code Formatting

When showing Rust code inline, please use the same spacing as `rustfmt`: `3 * x`
instead of `3*x`. However, feel free to remove newlines when it can make the
code more compact and easier to understand, e.g., you can define a struct on one
line if it is not the focus of your example:

<!-- dprint-ignore-start -->

```rust
struct Person { name: String }
```

<!-- dprint-ignore-end -->

Enclose the code block in `<!-- dprint-ignore-start -->` and
`<!-- dprint-ignore-end -->` to suppress the automatic formatting. Please use
this sparingly.

## Translations

This section is about what you write in the translation. We describe
[how to create or update translations elsewhere](TRANSLATIONS.md).

When translating the course, please take the following into account:

- Do not translate:
  - The course name ("Comprehensive Rust 🦀"). If the name is not easily
    understood in your language, please add the translated version after the
    original name.
  - Variable names (you _should_ translate the comments, though.)

- If the Rust Book has been
  [translated into your language](https://doc.rust-lang.org/book/appendix-06-translation.html),
  please use the same vocabulary.

- The text you write is in Markdown format. Make sure to preserve the original
  formatting in the translation by marking text as `` `code` ``, `_emphasis_`
  and `**strong emphasis**` like in the original.

- If you find mistakes or things that sound awkward in the original English
  text, please submit PRs to fix them in the English text! Fixing typos in the
  translation is great, but we want everybody to benefit from the fixes and that
  is why we need the fix to be made in the English text too.

## Licensing and Copyright

To comply with our licensing requirements, all content must include appropriate
copyright and license headers.

### Markdown Files

All Markdown files (`src/**/*.md`) must start with a copyright notice and an
SPDX identifier for the Creative Commons Attribution 4.0 International License
(CC-BY-4.0).

This block should be placed after the YAML frontmatter (if present), separated
by a blank line, or at the very top of the file. It must be enclosed in an HTML
comment block to hide it from the rendered output.

Example:

```markdown
---
minutes: 10
---

<!--
Copyright 2024 Google LLC
SPDX-License-Identifier: CC-BY-4.0
-->

# [ ...Slide title... ]

[ ...The rest of slide content... ]
```

The year should be the year the file was created.

### Embedded Rust Code

All Rust code blocks in Markdown files must include a copyright notice and an
SPDX identifier for the Apache License, Version 2.0.

These lines must be prefixed with `#` so they are hidden in the rendered slides
to save vertical space but remain inside the fenced code block to make the
association clear.

Use a `#` on the blank line following the header to ensure the vertical spacing
is also hidden in the rendered output.

Example:

````markdown
```rust
# // Copyright 2024 Google LLC
# // SPDX-License-Identifier: Apache-2.0
#
fn main() {
    println!("Hello, world!");
}
```
````


================================================
FILE: TRANSLATIONS.md
================================================
# Translations of Comprehensive Rust 🦀

We would love to have your help with translating the course into other
languages! Please see the [translations page] for the existing translations.

[translations page]: https://google.github.io/comprehensive-rust/running-the-course/translations.html

We use the [Gettext] system for translations. This means that you don't modify
the Markdown files directly: instead you modify `.po` files in a `po/`
directory. The `.po` files are small text-based translation databases.

> **Tip:** You should not edit the `.po` files by hand. Instead use a PO editor,
> such as [Poedit](https://poedit.net/). There are also several online editors
> available. This will ensure that the file is encoded correctly.

> **Important:** You need to run `dprint fmt` after editing the PO file. This
> ensures consistent formatting of the file. You need to install the Gettext
> tools for this, see the Preparation section below.

There is a `.po` file for each language. They are named after the [ISO 639]
language codes: Danish would go into `po/da.po`, Korean would go into
`po/ko.po`, etc. The `.po` files contain all the English text plus the
translations. They are initialized from a `messages.pot` file (a PO template)
which contains only the English text.

We will show how to update and manipulate the `.po` and `.pot` files using the
GNU Gettext utilities below.

[Gettext]: https://www.gnu.org/software/gettext/manual/html_node/index.html
[ISO 639]: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes

## Preparation

Please make sure you can [build the course](README.md#building). You will also
need the `msgmerge` and `msgcat` Gettext tool installed. Please see our
[contribution guide](CONTRIBUTING.md#formatting) for details.

## Creating and Updating Translations

First, you need to know how to update the `.pot` and `.po` files.

You should never touch the auto-generated `book/xgettext/messages.pot` file. You
should also never edit the `msgid` entries in a `po/xx.po` file. If you find
mistakes, you need to update the original English text instead. The fixes to the
English text will flow into the `.po` files the next time the translators update
them.

> **Tip:** See our [style guide](STYLE.md) for some things to keep in mind when
> writing the translation.

### Generating the PO Template

To extract the original English text and generate a `messages.pot` file, you
build the book. This will automatically invoke the `mdbook-xgettext` renderer:

```shell
mdbook build
```

You will find the generated POT file as `book/xgettext/messages.pot`.

### Initialize a New Translation

To start a new translation, first generate the `book/xgettext/messages.pot`
file. Then use `msginit` to create a `xx.po` file for the fictional `xx`
language:

```shell
msginit -i book/xgettext/messages.pot -l xx -o po/xx.po
```

You can also simply copy `book/xgettext/messages.pot` to `po/xx.po`. Then update
the file header (the first entry with `msgid ""`) to the correct language.

> **Tip:** You can use the
> [`cloud-translate`](https://github.com/mgeisler/cloud-translate) tool to
> quickly machine-translate a new translation. Install it with
>
> ```shell
> cargo install cloud-translate
> ```
>
> Untranslated entries will be sent through GCP Cloud Translate. Some of the
> translations will be wrong after this, so you must inspect them by hand
> afterwards.

Next, please update the file `.github/labeler.yml` to include the new language:

```diff
+"translation/xx":
+  - changed-files:
+      - any-glob-to-any-file: po/xx.po
```

### Refreshing an Existing Translation

As the English text changes, translations gradually become outdated. The
translations contain a POT-Creation-Date header which tells you when they were
last updated with new English messages.

To update the `po/xx.po` file with new messages, first extract the English text
into a `book/xgettext/messages.pot` template file. Then run

```shell
msgmerge --update po/xx.po book/xgettext/messages.pot
```

Notice that the POT-Creation-Date field is updated to the current time and date.
This becomes the new baseline for the translation: new English text added
afterwards will not show up in your translation, including completely new pages.

When running `msgmerge`, unchanged messages stay intact, deleted messages are
marked as old, and updated messages are marked "fuzzy". A fuzzy entry is not
used when we publish a translation! You have to go over the fuzzy entries by
hand and verify that the translation is correct the fuzzy marker.

> **Note:** Your PRs should either be the result of running `msgmerge` or the
> result of new translation work on the PO file for your language. Avoid mixing
> the two since it often creates a very large diff, which is hard or impossible
> to review.

### Editing a Translation

You should install a PO editor to edit the `.po` file for your language. The
files are simple text files, but it helps to use a dedicated editor since it
will take care of escaping things like `"` correctly.

There are many PO editors available. [Poedit](https://poedit.net/) is a popular
cross-platform choice, but you can also find several online editors.

### Formatting a Translation

If the file is not formatted correct, you will get an error on the PR. Make sure
to follow the [steps](#preparation) to install [Gettext] and
[`dprint`](https://dprint.dev/) and then run:

```shell
dprint fmt po/xx.po
```

This will automatically format the `.po` file for you. Commit the formatting fix
and push to your branch. Your PR should now be error free.

## Using Translations

This will show you how to use the translations to generate localized HTML
output.

> **Note:** `mdbook` will use original untranslated entries for all entries
> marked as "fuzzy" (visible as "Needs work" in Poedit). This is especially
> important when using
> [`cloud-translate`](https://github.com/mgeisler/cloud-translate) for initial
> translation as all entries will be marked as "fuzzy".

### Building a Translation

Make sure you have gone through the [build setup](./README.md#building) at least
once.

To use the `po/xx.po` file for your output, run the following command:

```shell
MDBOOK_BOOK__LANGUAGE=xx mdbook build -d book/xx
```

This will tell the `mdbook-gettext` preprocessor to translate the book using the
`po/xx.po` file. The HTML output can be found in `book/xx/html/`.

### Serving a Translation

Like normal, you can use `mdbook serve` to view your translation as you work on
it. You use the same command as with `mdbook build` above:

```shell
MDBOOK_BOOK__LANGUAGE=xx mdbook serve -d book/xx
```

When you update the `po/xx.po` file, the translated book will automatically
reload.

## Reviewing Translations

When a new translation is started, we look for people who can help review it.
These reviewers are often Googlers, but they don't have to be. To automatically
get an email when new PRs are created for your language, please add yourself to
the [CODEOWNERS] file.

When reviewing a translation, please keep in mind that translations are a labour
of love. Someone spends their free time translating the course because they want
to bring Rust to users who speak their language.

Nothing is published right away after a PR lands for a new in-progress language.
It is therefore safe to merge the PR as long as the translation is reasonable.
This is often better than leaving 50+ comments since this can be overwhelming
for the contributor. Instead, please work with the contributor to improve things
in follow-up PRs.

### GitHub Suggestions

When reviewing a translation PR, please use the
[GitHub suggestion feature](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/commenting-on-a-pull-request).
This feature allows you to directly write how you think a line or paragraph
should be phrased. Use the left-most button in the toolbar to create a
suggestion.

The PR author can
[apply the changes with a single click](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request)
afterwards, drastically reducing the number of round-trips needed in a review.

### Incomplete Translations

When the first 1-2 days of the course have been translated, we can publish the
translation and link it from the [translations page]. The idea is to celebrate
the hard work, even if it is incomplete.

[CODEOWNERS]: https://github.com/google/comprehensive-rust/blob/main/.github/CODEOWNERS

## Publication Workflow

> This section is for the developers of Comprehensive Rust, but it might give
> you valuable background information on how the translations are published.

When a change is made to the `main` branch, the [`publish.yml`] GitHub CI
workflow starts.

The `publish` job in this workflow will:

- Install dependencies as described in [`CONTRIBUTING`](CONTRIBUTING.md).

- Build every translation of the course, including the original English, using
  [`build.sh`]. The English HTML ends up in `book/html/`, the HTML for the `xx`
  language ends up in `book/xx/html/`.

- Publish the entire `book/html/` directory to
  https://google.github.io/comprehensive-rust/.

[`build.sh`]: https://github.com/google/comprehensive-rust/blob/main/.github/workflows/build.sh

### `build.sh`

The `build.sh` script is used both when testing code from a PR (with
[`build.yml`]) and when publishing the finished book (with [`publish.yml`]).

[`build.yml`]: https://github.com/google/comprehensive-rust/blob/main/.github/workflows/build.yml
[`publish.yml`]: https://github.com/google/comprehensive-rust/blob/main/.github/workflows/publish.yml

The job of the script is to call `mdbook build`, but with a few extra steps:

- It will enable the PDF output using `mdbook-pandoc`. This is disabled by
  default to make it easier for people to run `mdbook build` without having to
  configure LaTeX.

#### Restoring Translations

When building a translation (languages other than English), `build.sh` will
restore all Markdown files to how they looked at the time recorded in the
POT-Creation-Date header.

This means that:

- A translation does not degrade when the English text is changed.
- A translation will not received the latest fixes to the English text.

The script restores the Markdown with a simple

```sh
$ git restore --source $LAST_COMMIT src/ third_party/
```

command, where `$LAST_COMMIT` is the commit at the time of the POT-Creation-Date
header.

A consequence of this is that we use the latest theme, CSS, JavaScript, etc for
each translation.

After `build.sh` was run, the working copy is left in this dirty state. Beware
of this if you want to build the English version next, as you will have to clean
up manually.

## Status reports

Two translation status reports are automatically generated:

- [Translation status as checked in][translation-report]
- [Translation status after syncing to the latest version of the source with msgmerge][synced-translation-report]

You can also generate this report locally to see the effect of your local
changes:

```shell
i18n-report translation-report.html po/*.po
```

[translation-report]: https://google.github.io/comprehensive-rust/translation-report.html
[synced-translation-report]: https://google.github.io/comprehensive-rust/synced-translation-report.html


================================================
FILE: book.toml
================================================
[book]
authors = ["Martin Geisler"]
language = "en"
src = "src"
title = "Comprehensive Rust 🦀"

[rust]
edition = "2024"

[build]
extra-watch-dirs = ["po", "third_party"]

[preprocessor.gettext]
after = ["links"]

[preprocessor.svgbob]
renderers = ["html"]
after = ["gettext"]
class = "bob"

[preprocessor.course]
verbose = false # Report timing information.

[output.xgettext]
optional = true
pot-file = "messages.pot"
granularity = 0

[output.pandoc]
optional = true
disabled = true
hosted-html = "https://google.github.io/comprehensive-rust/"

[output.pandoc.profile.pdf]
output-file = "comprehensive-rust.pdf"
pdf-engine = "lualatex"

[output.pandoc.profile.pdf.variables]
mainfont = "Noto Serif"
sansfont = "Noto Sans"
monofont = "Noto Sans Mono"
mainfontfallback = [
  "NotoColorEmoji:mode=harf",
  "NotoNaskhArabic:",
]
sansfontfallback = [
  "NotoSansArabic:",
]
monofontfallback = [
  "NotoColorEmoji:mode=harf",
  "NotoSansMath:",
  "NotoSansMonoCJKSC:",
  "NotoSansArabic:",
]
geometry = ["margin=1.25in"]
linkcolor = "blue"
urlcolor = "red"

[output.html]
smart-punctuation = true
additional-js = [
  "theme/speaker-notes.js",
  "theme/redbox.js",
]
additional-css = [
  "theme/css/svgbob.css",
  "theme/css/redbox.css",
  "theme/css/speaker-notes.css",
  "theme/css/language-picker.css",
  "theme/css/rtl.css",
]
site-url = "/comprehensive-rust/"
git-repository-url = "https://github.com/google/comprehensive-rust"
edit-url-template = "https://github.com/google/comprehensive-rust/edit/main/{path}"

[output.html.fold]
enable = true
level = 0

[output.html.playground]
editable = true
line-numbers = true

[output.html.search]
use-boolean-and = true

# Redirects in the form of "old-path" = "new-path", where the new path
# is relative to the old path.
#
# Please keep the table sorted and avoid multi-step redirects.
[output.html.redirect]
"async/async-await.html" = "../concurrency/async/async-await.html"
"async/channels.html" = "../concurrency/async-control-flow/channels.html"
"async/concurrency/channels.html" = "../channels.html"
"async/control-flow/join.html" = "../concurrency/async-control-flow/join.html"
"async/control-flow/select.html" = "../concurrency/async-control-flow/select.html"
"async/futures.html" = "../concurrency/async/futures.html"
"async.html" = "concurrency/welcome-async.html"
"async/pitfall/async-traits.html" = "../async-pitfalls/async-traits.html"
"async/pitfalls/async-traits.html" = "../concurrency/async-pitfalls/async-traits.html"
"async/pitfalls/blocking-executor.html" = "../concurrency/async-pitfalls/blocking-executor.html"
"async/pitfalls/cancellation.html" = "../concurrency/async-pitfalls/cancellation.html"
"async/pitfalls.html" = "../concurrency/async-pitfalls.html"
"async/pitfalls/pin.html" = "../concurrency/async-pitfalls/pin.html"
"async/runtimes.html" = "../concurrency/async/runtimes.html"
"async/runtimes/tokio.html" = "../concurrency/async/runtimes/tokio.html"
"async/tasks.html" = "../concurrency/async/tasks.html"
"basic-syntax/compound-types.html" = "../tuples-and-arrays/tuples-and-arrays.html"
"basic-syntax/functions.html" = "../control-flow-basics/functions.html"
"basic-syntax/functions-interlude.html" = "../control-flow-basics/functions.html"
"basic-syntax.html" = "control-flow-basics.html"
"basic-syntax/methods.html" = "../control-flow-basics/functions.html"
"basic-syntax/references-dangling.html" = "../references/shared.html"
"basic-syntax/references.html" = "../references/shared.html"
"basic-syntax/rustdoc.html" = "../std-types/docs.html"
"basic-syntax/scalar-types.html" = "../types-and-values/values.html"
"basic-syntax/scopes-shadowing.html" = "../control-flow-basics/blocks-and-scopes.html"
"basic-syntax/slices.html" = "../references/slices.html"
"basic-syntax/static-and-const.html" = "../unsafe-rust/static-and-const.html"
"basic-syntax/string-slices.html" = "../references/strings.html"
"basic-syntax/type-inference.html" = "../types-and-values/inference.html"
"basic-syntax/variables.html" = "../types-and-values/variables.html"
"concurrency.html" = "concurrency/welcome.html"
"concurrency/scoped-threads.html" = "threads/scoped.html"
"concurrency/shared_state/arc.html" = "../shared-state/arc.html"
"concurrency/shared_state/example.html" = "../shared-state/example.html"
"concurrency/shared_state.html" = "shared-state.html"
"concurrency/shared_state/mutex.html" = "../shared-state/mutex.html"
"control-flow-basics/conditionals.html" = "if.html"
"control-flow/blocks.html" = "../control-flow-basics/blocks-and-scopes.html"
"control-flow/break-continue.html" = "../control-flow-basics/break-continue.html"
"control-flow/for-expressions.html" = "../control-flow-basics/loops.html"
"control-flow.html" = "control-flow-basics.html"
"control-flow/if-expressions.html" = "../control-flow-basics/conditionals.html"
"control-flow/if-let-expressions.html" = "../pattern-matching/let-control-flow.html"
"control-flow/loop-expressions.html" = "../control-flow-basics/loops.html"
"control-flow/match-expressions.html" = "../tuples-and-arrays/match.html"
"control-flow/novel.html" = "../pattern-matching/let-control-flow.html"
"control-flow/while-expressions.html" = "../control-flow-basics/loops.html"
"control-flow/while-let-expression.html" = "while-let-expressions.html"
"control-flow/while-let-expressions.html" = "../pattern-matching/let-control-flow.html"
"enums.html" = "user-defined-types/enums.html"
"enums/sizes.html" = "../user-defined-types/enums.html"
"enums/variant-payloads.html" = "../user-defined-types/enums.html"
"error-handling/converting-error-types-example.html" = "../error-handling/try-conversions.html"
"error-handling/converting-error-types.html" = "../error-handling/try-conversions.html"
"error-handling/deriving-error-enums.html" = "../error-handling/error.html"
"error-handling/dynamic-errors.html" = "../error-handling/anyhow.html"
"error-handling/error-contexts.html" = "../error-handling/anyhow.html"
"error-handling/thiserror-and-anyhow.html" = "../error-handling/anyhow.html"
"error-handling/panic-unwind.html" = "../error-handling/panics.html"
"error-handling/try-operator.html" = "../error-handling/try.html"
"exercises/concurrency/afternoon.html" = "../../concurrency/async-exercises.html"
"exercises/concurrency/chat-app.html" = "../../concurrency/async-exercises/chat-app.html"
"exercises/concurrency/dining-philosophers-async.html" = "../../concurrency/async-exercises/dining-philosophers.html"
"exercises/concurrency/dining-philosophers.html" = "../../concurrency/sync-exercises/dining-philosophers.html"
"exercises/concurrency/elevator.html" = "chat-app.html"
"exercises/concurrency/link-checker.html" = "../../concurrency/sync-exercises/link-checker.html"
"exercises/concurrency/morning.html" = "../../concurrency/sync-exercises.html"
"exercises/concurrency/solutions-afternoon.html" = "../../concurrency/async-exercises/solutions.html"
"exercises/concurrency/solutions-morning.html" = "../../concurrency/sync-exercises/solutions.html"
"exercises/day-1/afternoon.html" = "../../control-flow-basics/exercise.html"
"exercises/day-1/book-library.html" = "../day-2/book-library.html"
"exercises/day-1/for-loops.html" = "../../tuples-and-arrays/exercise.html"
"exercises/day-1/implicit-conversions.html" = "../../std-traits/exercise.html"
"exercises/day-1/iterators-and-ownership.html" = "../day-2/iterators-and-ownership.html"
"exercises/day-1/luhn.html" = "../../testing/exercise.html"
"exercises/day-1/morning.html" = "../../control-flow-basics/exercise.html"
"exercises/day-1/pattern-matching.html" = "../../user-defined-types/exercise.html"
"exercises/day-1/soluções-tarde.html" = "solutions-afternoon.html"
"exercises/day-2/afternoon.html" = "../../control-flow-basics/exercise.html"
"exercises/day-2/book-library.html" = "../../std-types/exercise.html"
"exercises/day-2/health-statistics.html" = "../../borrowing/exercise.html"
"exercises/day-2/iterators-and-ownership.html" = "../../iterators/intoiterator.html"
"exercises/day-2/luhn.html" = "../day-1/luhn.html"
"exercises/day-2/morning.html" = "../../control-flow-basics/exercise.html"
"exercises/day-2/points-polygons.html" = "../day-3/points-polygons.html"
"exercises/day-2/soluções-tarde.html" = "solutions-afternoon.html"
"exercises/day-2/strings-iterators.html" = "../../iterators/exercise.html"
"exercises/day-3/afternoon.html" = "../../control-flow-basics/exercise.html"
"exercises/day-3/morning.html" = "../../control-flow-basics/exercise.html"
"exercises/day-3/points-polygons.html" = "../../references/exercise.html"
"exercises/day-3/safe-ffi-wrapper.html" = "../../unsafe-rust/exercise.html"
"exercises/day-3/simple-gui.html" = "../../methods-and-traits/exercise.html"
"exercises/day-3/simples-gui.html" = "simple-gui.html"
"exercises/day-3/soluções-tarde.html" = "solutions-afternoon.html"
"exercises/day-4/afternoon.html" = "../android/morning.html"
"exercises/day-4/android.html" = "../android/morning.html"
"exercises/day-4/dining-philosophers.html" = "../concurrency/dining-philosophers.html"
"exercises/day-4/elevator.html" = "../concurrency/elevator.html"
"exercises/day-4/link-checker.html" = "../concurrency/link-checker.html"
"exercises/day-4/morning.html" = "../concurrency/morning.html"
"exercises/day-4/solutions-morning.html" = "../concurrency/solutions-morning.html"
"generics/closures.html" = "../traits/closures.html"
"generics/data-types.html" = "../generics/generic-data.html"
"generics/methods.html" = "../generics/generic-data.html"
"generics/monomorphization.html" = "../generics/generic-functions.html"
"generics/trait-objects.html" = "../traits/trait-objects.html"
"hello-world/basic-syntax/functions-interlude.html" = "../../control-flow-basics/functions.html"
"hello-world/hello-world.html" = "../types-and-values/hello-world.html"
"lifetimes/lifetime-annotations.html" = "../lifetimes.html"
"memory-management/manual.html" = "../memory-management/approaches.html"
"memory-management/rust.html" = "../memory-management/ownership.html"
"memory-management/scope-based.html" = "../memory-management/approaches.html"
"memory-management/stack.html" = "../memory-management/review.html"
"memory-management/stack-vs-heap.html" = "../memory-management/review.html"
"methods-and-traits/trait-objects.html" = "../smart-pointers/trait-objects.html"
"methods/example.html" = "../methods-and-traits/methods.html"
"methods.html" = "methods-and-traits/methods.html"
"methods/receiver.html" = "../methods-and-traits/methods.html"
"outros-recursos.html" = "other-resources.html"
"ownership/borrowing.html" = "../borrowing/shared.html"
"ownership/copy-clone.html" = "../memory-management/copy-types.html"
"ownership/double-free-modern-cpp.html" = "../memory-management/move.html"
"ownership.html" = "memory-management/ownership.html"
"ownership/lifetimes-data-structures.html" = "../lifetimes/struct-lifetimes.html"
"ownership/lifetimes-function-calls.html" = "../lifetimes/lifetime-elision.html"
"ownership/lifetimes.html" = "../lifetimes/lifetime-annotations.html"
"ownership/moved-strings-rust.html" = "../memory-management/move.html"
"ownership/move-semantics.html" = "../memory-management/move.html"
"ownership/moves-function-calls.html" = "../memory-management/move.html"
"ownership/shared-unique-borrows.html" = "../borrowing/shared.html"
"pattern-matching/destructuring-arrays.html" = "../tuples-and-arrays/destructuring.html"
"pattern-matching/destructuring.html" = "destructuring-structs.html"
"pattern-matching/match-guards.html" = "../tuples-and-arrays/match.html"
"running-the-course/day-4.html" = "course-structure.html"
"sintaxe-básica/funções-interlude.html" = "../basic-syntax/functions-interlude.html"
"slices-and-lifetimes/exercise.html" = "../lifetimes/exercise.html"
"slices-and-lifetimes.html" = "lifetimes.html"
"slices-and-lifetimes/lifetime-annotations.html" = "../lifetimes/lifetime-annotations.html"
"slices-and-lifetimes/lifetime-elision.html" = "../lifetimes/lifetime-elision.html"
"slices-and-lifetimes/slices.html" = "../references/slices.html"
"slices-and-lifetimes/solution.html" = "../lifetimes/solution.html"
"slices-and-lifetimes/str.html" = "../references/strings.html"
"slices-and-lifetimes/struct-lifetimes.html" = "../lifetimes/struct-lifetimes.html"
"std/box.html" = "../smart-pointers/box.html"
"std/box-niche.html" = "../smart-pointers/box.html"
"std/box-recursive.html" = "../smart-pointers/box.html"
"std/cell.html" = "../borrowing/interior-mutability.html"
"std/hashmap.html" = "../std-types/hashmap.html"
"std.html" = "std-types/std.html"
"std/option-result.html" = "../std-types/option.html"
"std/rc.html" = "../smart-pointers/rc.html"
"std/string.html" = "../std-types/string.html"
"std/vec.html" = "../std-types/vec.html"
"structs/field-shorthand.html" = "../user-defined-types/named-structs.html"
"structs.html" = "user-defined-types/named-structs.html"
"structs/tuple-structs.html" = "../user-defined-types/tuple-structs.html"
"structure.html" = "running-the-course/course-structure.html"
"testing/doc-tests.html" = "../testing/other.html"
"testing/googletest.html" = "../android/testing/googletest.html"
"testing/integration-tests.html" = "../testing/other.html"
"testing/mockall.html" = "../android/testing/mockall.html"
"testing/useful-crates.html" = "../testing.html"
"traits/closures.html" = "../std-traits/closures.html"
"traits/default.html" = "../std-traits/default.html"
"traits/default-methods.html" = "../methods-and-traits/traits.html"
"traits/deriving-traits.html" = "../methods-and-traits/deriving.html"
"traits/drop.html" = "../memory-management/drop.html"
"traits/from-into.html" = "../std-traits/from-and-into.html"
"traits/from-iterator.html" = "../iterators/fromiterator.html"
"traits.html" = "methods-and-traits/traits.html"
"traits/impl-trait.html" = "../generics/impl-trait.html"
"traits/important-traits.html" = "../std-traits/comparisons.html"
"traits/iterator.html" = "../iterators/iterators.html"
"traits/operators.html" = "../std-traits/operators.html"
"traits/read-write.html" = "../std-traits/read-and-write.html"
"traits/trait-bounds.html" = "../generics/trait-bounds.html"
"traits/trait-objects.html" = "../smart-pointers/trait-objects.html"
"tuples-and-arrays/match.html" = "../pattern-matching/match.html"
"tuples-and-arrays/tuples-and-arrays.html" = "tuples.html"
"types-and-values/strings.html" = "../references/strings.html"
"unsafe/calling-unsafe-functions.html" = "../unsafe-rust/unsafe-functions.html"
"unsafe/extern-functions.html" = "../unsafe-rust/unsafe-functions.html"
"unsafe.html" = "unsafe-rust/unsafe.html"
"unsafe/mutable-static-variables.html" = "../unsafe-rust/mutable-static.html"
"unsafe/mutable-static-variables.md" = "mutable-static-variables.html"
"unsafe/raw-pointers.html" = "../unsafe-rust/dereferencing.html"
"unsafe/unions.html" = "../unsafe-rust/unions.html"
"unsafe/unsafe-functions.html" = "calling-unsafe-functions.html"
"unsafe/unsafe-traits.html" = "../unsafe-rust/unsafe-traits.html"
"unsafe/writing-unsafe-functions.html" = "../unsafe-rust/unsafe-functions.html"
"user-defined-types/static-and-const.html" = "../user-defined-types/static.html"
"welcome-bare-metal.html" = "bare-metal.html"
"welcome-day-1/what-is-rust.html" = "../hello-world/what-is-rust.html"
"welcome.html" = "./"
"why-rust/an-example-in-c.html" = "../hello-world/example.html"
"why-rust/compile-time.html" = "../hello-world/benefits.html"
"why-rust.html" = "hello-world/benefits.html"
"why-rust/modern.html" = "../hello-world/benefits.html"
"why-rust/runtime.html" = "../hello-world/benefits.html"

[output.exerciser]
output-directory = "comprehensive-rust-exercises"

[output.linkcheck]
optional = true
follow-web-links = false # change to true to check web links
exclude = [
  "comprehensive-rust.pdf",
  "comprehensive-rust-exercises.zip",
  # "crates.io", # uncomment when follow-web-links is true
]

[output.linkcheck2]
optional = true
follow-web-links = false # change to true to check web links
exclude = [
  "comprehensive-rust.pdf",
  "comprehensive-rust-exercises.zip",
  # "crates.io", # uncomment when follow-web-links is true
]


================================================
FILE: dprint.json
================================================
{
  "lineWidth": 80,
  "json": {},
  "markdown": {
    "textWrap": "always"
  },
  "exec": {
    "commands": [{
      "command": "yapf3",
      "exts": ["py"]
    }, {
      "command": "rustup run nightly-2025-09-01 rustfmt --edition 2024",
      "exts": ["rs"]
    }]
  },
  "excludes": [
    "/book/",
    "/theme/*.hbs",
    "/theme/book.js",
    "/third_party/",
    "target/"
  ],
  "plugins": [
    "https://plugins.dprint.dev/exec-0.5.1.json@492414e39dea4dccc07b4af796d2f4efdb89e84bae2bd4e1e924c0cc050855bf",
    "https://plugins.dprint.dev/json-0.20.0.wasm",
    "https://plugins.dprint.dev/markdown-0.18.0.wasm",
    "https://plugins.dprint.dev/toml-0.7.0.wasm",
    "https://plugins.dprint.dev/prettier-0.56.0.json@0b67676535141b03f0eb0648172d3a20f13044b3d8df677d645bd79e3ee5147f"
  ]
}


================================================
FILE: mdbook-course/Cargo.toml
================================================
[package]
name = "mdbook-course"
version = "0.1.0"
authors = ["Dustin Mitchell <djmitche@google.com>"]
edition = "2024"
license = "Apache-2.0"
publish = false
repository = "https://github.com/google/comprehensive-rust"
description = "An mdbook preprocessor for comprehensive-rust."

[dependencies]
anyhow = "1.0.102"
clap = "4.5.60"
lazy_static = "1.5"
log = "0.4.29"
matter = "0.1.0-alpha4"
mdbook = "0.4.52"
pretty_env_logger = "0.5.0"
regex = "1.12"
serde = "1.0.228"
serde_json = "1.0.149"
serde_yaml = "0.9"


================================================
FILE: mdbook-course/README.md
================================================
# mdbook-course

This is an mdBook preprocessor to handle some specific details of Comprehensive
Rust.

It provides three binaries:

- `mdbook-course` -- the actual preprocessor
- `course-schedule` -- prints the course schedule with timings
- `course-content` -- dumps all course content to stdout, in order

## Frontmatter

The preprocessor parses "frontmatter" -- YAML between `---` at the beginning of
a Markdown file -- and removes it from the rendered result.

Frontmatter is optional, and can contain any of the following fields, defined
below:

```yaml
minutes: NNN
target_minutes: NNN
course: COURSE NAME
session: SESSION NAME
```

## Course Structure

A book can contain multiple _courses_. Each course is made up of _sessions_,
which are blocks of instructional time (and include breaks). Typically two
sessions are taught per day, morning and afternoon.

Each session is comprised of _segments_, which are slides on a related theme.
Breaks are scheduled between segments.

Each segment is comprised of _slides_. A slide can be made up of one or more
mdBook chapters.

The course structure is derived from the mdBook structure. Each top-level mdBook
"section" is treated as a segment, and may optionally begin a new session or
course. Within each section, the first chapter and subsequent second-level
chapters are each treated as a slide. Any further-nested chapters are treated as
parts of the parent slide. For example:

```ignore
- [Frobnication](frobnication.md)
  - [Integer Frobnication](frobnication/integers.md)
  - [Frob Expansion](frobnication/expansion.md)
    - [Structs](frobnication/expansion-structs.md)
    - [Enums](frobnication/expansion-structs.md)
  - [Exercise](frobnication/exercise.md)
    - [Solution](frobnication/Solution.md)
```

In this segment, there are four slides: "Frobnication", "Integer Frobnication",
"Frob Expansion", and "Exercise". The last two slides are made up of multiple
chapters.

The first chapter of a segment can use the `course` and `session` fields in its
frontmatter to indicate that it is the first segment in a session or course.

## Timing

Each chapter should specify an estimate of the instructional time it will
require in the `minutes` field. This information is summed, with breaks
automatically added between segments, to give time estimates for segments,
sessions, and courses.

Each session should list a `target_minutes` that is the target duration of the
session.

## Directives

Within the course material, the following directives can be used:

```
{{%segment outline}}
{{%session outline}}
{{%course outline}}
{{%course outline COURSENAME}}
```

These will be replaced with a markdown outline of the current segment, session,
or course. The last directive can refer to another course by name and is used in
the "Running the Course" section.

# Course-Schedule Comments

The `course-schedule` binary generates Markdown output that is included in a
GitHub pull request comment, based on the information provided in the above
format.


================================================
FILE: mdbook-course/src/bin/course-content.rs
================================================
// Copyright 2024 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use mdbook::MDBook;
use mdbook_course::course::Courses;
use std::fs;
use std::path::Path;

fn main() {
    pretty_env_logger::init();
    let root_dir = ".";
    let mdbook = MDBook::load(root_dir).expect("Unable to load the book");
    let (courses, _) = Courses::extract_structure(mdbook.book)
        .expect("Unable to extract course structure");

    let src_dir = Path::new("src");
    for course in &courses {
        println!("# COURSE: {}", course.name);
        for session in course {
            println!("# SESSION: {}", session.name);
            for segment in session {
                println!("# SEGMENT: {}", segment.name);
                for slide in segment {
                    println!("# SLIDE: {}", slide.name);
                    for path in &slide.source_paths {
                        let content =
                            fs::read_to_string(src_dir.join(path)).unwrap();
                        println!("{}", content);
                    }
                }
            }
        }
    }
}


================================================
FILE: mdbook-course/src/bin/course-schedule.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap::Command;
use mdbook::MDBook;
use mdbook_course::course::Courses;
use mdbook_course::markdown::duration;

fn main() {
    pretty_env_logger::init();
    let app = Command::new("mdbook-course")
        .about("mdbook preprocessor for Comprehensive Rust")
        .subcommand(Command::new("sessions").about("Show session summary (default)"))
        .subcommand(Command::new("segments").about("Show segment summary"))
        .subcommand(Command::new("pr").about("Show summary for a PR"));
    let matches = app.get_matches();

    let root_dir = ".";
    let mdbook = MDBook::load(root_dir).expect("Unable to load the book");
    let (courses, _) = Courses::extract_structure(mdbook.book)
        .expect("Unable to extract course structure");

    match matches.subcommand() {
        Some(("session", _)) | None => session_summary(&courses),
        Some(("pr", _)) => pr_summary(&courses),
        _ => unreachable!(),
    }
}

fn timediff(actual: u64, target: u64, slop: u64) -> String {
    if actual > target + slop {
        format!(
            "{} (\u{23f0} *{} too long*)",
            duration(actual),
            duration(actual - target),
        )
    } else if actual + slop < target {
        format!("{}: ({} short)", duration(actual), duration(target - actual),)
    } else {
        duration(actual).to_string()
    }
}

fn session_summary(courses: &Courses) {
    for course in courses {
        if course.target_minutes() == 0 {
            return;
        }
        for session in course {
            println!("### {} // {}", course.name, session.name);
            println!(
                "_{}_",
                timediff(session.minutes(), session.target_minutes(), 15)
            );
            println!();
            for segment in session {
                println!("* {} - _{}_", segment.name, duration(segment.minutes()));
            }
            println!();
        }
    }
}

fn pr_summary(courses: &Courses) {
    println!("## Course Schedule");
    println!("With this pull request applied, the course schedule is as follows:");
    for course in courses {
        if course.target_minutes() == 0 {
            return;
        }
        println!("### {}", course.name);
        println!("_{}_", timediff(course.minutes(), course.target_minutes(), 15));

        for session in course {
            println!(
                "* {} - _{}_",
                session.name,
                timediff(session.minutes(), session.target_minutes(), 5)
            );
        }
    }
}


================================================
FILE: mdbook-course/src/bin/mdbook-course.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap::{Arg, Command};
use mdbook::book::BookItem;
use mdbook::preprocess::CmdPreprocessor;
use mdbook_course::course::Courses;
use mdbook_course::{replacements, timing_info};
use std::io::{stdin, stdout};
use std::process;

fn main() {
    pretty_env_logger::init();
    let app = Command::new("mdbook-course")
        .about("mdbook preprocessor for Comprehensive Rust")
        .subcommand(
            Command::new("supports").arg(Arg::new("renderer").required(true)),
        );
    let matches = app.get_matches();

    if matches.subcommand_matches("supports").is_some() {
        // Support all renderers.
        process::exit(0);
    }

    if let Err(e) = preprocess() {
        eprintln!("{}", e);
        process::exit(1);
    }
}

fn preprocess() -> anyhow::Result<()> {
    let (_, book) = CmdPreprocessor::parse_input(stdin())?;
    let (courses, mut book) = Courses::extract_structure(book)?;

    book.for_each_mut(|chapter| {
        if let BookItem::Chapter(chapter) = chapter {
            if let Some((course, session, segment, slide)) =
                courses.find_slide(chapter)
            {
                timing_info::insert_timing_info(slide, chapter);
                replacements::replace(
                    &courses,
                    Some(course),
                    Some(session),
                    Some(segment),
                    chapter,
                );
            } else {
                // Outside of a course, just perform replacements.
                replacements::replace(&courses, None, None, None, chapter);
            }
        }
    });

    serde_json::to_writer(stdout(), &book)?;
    Ok(())
}


================================================
FILE: mdbook-course/src/course.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Representation of Comprehensive Rust as a hierarchy of types.
//!
//! ```ignore
//! Courses -- a collection of courses
//!   Course -- the level of content at which students enroll (fundamentals, android, etc.)
//!     Session -- a block of instructional time (typically morning or afternoon)
//!       Segment -- a collection of slides with a related theme
//!         Slide -- a single topic (may be represented by multiple mdBook chapters)
//! ```
//!
//! This structure is parsed from the format of the book using a combination of
//! the order in which chapters are listed in `SUMMARY.md` and annotations in
//! the frontmatter of each chapter.
//!
//! A book contains a sequence of BookItems, each of which can contain
//! sub-items. A top-level item can potentially introduce a new course, session,
//! segment, and slide all in the same item. If the item has a `course` property
//! in its frontmatter, then it introduces a new course. If it has a `session`
//! property, then it introduces a new session. A top-level item always
//! corresponds 1-to-1 with a segment (as long as it is a chapter), and that
//! item becomes the first slide in that segment. Any other sub-items of the
//! top-level item are treated as further slides in the same segment.

use crate::frontmatter::{Frontmatter, split_frontmatter};
use crate::markdown::{Table, duration};
use mdbook::book::{Book, BookItem, Chapter};
use std::fmt::Write;
use std::path::PathBuf;

/// Duration, in minutes, of breaks between segments in the course.
const BREAK_DURATION: u64 = 10;

/// Courses is simply a collection of Courses.
///
/// Non-instructional material (such as the introduction) has `course: none` and
/// is not included in this data structure.
#[derive(Default, Debug)]
pub struct Courses {
    pub courses: Vec<Course>,
}

/// A Course is the level of content at which students enroll.
///
/// Courses are identified by the `course` property in a session's frontmatter.
/// All sessions with the same value for `course` are grouped into a Course.
#[derive(Default, Debug)]
pub struct Course {
    pub name: String,
    pub sessions: Vec<Session>,
}

/// A Session is a block of instructional time, containing segments. Typically a
/// full day of instruction contains two sessions: morning and afternoon.
///
/// A session is identified by the `session` property in the session's
/// frontmatter. There can be only one session with a given name in a course.
#[derive(Default, Debug)]
pub struct Session {
    pub name: String,
    pub segments: Vec<Segment>,
    target_minutes: u64,
}

/// A Segment is a collection of slides with a related theme.
///
/// A segment is identified as a top-level chapter within a session.
#[derive(Default, Debug)]
pub struct Segment {
    pub name: String,
    pub slides: Vec<Slide>,
}

/// A Slide presents a single topic. It may contain multiple mdBook chapters.
///
/// A slide is identified as an sub-chapter of a segment. Any sub-items of
/// that chapter are also included in the slide.
#[derive(Default, Debug)]
pub struct Slide {
    pub name: String,
    /// Minutes this slide should take to teach.
    pub minutes: u64,
    /// Source paths (`.md` files) in this slide.
    pub source_paths: Vec<PathBuf>,
}

impl Courses {
    /// Extract the course structure from the book. As a side-effect, the
    /// frontmatter is stripped from each slide.
    pub fn extract_structure(mut book: Book) -> anyhow::Result<(Self, Book)> {
        let mut courses = Courses::default();
        let mut current_course_name = None;
        let mut current_session_name = None;

        for item in &mut book.sections {
            // We only want to process chapters, omitting part titles and separators.
            let BookItem::Chapter(chapter) = item else {
                continue;
            };

            let (frontmatter, content) = split_frontmatter(chapter)?;
            chapter.content = content;

            // If 'course' is given, use that course (if not 'none') and reset the
            // session.
            if let Some(course_name) = &frontmatter.course {
                current_session_name = None;
                if course_name == "none" {
                    current_course_name = None;
                } else {
                    current_course_name = Some(course_name.clone());
                }
            }

            // If 'session' is given, use that session.
            if let Some(session_name) = &frontmatter.session {
                current_session_name = Some(session_name.clone());
            }

            if current_course_name.is_some() && current_session_name.is_none() {
                anyhow::bail!(
                    "{:?}: 'session' must appear in frontmatter when 'course' appears",
                    chapter.path
                );
            }

            // If we have a course and session, then add this chapter to it as a
            // segment.
            if let (Some(course_name), Some(session_name)) =
                (&current_course_name, &current_session_name)
            {
                let course = courses.course_mut(course_name);
                let session = course.session_mut(session_name);
                session.target_minutes += frontmatter.target_minutes.unwrap_or(0);
                session.add_segment(frontmatter, chapter)?;
            }
        }
        Ok((courses, book))
    }

    /// Get a reference to a course, adding a new one if none by this name
    /// exists.
    fn course_mut(&mut self, name: impl AsRef<str>) -> &mut Course {
        let name = name.as_ref();
        if let Some(found_idx) =
            self.courses.iter().position(|course| course.name == name)
        {
            return &mut self.courses[found_idx];
        }
        let course = Course::new(name);
        self.courses.push(course);
        self.courses.last_mut().unwrap()
    }

    /// Find a course by name.
    pub fn find_course(&self, name: impl AsRef<str>) -> Option<&Course> {
        let name = name.as_ref();
        self.courses.iter().find(|c| c.name == name)
    }

    /// Find the slide generated from the given Chapter within these courses,
    /// returning the "path" to that slide.
    pub fn find_slide(
        &self,
        chapter: &Chapter,
    ) -> Option<(&Course, &Session, &Segment, &Slide)> {
        let source_path = chapter.source_path.as_ref()?;

        for course in self {
            for session in course {
                for segment in session {
                    for slide in segment {
                        if slide.source_paths.contains(source_path) {
                            return Some((course, session, segment, slide));
                        }
                    }
                }
            }
        }

        None
    }
}

impl<'a> IntoIterator for &'a Courses {
    type Item = &'a Course;
    type IntoIter = std::slice::Iter<'a, Course>;

    fn into_iter(self) -> Self::IntoIter {
        self.courses.iter()
    }
}

impl Course {
    fn new(name: impl Into<String>) -> Self {
        Course { name: name.into(), ..Default::default() }
    }

    /// Get a reference to a session, adding a new one if none by this name
    /// exists.
    fn session_mut(&mut self, name: impl AsRef<str>) -> &mut Session {
        let name = name.as_ref();
        if let Some(found_idx) =
            self.sessions.iter().position(|session| session.name == name)
        {
            return &mut self.sessions[found_idx];
        }
        let session = Session::new(name);
        self.sessions.push(session);
        self.sessions.last_mut().unwrap()
    }

    /// Return the total duration of this course, as the sum of all segment
    /// durations.
    ///
    /// This includes breaks between segments, but does not count time between
    /// between sessions.
    pub fn minutes(&self) -> u64 {
        self.into_iter().map(|s| s.minutes()).sum()
    }

    /// Return the target duration of this course, as the sum of all segment
    /// target durations.
    ///
    /// This includes breaks between segments, but does not count time between
    /// sessions.
    pub fn target_minutes(&self) -> u64 {
        self.into_iter().map(|s| s.target_minutes()).sum()
    }

    /// Generate a Markdown schedule for this course, for placement at the given
    /// path.
    pub fn schedule(&self) -> String {
        let mut outline = String::from("Course schedule:\n");
        for session in self {
            writeln!(
                &mut outline,
                " * {} ({}, including breaks)\n",
                session.name,
                duration(session.minutes())
            )
            .unwrap();
            let mut segments = Table::new(["Segment".into(), "Duration".into()]);
            for segment in session {
                // Skip short segments (welcomes, wrap-up, etc.)
                if segment.minutes() == 0 {
                    continue;
                }
                segments
                    .add_row([segment.name.clone(), duration(segment.minutes())]);
            }
            writeln!(&mut outline, "{}\n", segments).unwrap();
        }
        outline
    }
}

impl<'a> IntoIterator for &'a Course {
    type Item = &'a Session;
    type IntoIter = std::slice::Iter<'a, Session>;

    fn into_iter(self) -> Self::IntoIter {
        self.sessions.iter()
    }
}

impl Session {
    fn new(name: impl Into<String>) -> Self {
        Session { name: name.into(), ..Default::default() }
    }

    /// Add a new segment to the session, representing sub-items as slides.
    fn add_segment(
        &mut self,
        frontmatter: Frontmatter,
        chapter: &mut Chapter,
    ) -> anyhow::Result<()> {
        let mut segment = Segment::new(&chapter.name);
        segment.add_slide(frontmatter, chapter, false)?;
        for sub_chapter in &mut chapter.sub_items {
            let BookItem::Chapter(sub_chapter) = sub_chapter else {
                continue;
            };
            let (frontmatter, content) = split_frontmatter(sub_chapter)?;
            sub_chapter.content = content;

            segment.add_slide(frontmatter, sub_chapter, true)?;
        }
        self.segments.push(segment);
        Ok(())
    }

    /// Generate a Markdown outline for this session, for placement at the given
    /// path.
    pub fn outline(&self) -> String {
        let mut segments = Table::new(["Segment".into(), "Duration".into()]);
        for segment in self {
            // Skip short segments (welcomes, wrap-up, etc.)
            if segment.minutes() == 0 {
                continue;
            }
            segments.add_row([segment.name.clone(), duration(segment.minutes())]);
        }
        format!(
            "Including {BREAK_DURATION} minute breaks, this session should take about {}. It contains:\n\n{}",
            duration(self.minutes()),
            segments
        )
    }

    /// Return the total duration of this session.
    pub fn minutes(&self) -> u64 {
        let instructional_time: u64 = self.into_iter().map(|s| s.minutes()).sum();
        if instructional_time == 0 {
            return instructional_time;
        }
        let breaks = (self.into_iter().filter(|s| s.minutes() > 0).count() - 1)
            as u64
            * BREAK_DURATION;
        instructional_time + breaks
    }

    /// Return the target duration of this session.
    ///
    /// This includes breaks between segments.
    pub fn target_minutes(&self) -> u64 {
        if self.target_minutes > 0 { self.target_minutes } else { self.minutes() }
    }
}

impl<'a> IntoIterator for &'a Session {
    type Item = &'a Segment;
    type IntoIter = std::slice::Iter<'a, Segment>;

    fn into_iter(self) -> Self::IntoIter {
        self.segments.iter()
    }
}

impl Segment {
    fn new(name: impl Into<String>) -> Self {
        Segment { name: name.into(), ..Default::default() }
    }

    /// Create a slide from a chapter. If `recurse` is true, sub-items of this
    /// chapter are included in this slide as well.
    fn add_slide(
        &mut self,
        frontmatter: Frontmatter,
        chapter: &mut Chapter,
        recurse: bool,
    ) -> anyhow::Result<()> {
        let mut slide = Slide::new(frontmatter, chapter);

        if recurse {
            slide.add_sub_chapters(chapter)?;
        }
        self.slides.push(slide);
        Ok(())
    }

    /// Return the total duration of this segment (the sum of the durations of
    /// the enclosed slides).
    pub fn minutes(&self) -> u64 {
        self.into_iter().map(|s| s.minutes()).sum()
    }

    pub fn outline(&self) -> String {
        let mut slides = Table::new(["Slide".into(), "Duration".into()]);
        for slide in self {
            if slide.minutes() == 0 {
                continue;
            }
            slides.add_row([slide.name.clone(), duration(slide.minutes())]);
        }
        format!(
            "This segment should take about {}. It contains:\n\n{}",
            duration(self.minutes()),
            slides,
        )
    }
}

impl<'a> IntoIterator for &'a Segment {
    type Item = &'a Slide;
    type IntoIter = std::slice::Iter<'a, Slide>;

    fn into_iter(self) -> Self::IntoIter {
        self.slides.iter()
    }
}

impl Slide {
    fn new(frontmatter: Frontmatter, chapter: &Chapter) -> Self {
        let mut slide = Self { name: chapter.name.clone(), ..Default::default() };
        slide.add_frontmatter(&frontmatter);
        slide.push_source_path(&chapter.source_path);
        slide
    }

    fn add_frontmatter(&mut self, frontmatter: &Frontmatter) {
        self.minutes += frontmatter.minutes.unwrap_or(0);
    }

    fn push_source_path(&mut self, source_path: &Option<PathBuf>) {
        if let Some(source_path) = &source_path {
            self.source_paths.push(source_path.clone());
        }
    }

    /// Add sub-chapters of this chapter to this slide (recursively).
    fn add_sub_chapters(&mut self, chapter: &mut Chapter) -> anyhow::Result<()> {
        for sub_slide in &mut chapter.sub_items {
            let BookItem::Chapter(sub_slide) = sub_slide else {
                continue;
            };
            let (frontmatter, content) = split_frontmatter(sub_slide)?;
            sub_slide.content = content;

            if frontmatter.course.is_some() || frontmatter.session.is_some() {
                anyhow::bail!(
                    "{:?}: sub-slides may not have 'course' or 'session' set",
                    sub_slide.path
                );
            }
            self.add_frontmatter(&frontmatter);
            self.push_source_path(&sub_slide.source_path);
            self.add_sub_chapters(sub_slide)?;
        }
        Ok(())
    }

    /// Determine whether the given chapter is a sub-chapter of this slide.
    pub fn is_sub_chapter(&self, chapter: &Chapter) -> bool {
        // The first `source_path` in the slide is the "parent" chapter, so anything
        // else is a sub-chapter.
        chapter.source_path.as_ref() != self.source_paths.first()
    }

    /// Return the total duration of this slide.
    pub fn minutes(&self) -> u64 {
        self.minutes
    }
}


================================================
FILE: mdbook-course/src/frontmatter.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::Context;
use matter::matter;
use mdbook::book::Chapter;
use serde::Deserialize;

#[derive(Deserialize, Debug, Default)]
pub struct Frontmatter {
    pub minutes: Option<u64>,
    pub target_minutes: Option<u64>,
    pub course: Option<String>,
    pub session: Option<String>,
}

/// Split a chapter's contents into frontmatter and the remaining contents.
pub fn split_frontmatter(
    chapter: &Chapter,
) -> anyhow::Result<(Frontmatter, String)> {
    if let Some((frontmatter, content)) = matter(&chapter.content) {
        let frontmatter: Frontmatter = serde_yaml::from_str(&frontmatter)
            .with_context(|| {
                format!("error parsing frontmatter in {:?}", chapter.source_path)
            })?;

        Ok((frontmatter, content))
    } else {
        Ok((Frontmatter::default(), chapter.content.clone()))
    }
}


================================================
FILE: mdbook-course/src/lib.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod course;
pub mod frontmatter;
pub mod markdown;
pub mod replacements;
pub mod timing_info;


================================================
FILE: mdbook-course/src/markdown.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;
use std::path::Path;

/// Given a source_path for the markdown file being rendered and a source_path
/// for the target, generate a relative link.
pub fn relative_link(
    doc_path: impl AsRef<Path>,
    target_path: impl AsRef<Path>,
) -> String {
    let doc_path = doc_path.as_ref();
    let target_path = target_path.as_ref();

    let mut dotdot = -1;
    for parent in doc_path.ancestors() {
        if target_path.starts_with(parent) {
            break;
        }
        dotdot += 1;
    }
    if dotdot > 0 {
        format!("{}{}", "../".repeat(dotdot as usize), target_path.display())
    } else {
        format!("./{}", target_path.display())
    }
}

/// Represent the given duration in a human-readable way.
///
/// This will round times longer than 5 minutes to the next 5-minute interval.
pub fn duration(mut minutes: u64) -> String {
    if minutes > 5 {
        minutes += 4;
        minutes -= minutes % 5;
    }

    let (hours, minutes) = (minutes / 60, minutes % 60);
    match (hours, minutes) {
        (0, 1) => "1 minute".into(),
        (0, m) => format!("{m} minutes"),
        (1, 0) => "1 hour".into(),
        (1, m) => format!("1 hour and {m} minutes"),
        (h, 0) => format!("{h} hours"),
        (h, m) => format!("{h} hours and {m} minutes"),
    }
}

/// Table implements Display to format a two-dimensional table as markdown,
/// following https://github.github.com/gfm/#tables-extension-.
pub struct Table<const N: usize> {
    header: [String; N],
    rows: Vec<[String; N]>,
}

impl<const N: usize> Table<N> {
    pub fn new(header: [String; N]) -> Self {
        Self { header, rows: Vec::new() }
    }

    pub fn add_row(&mut self, row: [String; N]) {
        self.rows.push(row);
    }

    fn write_row<'a, I: Iterator<Item = &'a str>>(
        &self,
        f: &mut fmt::Formatter<'_>,
        iter: I,
    ) -> fmt::Result {
        write!(f, "|")?;
        for cell in iter {
            write!(f, " {} |", cell)?;
        }
        writeln!(f)
    }
}

impl<const N: usize> fmt::Display for Table<N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.write_row(f, self.header.iter().map(|s| s.as_str()))?;
        self.write_row(f, self.header.iter().map(|_| "-"))?;
        for row in &self.rows {
            self.write_row(f, row.iter().map(|s| s.as_str()))?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn relative_link_same_dir() {
        assert_eq!(
            relative_link(Path::new("welcome.md"), Path::new("hello-world.md")),
            "./hello-world.md".to_string()
        );
    }

    #[test]
    fn relative_link_subdir() {
        assert_eq!(
            relative_link(
                Path::new("hello-world.md"),
                Path::new("hello-world/foo.md")
            ),
            "./hello-world/foo.md".to_string()
        );
    }

    #[test]
    fn relative_link_parent_dir() {
        assert_eq!(
            relative_link(
                Path::new("references/foo.md"),
                Path::new("hello-world.md")
            ),
            "../hello-world.md".to_string()
        );
    }

    #[test]
    fn relative_link_deep_parent_dir() {
        assert_eq!(
            relative_link(
                Path::new("references/foo/bar.md"),
                Path::new("hello-world.md")
            ),
            "../../hello-world.md".to_string()
        );
    }

    #[test]
    fn relative_link_peer_dir() {
        assert_eq!(
            relative_link(
                Path::new("references/foo.md"),
                Path::new("hello-world/foo.md")
            ),
            "../hello-world/foo.md".to_string()
        );
    }

    #[test]
    fn duration_no_time() {
        assert_eq!(duration(0), "0 minutes");
    }

    #[test]
    fn duration_single_minute() {
        assert_eq!(duration(1), "1 minute");
    }

    #[test]
    fn duration_two_minutes() {
        assert_eq!(duration(2), "2 minutes");
    }

    #[test]
    fn duration_seven_minutes() {
        assert_eq!(duration(7), "10 minutes");
    }

    #[test]
    fn duration_hour() {
        assert_eq!(duration(60), "1 hour");
    }

    #[test]
    fn duration_hour_mins() {
        assert_eq!(duration(61), "1 hour and 5 minutes");
    }

    #[test]
    fn duration_hours() {
        assert_eq!(duration(120), "2 hours");
    }

    #[test]
    fn duration_hours_mins() {
        assert_eq!(duration(130), "2 hours and 10 minutes");
    }

    #[test]
    fn table() {
        let mut table = Table::new(["a".into(), "b".into()]);
        table.add_row(["a1".into(), "b1".into()]);
        table.add_row(["a2".into(), "b2".into()]);
        assert_eq!(
            format!("{}", table),
            "| a | b |\n| - | - |\n| a1 | b1 |\n| a2 | b2 |\n"
        );
    }
}


================================================
FILE: mdbook-course/src/replacements.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::course::{Course, Courses, Segment, Session};
use mdbook::book::Chapter;
use regex::Regex;

lazy_static::lazy_static! {
    static ref DIRECTIVE: Regex = Regex::new(r#"\{\{%([^}]*)}}"#).unwrap();
}

/// Replace supported directives with the relevant content.
///
/// See the mdbook-course README for details.
#[allow(unused_variables)]
pub fn replace(
    courses: &Courses,
    course: Option<&Course>,
    session: Option<&Session>,
    segment: Option<&Segment>,
    chapter: &mut Chapter,
) {
    let Some(source_path) = &chapter.source_path else {
        return;
    };
    chapter.content = DIRECTIVE
        .replace_all(&chapter.content, |captures: &regex::Captures| {
            let directive_str = captures[1].trim();
            let directive: Vec<_> = directive_str.split_whitespace().collect();
            match directive.as_slice() {
                ["session", "outline"] if session.is_some() => {
                    session.unwrap().outline()
                }
                ["segment", "outline"] if segment.is_some() => {
                    segment.unwrap().outline()
                }
                ["course", "outline"] if course.is_some() => {
                    course.unwrap().schedule()
                }
                ["course", "outline", course_name @ ..] => {
                    let course_name = course_name.join(" ");
                    let Some(course) = courses.find_course(course_name) else {
                        return format!("not found - {}", &captures[0]);
                    };
                    course.schedule()
                }
                _ => directive_str.to_owned(),
            }
        })
        .to_string();
}


================================================
FILE: mdbook-course/src/timing_info.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::course::Slide;
use mdbook::book::Chapter;

/// Insert timing information for this slide into the speaker notes.
pub fn insert_timing_info(slide: &Slide, chapter: &mut Chapter) {
    if slide.minutes > 0
        && !slide.is_sub_chapter(chapter)
        && chapter.content.contains("<details>")
    {
        // Include the minutes in the speaker notes.
        let minutes = slide.minutes;
        let plural = if slide.minutes == 1 { "minute" } else { "minutes" };
        let mut subslides = "";
        if slide.source_paths.len() > 1 {
            subslides = "and its sub-slides ";
        }
        let timing_message =
            format!("This slide {subslides}should take about {minutes} {plural}. ");
        chapter.content = chapter
            .content
            .replace("<details>", &format!("<details>\n{timing_message}"));
    }
}


================================================
FILE: mdbook-exerciser/Cargo.toml
================================================
[package]
name = "mdbook-exerciser"
version = "0.1.0"
authors = ["Andrew Walbran <qwandor@google.com>"]
edition = "2024"
license = "Apache-2.0"
repository = "https://github.com/google/comprehensive-rust"
description = "A tool for extracting starter code for exercises from Markdown files."

[dependencies]
anyhow = "1.0.102"
log = "0.4.29"
mdbook = "0.4.52"
pretty_env_logger = "0.5.0"
pulldown-cmark = { version = "0.13.1", default-features = false }


================================================
FILE: mdbook-exerciser/README.md
================================================
# exerciser

This is an mdBook renderer to generate templates for exercises from the Markdown
source. Given a Markdown file `example.md` with one or more sections like:

````markdown
<!-- File src/main.rs -->

```rust,compile_fail
{{#include example/src/main.rs:main}}

fn some_more_code() {
    // TODO: Write some Rust code here.
}
```
````

and mdbook configuration in `book.toml` like:

```toml
[output.exerciser]
output-directory = "comprehensive-rust-exercises"
```

It will create a file
`book/exerciser/comprehensive-rust-exercises/example/src/main.rs` with the
appropriate contents.


================================================
FILE: mdbook-exerciser/src/lib.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use log::{info, trace};
use pulldown_cmark::{Event, Parser, Tag, TagEnd};
use std::fs::{File, create_dir_all};
use std::io::Write;
use std::path::Path;

const FILENAME_START: &str = "<!-- File ";
const FILENAME_END: &str = " -->";

pub fn process(output_directory: &Path, input_contents: &str) -> anyhow::Result<()> {
    let parser = Parser::new(input_contents);

    // Find a specially-formatted comment followed by a code block, and then call
    // `write_output` with the contents of the code block, to write to a file
    // named by the comment. Code blocks without matching comments will be
    // ignored, as will comments which are not followed by a code block.
    let mut next_filename: Option<String> = None;
    let mut current_file: Option<File> = None;
    for event in parser {
        trace!("{:?}", event);
        match event {
            Event::Html(html) => {
                let html = html.trim();
                if html.starts_with(FILENAME_START) && html.ends_with(FILENAME_END) {
                    next_filename = Some(
                        html[FILENAME_START.len()..html.len() - FILENAME_END.len()]
                            .to_string(),
                    );
                    info!("Next file: {:?}:", next_filename);
                }
            }
            Event::Start(Tag::CodeBlock(x)) => {
                info!("Start {:?}", x);
                if let Some(filename) = &next_filename {
                    let full_filename = output_directory.join(filename);
                    info!("Opening {:?}", full_filename);
                    if let Some(directory) = full_filename.parent() {
                        create_dir_all(directory)?;
                    }
                    current_file = Some(File::create(full_filename)?);
                    next_filename = None;
                }
            }
            Event::Text(text) => {
                info!("Text: {:?}", text);
                if let Some(output_file) = &mut current_file {
                    output_file.write_all(text.as_bytes())?;
                }
            }
            Event::End(TagEnd::CodeBlock) => {
                info!("End");
                current_file = None;
            }
            _ => {}
        }
    }

    Ok(())
}


================================================
FILE: mdbook-exerciser/src/main.rs
================================================
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::Context;
use log::trace;
use mdbook::BookItem;
use mdbook::book::Book;
use mdbook::renderer::RenderContext;
use mdbook_exerciser::process;
use std::fs::{create_dir, remove_dir_all};
use std::io::stdin;
use std::path::Path;

fn main() -> anyhow::Result<()> {
    pretty_env_logger::init();

    let context = RenderContext::from_json(&mut stdin()).context("Parsing stdin")?;

    let config = context
        .config
        .get_renderer("exerciser")
        .context("Missing output.exerciser configuration")?;

    let output_directory = Path::new(
        config
            .get("output-directory")
            .context(
                "Missing output.exerciser.output-directory configuration value",
            )?
            .as_str()
            .context("Expected a string for output.exerciser.output-directory")?,
    );

    let _ = remove_dir_all(output_directory);
    create_dir(output_directory).with_context(|| {
        format!("Failed to create output directory {:?}", output_directory)
    })?;

    process_all(&context.book, output_directory)?;

    Ok(())
}

fn process_all(book: &Book, output_directory: &Path) -> anyhow::Result<()> {
    for item in book.iter() {
        if let BookItem::Chapter(chapter) = item {
            trace!("Chapter {:?} / {:?}", chapter.path, chapter.source_path);
            if let Some(chapter_path) = &chapter.path {
                // Put the exercises in a subdirectory named after the chapter file,
                // without its parent directories.
                let chapter_output_directory =
                    output_directory.join(chapter_path.file_stem().with_context(
                        || format!("Chapter {:?} has no file stem", chapter_path),
                    )?);
                process(&chapter_output_directory, &chapter.content)?;
            }
        }
    }

    Ok(())
}


================================================
FILE: po/ar.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: Comprehensive Rust 🦀\n"
"POT-Creation-Date: 2024-07-09T12:20:23-07:00\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: ar\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#: src/SUMMARY.md src/index.md
msgid "Welcome to Comprehensive Rust 🦀"
msgstr "مرحبًا بكم في Comprehensive Rust 🦀"

#: src/SUMMARY.md src/running-the-course.md
msgid "Running the Course"
msgstr "تشغيل الدورة"

#: src/SUMMARY.md src/running-the-course/course-structure.md
msgid "Course Structure"
msgstr "هيكل الدورة"

#: src/SUMMARY.md src/running-the-course/keyboard-shortcuts.md
msgid "Keyboard Shortcuts"
msgstr "(keyboard shortcuts) اختصارات لوحة المفاتيح"

#: src/SUMMARY.md src/running-the-course/translations.md
msgid "Translations"
msgstr "الترجمات"

#: src/SUMMARY.md src/cargo.md
msgid "Using Cargo"
msgstr "استخدام Cargo"

#: src/SUMMARY.md
msgid "Rust Ecosystem"
msgstr "النظام البيئي ل Rust"

#: src/SUMMARY.md
msgid "Code Samples"
msgstr "(Code Samples) عينات الكود"

#: src/SUMMARY.md
msgid "Running Cargo Locally"
msgstr "تشغيل Cargo محليًا"

#: src/SUMMARY.md
msgid "Day 1: Morning"
msgstr "اليوم الأول: صباحا"

#: src/SUMMARY.md src/concurrency/welcome-async.md
msgid "Welcome"
msgstr "مرحبًا"

#: src/SUMMARY.md src/hello-world.md src/types-and-values/hello-world.md
msgid "Hello, World"
msgstr "مرحبًا، أيها العالم"

#: src/SUMMARY.md src/hello-world/what-is-rust.md
msgid "What is Rust?"
msgstr "ما هي Rust؟"

#: src/SUMMARY.md src/hello-world/benefits.md
msgid "Benefits of Rust"
msgstr "فوائد Rust"

#: src/SUMMARY.md src/hello-world/playground.md
msgid "Playground"
msgstr "مكان لتجربة اللغة (playground)"

#: src/SUMMARY.md src/types-and-values.md
msgid "Types and Values"
msgstr "الأنواع والقيم"

#: src/SUMMARY.md src/types-and-values/variables.md
msgid "Variables"
msgstr "المتغيرات"

#: src/SUMMARY.md src/types-and-values/values.md
msgid "Values"
msgstr "القيم"

#: src/SUMMARY.md src/types-and-values/arithmetic.md
msgid "Arithmetic"
msgstr "الحساب"

#: src/SUMMARY.md src/types-and-values/inference.md
msgid "Type Inference"
msgstr "استنباط النوع "

#: src/SUMMARY.md src/types-and-values/exercise.md
msgid "Exercise: Fibonacci"
msgstr "تمرين: فيبوناتشي"

#: src/SUMMARY.md src/types-and-values/solution.md
#: src/control-flow-basics/solution.md src/tuples-and-arrays/solution.md
#: src/references/solution.md src/user-defined-types/solution.md
#: src/pattern-matching/solution.md src/methods-and-traits/solution.md
#: src/generics/solution.md src/std-types/solution.md
#: src/std-traits/solution.md src/memory-management/solution.md
#: src/smart-pointers/solution.md src/borrowing/solution.md
#: src/lifetimes/solution.md src/iterators/solution.md src/modules/solution.md
#: src/testing/solution.md src/error-handling/solution.md
#: src/unsafe-rust/solution.md
msgid "Solution"
msgstr "الحل"

#: src/SUMMARY.md src/control-flow-basics.md
msgid "Control Flow Basics"
msgstr "أساسيات التحكم في التدفق"

#: src/SUMMARY.md
msgid "`if` Expressions"
msgstr "تعبيرات `if`"

#: src/SUMMARY.md src/control-flow-basics/loops.md
msgid "Loops"
msgstr "الحلقات"

#: src/SUMMARY.md src/control-flow-basics/loops/for.md
msgid "`for`"
msgstr "الحلقة `for`"

#: src/SUMMARY.md src/control-flow-basics/loops/loop.md
msgid "`loop`"
msgstr "حلقة"

#: src/SUMMARY.md src/control-flow-basics/break-continue.md
msgid "`break` and `continue`"
msgstr "كسر واستمرار"

#: src/SUMMARY.md src/control-flow-basics/break-continue/labels.md
msgid "Labels"
msgstr "تسميات"

#: src/SUMMARY.md src/control-flow-basics/blocks-and-scopes.md
msgid "Blocks and Scopes"
msgstr "الكتل والنطاقات"

#: src/SUMMARY.md src/control-flow-basics/blocks-and-scopes/scopes.md
msgid "Scopes and Shadowing"
msgstr "النطاقات والتظليل"

#: src/SUMMARY.md src/control-flow-basics/functions.md
msgid "Functions"
msgstr "الدوال"

#: src/SUMMARY.md src/control-flow-basics/macros.md
msgid "Macros"
msgstr "الماكروهات"

#: src/SUMMARY.md src/control-flow-basics/exercise.md
msgid "Exercise: Collatz Sequence"
msgstr "تمرين: تسلسل كولاتز"

#: src/SUMMARY.md
#, fuzzy
msgid "Day 1: Afternoon"
msgstr "اليوم الأول: صباحا"

#: src/SUMMARY.md src/tuples-and-arrays.md
#, fuzzy
msgid "Tuples and Arrays"
msgstr "الأنواع والقيم"

#: src/SUMMARY.md src/tuples-and-arrays/arrays.md
msgid "Arrays"
msgstr "المصفوفات"

#: src/SUMMARY.md src/tuples-and-arrays/tuples.md
msgid "Tuples"
msgstr "الصفوف"

#: src/SUMMARY.md src/tuples-and-arrays/iteration.md
msgid "Array Iteration"
msgstr "الدوران على عناصر المصفوفة"

#: src/SUMMARY.md src/tuples-and-arrays/destructuring.md
msgid "Patterns and Destructuring"
msgstr "الأنماط والتفكيك"

#: src/SUMMARY.md src/tuples-and-arrays/exercise.md
msgid "Exercise: Nested Arrays"
msgstr "تمرين: المصفوفات المتداخلة"

#: src/SUMMARY.md src/references.md
#, fuzzy
msgid "References"
msgstr "استنباط النوع "

#: src/SUMMARY.md src/references/shared.md
msgid "Shared References"
msgstr "مراجع مشتركة"

#: src/SUMMARY.md src/references/exclusive.md
msgid "Exclusive References"
msgstr "مراجع حصرية"

#: src/SUMMARY.md
msgid "Slices: `&[T]`"
msgstr "الشرائح: `&[T]`"

#: src/SUMMARY.md src/references/strings.md
msgid "Strings"
msgstr "السلاسل النصية"

#: src/SUMMARY.md src/references/exercise.md
msgid "Exercise: Geometry"
msgstr "تمرين: هندسة الأشكال"

#: src/SUMMARY.md src/user-defined-types.md
msgid "User-Defined Types"
msgstr "أنواع معرفة من قبل المستخدم"

#: src/SUMMARY.md src/user-defined-types/named-structs.md
msgid "Named Structs"
msgstr "هياكل مسماة"

#: src/SUMMARY.md src/user-defined-types/tuple-structs.md
#, fuzzy
msgid "Tuple Structs"
msgstr "هيكل الصفوف"

#: src/SUMMARY.md src/user-defined-types/enums.md
#: src/pattern-matching/destructuring-enums.md
msgid "Enums"
msgstr "التعدادات"

#: src/SUMMARY.md
msgid "Static"
msgstr "ثابت الذاكرة (Static)"

#: src/SUMMARY.md
msgid "Const"
msgstr "الثوابت (Const)"

#: src/SUMMARY.md src/user-defined-types/aliases.md
msgid "Type Aliases"
msgstr "أسماء مستعارة للنوع"

#: src/SUMMARY.md src/user-defined-types/exercise.md
msgid "Exercise: Elevator Events"
msgstr "تمرين: أحداث المصعد"

#: src/SUMMARY.md
#, fuzzy
msgid "Day 2: Morning"
msgstr "اليوم الثاني: صباحا"

#: src/SUMMARY.md src/pattern-matching.md
msgid "Pattern Matching"
msgstr "مطابقة الأنماط"

#: src/SUMMARY.md src/pattern-matching/match.md
msgid "Matching Values"
msgstr "مطابقة القيم"

#: src/SUMMARY.md
msgid "Destructuring Structs"
msgstr "تفكيك الهياكل"

#: src/SUMMARY.md
msgid "Destructuring Enums"
msgstr "تفكيك التعدادات"

#: src/SUMMARY.md src/pattern-matching/let-control-flow.md
msgid "Let Control Flow"
msgstr "دع التحكم في التدفق"

#: src/SUMMARY.md src/pattern-matching/exercise.md
#, fuzzy
msgid "Exercise: Expression Evaluation"
msgstr "تمرين: فيبوناتشي"

#: src/SUMMARY.md src/methods-and-traits.md
msgid "Methods and Traits"
msgstr ""

#: src/SUMMARY.md src/methods-and-traits/methods.md
msgid "Methods"
msgstr "الدوال"

#: src/SUMMARY.md src/methods-and-traits/traits.md
msgid "Traits"
msgstr "سمات"

#: src/SUMMARY.md src/methods-and-traits/traits/implementing.md
msgid "Implementing Traits"
msgstr "تنفيذ السمات"

#: src/SUMMARY.md src/methods-and-traits/traits/supertraits.md
msgid "Supertraits"
msgstr "السمات الفائقة"

#: src/SUMMARY.md src/methods-and-traits/traits/associated-types.md
msgid "Associated Types"
msgstr "الأنواع المرتبطة"

#: src/SUMMARY.md src/methods-and-traits/deriving.md
msgid "Deriving"
msgstr "اشتقاق"

#: src/SUMMARY.md
msgid "Exercise: Generic Logger"
msgstr "تمرين: مسجل عام"

#: src/SUMMARY.md
#, fuzzy
msgid "Day 2: Afternoon"
msgstr "اليوم الثاني: بعد الظهر"

#: src/SUMMARY.md src/generics.md
msgid "Generics"
msgstr "التعميم"

#: src/SUMMARY.md src/generics/generic-functions.md
msgid "Generic Functions"
msgstr "الدوال المعممة"

#: src/SUMMARY.md src/generics/generic-data.md
msgid "Generic Data Types"
msgstr "أنواع البيانات المعممة"

#: src/SUMMARY.md src/generics/generic-traits.md
msgid "Generic Traits"
msgstr "السمات المعممة"

#: src/SUMMARY.md src/generics/trait-bounds.md
msgid "Trait Bounds"
msgstr "حدود السمات"

#: src/SUMMARY.md src/generics/impl-trait.md
msgid "`impl Trait`"
msgstr "تطوير السمات `impl Trait`"

#: src/SUMMARY.md src/generics/dyn-trait.md
msgid "`dyn Trait`"
msgstr "تطوير السمات المتغيرة `dyn Trait`"

#: src/SUMMARY.md src/generics/exercise.md
#, fuzzy
msgid "Exercise: Generic `min`"
msgstr "تمرين: فيبوناتشي"

#: src/SUMMARY.md src/std-types.md
msgid "Standard Library Types"
msgstr "أنواع المكتبة القياسية"

#: src/SUMMARY.md src/std-types/std.md
msgid "Standard Library"
msgstr "المكتبة القياسية"

#: src/SUMMARY.md src/std-types/docs.md
msgid "Documentation"
msgstr "المستندات التوثيقية (Documentation)"

#: src/SUMMARY.md
msgid "`Option`"
msgstr "الخيار (`Option`)"

#: src/SUMMARY.md src/error-handling/result.md
msgid "`Result`"
msgstr "النتيجة (`Result`)"

#: src/SUMMARY.md src/android/aidl/types/primitives.md
#: src/android/interoperability/cpp/type-mapping.md
#, fuzzy
msgid "`String`"
msgstr "السلاسل النصية (`String`)"

#: src/SUMMARY.md src/std-types/vec.md
msgid "`Vec`"
msgstr "المصفوفات (`Vec`)"

#: src/SUMMARY.md src/std-types/hashmap.md src/bare-metal/no_std.md
msgid "`HashMap`"
msgstr "خريطة المشفرة (`HashMap`)"

#: src/SUMMARY.md src/std-types/exercise.md
#, fuzzy
msgid "Exercise: Counter"
msgstr "تمرين: عداد"

#: src/SUMMARY.md src/std-traits.md
msgid "Standard Library Traits"
msgstr "سمات المكتبة القياسية"

#: src/SUMMARY.md src/std-traits/comparisons.md
#: src/concurrency/welcome-async.md
msgid "Comparisons"
msgstr "مقارنات"

#: src/SUMMARY.md src/std-traits/operators.md
msgid "Operators"
msgstr "المشغلات (Operators)"

#: src/SUMMARY.md src/std-traits/from-and-into.md
msgid "`From` and `Into`"
msgstr "السمات (من و إلى) (`From` and `Into`)"

#: src/SUMMARY.md src/std-traits/casting.md
msgid "Casting"
msgstr "التحويل"

#: src/SUMMARY.md src/std-traits/read-and-write.md
msgid "`Read` and `Write`"
msgstr "السمات (القراءة و الكتابة) (`Read` and `Write`)"

#: src/SUMMARY.md
msgid "`Default`, struct update syntax"
msgstr "الإفتراضي، بناء جملة تحديث البنية (`Default`, struct update syntax)"

#: src/SUMMARY.md src/std-traits/closures.md
msgid "Closures"
msgstr "الإغلاقات"

#: src/SUMMARY.md src/std-traits/exercise.md
msgid "Exercise: ROT13"
msgstr "تمرين: ROT13"

#: src/SUMMARY.md
#, fuzzy
msgid "Day 3: Morning"
msgstr "اليوم الثالث: صباحا"

#: src/SUMMARY.md src/memory-management.md
msgid "Memory Management"
msgstr "إدارة الذاكرة"

#: src/SUMMARY.md src/memory-management/review.md
msgid "Review of Program Memory"
msgstr "مراجعة ذاكرة البرنامج"

#: src/SUMMARY.md src/memory-management/approaches.md
msgid "Approaches to Memory Management"
msgstr "طرق إدارة الذاكرة"

#: src/SUMMARY.md src/memory-management/ownership.md
msgid "Ownership"
msgstr "الملكية"

#: src/SUMMARY.md src/memory-management/move.md
msgid "Move Semantics"
msgstr "دلالات النقل"

#: src/SUMMARY.md
msgid "`Clone`"
msgstr "الاستنساخ"

#: src/SUMMARY.md src/memory-management/copy-types.md
msgid "Copy Types"
msgstr "أنواع النسخ"

#: src/SUMMARY.md
msgid "`Drop`"
msgstr "`Drop`"

#: src/SUMMARY.md src/memory-management/exercise.md
msgid "Exercise: Builder Type"
msgstr "تمرين: نمط البناء"

#: src/SUMMARY.md src/smart-pointers.md
msgid "Smart Pointers"
msgstr "المؤشرات الذكية"

#: src/SUMMARY.md src/smart-pointers/box.md
#: src/android/interoperability/cpp/type-mapping.md
msgid "`Box<T>`"
msgstr "`Box<T>`"

#: src/SUMMARY.md src/smart-pointers/rc.md
msgid "`Rc`"
msgstr "`Rc`"

#: src/SUMMARY.md src/smart-pointers/trait-objects.md
msgid "Owned Trait Objects"
msgstr "`(Owned Trait Objects)` كائنات السمات المملوكة"

#: src/SUMMARY.md src/smart-pointers/exercise.md
#, fuzzy
msgid "Exercise: Binary Tree"
msgstr "تمرين: فيبوناتشي"

#: src/SUMMARY.md
#, fuzzy
msgid "Day 3: Afternoon"
msgstr "اليوم الأول: صباحا"

#: src/SUMMARY.md src/borrowing.md
msgid "Borrowing"
msgstr "الاستعارة (Borrowing)"

#: src/SUMMARY.md src/borrowing/shared.md
msgid "Borrowing a Value"
msgstr "استعارة قيمة"

#: src/SUMMARY.md src/borrowing/borrowck.md
msgid "Borrow Checking"
msgstr "فحص الاستعارة (Borrow Checking)"

#: src/SUMMARY.md src/borrowing/examples.md
msgid "Borrow Errors"
msgstr "أخطاء الاستعارة (Borrow Errors)"

#: src/SUMMARY.md src/borrowing/interior-mutability.md
msgid "Interior Mutability"
msgstr "القابلية للتغيير الداخلي (Interior Mutability)"

#: src/SUMMARY.md src/borrowing/exercise.md
msgid "Exercise: Health Statistics"
msgstr "(Health Statistics) تمرين: إحصاءات الصحة"

#: src/SUMMARY.md src/lifetimes.md
msgid "Lifetimes"
msgstr "فترات الحياة (Lifetimes)"

#: src/SUMMARY.md src/lifetimes/lifetime-annotations.md
msgid "Lifetime Annotations"
msgstr "تعليقات فترة الحياة (Lifetime Annotations)"

#: src/SUMMARY.md
msgid "Lifetime Elision"
msgstr "حذف فترة الحياة (Lifetime Elision)"

#: src/SUMMARY.md
msgid "Struct Lifetimes"
msgstr "فترات حياة الهيكل (Struct Lifetimes)"

#: src/SUMMARY.md src/lifetimes/exercise.md
msgid "Exercise: Protobuf Parsing"
msgstr "تمرين: تحليل Protobuf (Protobuf Parsing)"

#: src/SUMMARY.md
#, fuzzy
msgid "Day 4: Morning"
msgstr "اليوم الأول: صباحا"

#: src/SUMMARY.md src/iterators.md
msgid "Iterators"
msgstr "المكررات (Iterators)"

#: src/SUMMARY.md src/iterators/iterator.md src/bare-metal/no_std.md
msgid "`Iterator`"
msgstr "`Iterator` (المكرر)"

#: src/SUMMARY.md src/iterators/intoiterator.md
msgid "`IntoIterator`"
msgstr "`IntoIterator` (إلى مكرر)"

#: src/SUMMARY.md
msgid "`FromIterator`"
msgstr "`FromIterator` (من مكرر)"

#: src/SUMMARY.md src/iterators/exercise.md
msgid "Exercise: Iterator Method Chaining"
msgstr "تمرين: تسلسل طرق المكرر (Iterator Method Chaining)"

#: src/SUMMARY.md src/modules.md src/modules/modules.md
msgid "Modules"
msgstr "الوحدات (Modules)"

#: src/SUMMARY.md src/modules/filesystem.md
msgid "Filesystem Hierarchy"
msgstr "التسلسل الهرمي لنظام الملفات (Filesystem Hierarchy)"

#: src/SUMMARY.md src/modules/visibility.md
msgid "Visibility"
msgstr "الرؤية (Visibility)"

#: src/SUMMARY.md
msgid "`use`, `super`, `self`"
msgstr "`use`, `super`, `self`"

#: src/SUMMARY.md src/modules/exercise.md
msgid "Exercise: Modules for a GUI Library"
msgstr ""
"تمرين: الوحدات لمكتبة واجهة المستخدم الرسومية (Modules for a GUI Library)"

#: src/SUMMARY.md src/testing.md src/chromium/testing.md
msgid "Testing"
msgstr "الاختبار (Testing)"

#: src/SUMMARY.md
msgid "Test Modules"
msgstr "وحدات الاختبار (Test Modules)"

#: src/SUMMARY.md src/testing/other.md
msgid "Other Types of Tests"
msgstr "أنواع أخرى من الاختبارات (Other Types of Tests)"

#: src/SUMMARY.md src/testing/lints.md
msgid "Compiler Lints and Clippy"
msgstr "التحذيرات البرمجية  (Compiler Lints) و Clippy"

#: src/SUMMARY.md src/testing/exercise.md
msgid "Exercise: Luhn Algorithm"
msgstr "تمرين: خوارزمية لون (Luhn Algorithm)"

#: src/SUMMARY.md
#, fuzzy
msgid "Day 4: Afternoon"
msgstr "اليوم الأول: صباحا"

#: src/SUMMARY.md src/error-handling.md
msgid "Error Handling"
msgstr "معالجة الأخطاء (Error Handling)"

#: src/SUMMARY.md src/error-handling/panics.md
msgid "Panics"
msgstr "Panics"

#: src/SUMMARY.md src/error-handling/try.md
msgid "Try Operator"
msgstr "مشغل المحاولة (Try Operator)"

#: src/SUMMARY.md src/error-handling/try-conversions.md
msgid "Try Conversions"
msgstr "محاولات التحويل (Try Conversions)"

#: src/SUMMARY.md
msgid "`Error` Trait"
msgstr "سمة `Error` (Error Trait)"

#: src/SUMMARY.md src/error-handling/thiserror-and-anyhow.md
msgid "`thiserror` and `anyhow`"
msgstr "`thiserror` و `anyhow`"

#: src/SUMMARY.md
msgid "Exercise: Rewriting with `Result`"
msgstr "تمرين: إعادة الكتابة باستخدام `Result`"

#: src/SUMMARY.md src/unsafe-rust.md src/unsafe-rust/unsafe.md
msgid "Unsafe Rust"
msgstr "Rust غير الآمنة (Unsafe Rust)"

#: src/SUMMARY.md
msgid "Unsafe"
msgstr "غير آمن (Unsafe)"

#: src/SUMMARY.md src/unsafe-rust/dereferencing.md
msgid "Dereferencing Raw Pointers"
msgstr "إلغاء مرجعية المؤشرات الخام (Dereferencing Raw Pointers)"

#: src/SUMMARY.md src/unsafe-rust/mutable-static.md
msgid "Mutable Static Variables"
msgstr "المتغيرات الثابتة القابلة للتغيير (Mutable Static Variables)"

#: src/SUMMARY.md src/unsafe-rust/unions.md
msgid "Unions"
msgstr "الاتحادات (Unions)"

#: src/SUMMARY.md src/unsafe-rust/unsafe-functions.md
msgid "Unsafe Functions"
msgstr "الدوال غير الآمنة (Unsafe Functions)"

#: src/SUMMARY.md
msgid "Unsafe Traits"
msgstr "السمات غير الآمنة (Unsafe Traits)"

#: src/SUMMARY.md
#, fuzzy
msgid "Exercise: FFI Wrapper"
msgstr "تمرين: فيبوناتشي"

#: src/SUMMARY.md src/bare-metal/android.md
msgid "Android"
msgstr "أندرويد (Android)"

#: src/SUMMARY.md src/android/setup.md src/chromium/setup.md
msgid "Setup"
msgstr "الإعداد (Setup)"

#: src/SUMMARY.md src/android/build-rules.md
msgid "Build Rules"
msgstr "قواعد البناء (Build Rules)"

#: src/SUMMARY.md
msgid "Binary"
msgstr "ثنائي (Binary)"

#: src/SUMMARY.md
msgid "Library"
msgstr "مكتبة (Library)"

#: src/SUMMARY.md src/android/aidl.md
msgid "AIDL"
msgstr "AIDL"

#: src/SUMMARY.md src/android/aidl/birthday-service.md
msgid "Birthday Service Tutorial"
msgstr "دليل خدمة عيد الميلاد (Birthday Service Tutorial)"

#: src/SUMMARY.md
msgid "Interface"
msgstr "الواجهة (Interface)"

#: src/SUMMARY.md
msgid "Service API"
msgstr "واجهة برمجة التطبيقات للخدمة (Service API)"

#: src/SUMMARY.md
msgid "Service"
msgstr "الخدمة (Service)"

#: src/SUMMARY.md
msgid "Server"
msgstr "الخادم (Server)"

#: src/SUMMARY.md src/android/aidl/example-service/deploy.md
msgid "Deploy"
msgstr "النشر (Deploy)"

#: src/SUMMARY.md
msgid "Client"
msgstr "العميل (Client)"

#: src/SUMMARY.md src/android/aidl/example-service/changing-definition.md
msgid "Changing API"
msgstr "تغيير واجهة برمجة التطبيقات (Changing API)"

#: src/SUMMARY.md
msgid "Updating Implementations"
msgstr "تحديث التنفيذات (Updating Implementations)"

#: src/SUMMARY.md
msgid "AIDL Types"
msgstr "أنواع AIDL (AIDL Types)"

#: src/SUMMARY.md src/android/aidl/types/primitives.md
msgid "Primitive Types"
msgstr "الأنواع الأولية (Primitive Types)"

#: src/SUMMARY.md src/android/aidl/types/arrays.md
msgid "Array Types"
msgstr "أنواع المصفوفات (Array Types)"

#: src/SUMMARY.md src/android/aidl/types/objects.md
msgid "Sending Objects"
msgstr "إرسال الكائنات (Sending Objects)"

#: src/SUMMARY.md src/android/aidl/types/parcelables.md
#, fuzzy
msgid "Parcelables"
msgstr "المتغيرات"

#: src/SUMMARY.md src/android/aidl/types/file-descriptor.md
msgid "Sending Files"
msgstr "إرسال الملفات (Sending Files)"

#: src/SUMMARY.md src/android/testing/googletest.md
msgid "GoogleTest"
msgstr "GoogleTest"

#: src/SUMMARY.md src/android/testing/mocking.md
msgid "Mocking"
msgstr "المحاكاة (Mocking)"

#: src/SUMMARY.md src/android/logging.md src/bare-metal/aps/logging.md
msgid "Logging"
msgstr "التسجيل (Logging)"

#: src/SUMMARY.md src/android/interoperability.md
msgid "Interoperability"
msgstr "قابلية التشغيل البيني (Interoperability)"

#: src/SUMMARY.md
msgid "With C"
msgstr "مع C (With C)"

#: src/SUMMARY.md
msgid "Calling C with Bindgen"
msgstr "استدعاء C باستخدام Bindgen (Calling C with Bindgen)"

#: src/SUMMARY.md
msgid "Calling Rust from C"
msgstr "استدعاء Rust من C (Calling Rust from C)"

#: src/SUMMARY.md src/android/interoperability/cpp.md
msgid "With C++"
msgstr "مع C++ (With C++)"

#: src/SUMMARY.md src/android/interoperability/cpp/bridge.md
msgid "The Bridge Module"
msgstr "وحدة الجسر (The Bridge Module)"

#: src/SUMMARY.md
msgid "Rust Bridge"
msgstr "جسر Rust (Rust Bridge)"

#: src/SUMMARY.md src/android/interoperability/cpp/generated-cpp.md
msgid "Generated C++"
msgstr "C++ المُولَّد (Generated C++)"

#: src/SUMMARY.md
msgid "C++ Bridge"
msgstr "جسر C++ (C++ Bridge)"

#: src/SUMMARY.md src/android/interoperability/cpp/shared-types.md
msgid "Shared Types"
msgstr "الأنواع المشتركة (Shared Types)"

#: src/SUMMARY.md src/android/interoperability/cpp/shared-enums.md
msgid "Shared Enums"
msgstr "التعدادات المشتركة (Shared Enums)"

#: src/SUMMARY.md src/android/interoperability/cpp/rust-result.md
msgid "Rust Error Handling"
msgstr "معالجة الأخطاء في Rust (Rust Error Handling)"

#: src/SUMMARY.md src/android/interoperability/cpp/cpp-exception.md
msgid "C++ Error Handling"
msgstr "معالجة الأخطاء في C++ (C++ Error Handling)"

#: src/SUMMARY.md src/android/interoperability/cpp/type-mapping.md
msgid "Additional Types"
msgstr "الأنواع الإضافية (Additional Types)"

#: src/SUMMARY.md
msgid "Building for Android: C++"
msgstr "البناء لأندرويد: C++ (Building for Android: C++)"

#: src/SUMMARY.md
msgid "Building for Android: Genrules"
msgstr "البناء لأندرويد: قواعد التوليد (Building for Android: Genrules)"

#: src/SUMMARY.md
msgid "Building for Android: Rust"
msgstr "البناء لأندرويد: Rust (Building for Android: Rust)"

#: src/SUMMARY.md
msgid "With Java"
msgstr "مع Java (With Java)"

#: src/SUMMARY.md src/exercises/android/morning.md
#: src/exercises/bare-metal/morning.md src/exercises/bare-metal/afternoon.md
#: src/concurrency/sync-exercises.md src/concurrency/async-exercises.md
msgid "Exercises"
msgstr "التمارين"

#: src/SUMMARY.md
msgid "Chromium"
msgstr "كروميوم (Chromium)"

#: src/SUMMARY.md src/chromium/cargo.md
msgid "Comparing Chromium and Cargo Ecosystems"
msgstr ""
"مقارنة بين بيئات Chromium و Cargo (Comparing Chromium and Cargo Ecosystems)"

#: src/SUMMARY.md
msgid "Policy"
msgstr "سياسة الاستخدام (Policy)"

#: src/SUMMARY.md
msgid "Unsafe Code"
msgstr "الكود غير الآمن (Unsafe Code)"

#: src/SUMMARY.md src/chromium/build-rules/depending.md
msgid "Depending on Rust Code from Chromium C++"
msgstr ""
"الاعتماد على كود Rust من Chromium C++ (Depending on Rust Code from Chromium "
"C++)"

#: src/SUMMARY.md src/chromium/build-rules/vscode.md
msgid "Visual Studio Code"
msgstr "فيجوال ستوديو كود (Visual Studio Code)"

#: src/SUMMARY.md src/exercises/chromium/third-party.md
msgid "Exercise"
msgstr "تمرين (Exercise)"

#: src/SUMMARY.md src/chromium/testing/rust-gtest-interop.md
msgid "`rust_gtest_interop` Library"
msgstr "مكتبة `rust_gtest_interop`"

#: src/SUMMARY.md src/chromium/testing/build-gn.md
msgid "GN Rules for Rust Tests"
msgstr "قواعد GN لاختبارات Rust (GN Rules for Rust Tests)"

#: src/SUMMARY.md src/chromium/testing/chromium-import-macro.md
msgid "`chromium::import!` Macro"
msgstr "ماكرو Macro `chromium::import!`"

#: src/SUMMARY.md src/chromium/interoperability-with-cpp.md
msgid "Interoperability with C++"
msgstr "التشغيل البيني مع C++ (Interoperability with C++)"

#: src/SUMMARY.md src/chromium/interoperability-with-cpp/example-bindings.md
msgid "Example Bindings"
msgstr "أمثلة على الربط (Example Bindings)"

#: src/SUMMARY.md src/chromium/interoperability-with-cpp/limitations-of-cxx.md
msgid "Limitations of CXX"
msgstr "قيود CXX"

#: src/SUMMARY.md src/chromium/interoperability-with-cpp/error-handling.md
msgid "CXX Error Handling"
msgstr "معالجة الأخطاء في CXX (CXX Error Handling)"

#: src/SUMMARY.md
msgid "Error Handling: QR Example"
msgstr "معالجة الأخطاء (Error Handling): مثال QR"

#: src/SUMMARY.md
msgid "Error Handling: PNG Example"
msgstr "معالجة الأخطاء: مثال PNG"

#: src/SUMMARY.md
msgid "Using CXX in Chromium"
msgstr "استخدام CXX في Chromium"

#: src/SUMMARY.md src/chromium/adding-third-party-crates.md
msgid "Adding Third Party Crates"
msgstr "إضافة كريت الطرف الثالث (third party Crates)"

#: src/SUMMARY.md
msgid "Configuring Cargo.toml"
msgstr "تهيئة Cargo.toml"

#: src/SUMMARY.md
#: src/chromium/adding-third-party-crates/configuring-gnrt-config-toml.md
msgid "Configuring `gnrt_config.toml`"
msgstr "تهيئة `gnrt_config.toml`"

#: src/SU
Download .txt
gitextract_wyjk7nt0/

├── .cargo/
│   └── config.toml
├── .github/
│   ├── CODEOWNERS
│   ├── dependabot.yml
│   ├── labeler.yml
│   ├── pandoc/
│   │   ├── README.md
│   │   ├── ja.yaml
│   │   ├── ko.yaml
│   │   ├── zh-CN.yaml
│   │   └── zh-TW.yaml
│   ├── typos.toml
│   └── workflows/
│       ├── apt-get-install/
│       │   └── action.yml
│       ├── build.sh
│       ├── build.yml
│       ├── check-msgid-changes.py
│       ├── check-msgid-changes.yml
│       ├── install-mdbook/
│       │   └── action.yml
│       ├── labeler.yml
│       ├── lint.yml
│       ├── publish.yml
│       └── setup-rust-cache/
│           └── action.yml
├── .gitignore
├── CONTRIBUTING.md
├── Cargo.toml
├── GEMINI.md
├── LICENSE
├── LICENSE-CC-BY
├── README.md
├── STYLE.md
├── TRANSLATIONS.md
├── book.toml
├── dprint.json
├── mdbook-course/
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── bin/
│       │   ├── course-content.rs
│       │   ├── course-schedule.rs
│       │   └── mdbook-course.rs
│       ├── course.rs
│       ├── frontmatter.rs
│       ├── lib.rs
│       ├── markdown.rs
│       ├── replacements.rs
│       └── timing_info.rs
├── mdbook-exerciser/
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── lib.rs
│       └── main.rs
├── po/
│   ├── ar.po
│   ├── bn.po
│   ├── da.po
│   ├── de.po
│   ├── el.po
│   ├── es.po
│   ├── fa.po
│   ├── fr.po
│   ├── id.po
│   ├── it.po
│   ├── ja.po
│   ├── ko.po
│   ├── pl.po
│   ├── pt-BR.po
│   ├── ro.po
│   ├── ru.po
│   ├── tr.po
│   ├── uk.po
│   ├── vi.po
│   ├── zh-CN.po
│   └── zh-TW.po
├── rustfmt.toml
├── src/
│   ├── README.md
│   ├── SUMMARY.md
│   ├── android/
│   │   ├── aidl/
│   │   │   ├── birthday-service.md
│   │   │   ├── birthday_service/
│   │   │   │   ├── Android.bp
│   │   │   │   ├── aidl/
│   │   │   │   │   ├── Android.bp
│   │   │   │   │   └── com/
│   │   │   │   │       └── example/
│   │   │   │   │           └── birthdayservice/
│   │   │   │   │               ├── BirthdayInfo.aidl
│   │   │   │   │               ├── IBirthdayInfoProvider.aidl
│   │   │   │   │               └── IBirthdayService.aidl
│   │   │   │   └── src/
│   │   │   │       ├── client.rs
│   │   │   │       ├── lib.rs
│   │   │   │       └── server.rs
│   │   │   ├── example-service/
│   │   │   │   ├── changing-definition.md
│   │   │   │   ├── changing-implementation.md
│   │   │   │   ├── client.md
│   │   │   │   ├── deploy.md
│   │   │   │   ├── implementation.md
│   │   │   │   ├── interface.md
│   │   │   │   ├── server.md
│   │   │   │   ├── service-bindings.md
│   │   │   │   └── service.md
│   │   │   ├── types/
│   │   │   │   ├── arrays.md
│   │   │   │   ├── file-descriptor.md
│   │   │   │   ├── objects.md
│   │   │   │   ├── parcelables.md
│   │   │   │   └── primitives.md
│   │   │   └── types.md
│   │   ├── aidl.md
│   │   ├── bpfmt.sh
│   │   ├── build-rules/
│   │   │   ├── binary/
│   │   │   │   ├── Android.bp
│   │   │   │   └── src/
│   │   │   │       └── main.rs
│   │   │   ├── binary.md
│   │   │   ├── library/
│   │   │   │   ├── Android.bp
│   │   │   │   └── src/
│   │   │   │       ├── lib.rs
│   │   │   │       └── main.rs
│   │   │   └── library.md
│   │   ├── build-rules.md
│   │   ├── build_all.sh
│   │   ├── interoperability/
│   │   │   ├── cpp/
│   │   │   │   ├── android-build-cpp.md
│   │   │   │   ├── android-build-rust.md
│   │   │   │   ├── android-cpp-genrules.md
│   │   │   │   ├── bridge.md
│   │   │   │   ├── cpp-bridge.md
│   │   │   │   ├── cpp-exception.md
│   │   │   │   ├── generated-cpp.md
│   │   │   │   ├── rust-bridge.md
│   │   │   │   ├── rust-result.md
│   │   │   │   ├── shared-enums.md
│   │   │   │   ├── shared-types.md
│   │   │   │   └── type-mapping.md
│   │   │   ├── cpp.md
│   │   │   ├── java/
│   │   │   │   ├── Android.bp
│   │   │   │   ├── HelloWorld.java
│   │   │   │   └── src/
│   │   │   │       └── lib.rs
│   │   │   ├── java.md
│   │   │   ├── with-c/
│   │   │   │   ├── bindgen/
│   │   │   │   │   ├── Android.bp
│   │   │   │   │   ├── c-library.md
│   │   │   │   │   ├── libbirthday.c
│   │   │   │   │   ├── libbirthday.h
│   │   │   │   │   ├── libbirthday_wrapper.h
│   │   │   │   │   └── main.rs
│   │   │   │   ├── bindgen.md
│   │   │   │   ├── c-library.md
│   │   │   │   ├── hand-written.md
│   │   │   │   ├── run-our-binary.md
│   │   │   │   ├── rust/
│   │   │   │   │   ├── analyze/
│   │   │   │   │   │   ├── Android.bp
│   │   │   │   │   │   └── main.c
│   │   │   │   │   └── libanalyze/
│   │   │   │   │       ├── Android.bp
│   │   │   │   │       ├── analyze.h
│   │   │   │   │       └── analyze.rs
│   │   │   │   ├── rust-library.md
│   │   │   │   └── rust.md
│   │   │   └── with-c.md
│   │   ├── interoperability.md
│   │   ├── logging/
│   │   │   ├── Android.bp
│   │   │   └── src/
│   │   │       └── main.rs
│   │   ├── logging.md
│   │   ├── setup.md
│   │   ├── testing/
│   │   │   ├── Android.bp
│   │   │   ├── Cargo.toml
│   │   │   ├── googletest.md
│   │   │   ├── googletest.rs
│   │   │   ├── mockall.rs
│   │   │   ├── mocking.md
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   └── testing.md
│   ├── android.md
│   ├── bare-metal/
│   │   ├── alloc-example/
│   │   │   ├── .cargo/
│   │   │   │   └── config.toml
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── main.rs
│   │   ├── alloc.md
│   │   ├── android/
│   │   │   └── vmbase.md
│   │   ├── android.md
│   │   ├── aps/
│   │   │   ├── aarch64-rt/
│   │   │   │   └── exceptions.md
│   │   │   ├── aarch64-rt.md
│   │   │   ├── better-uart/
│   │   │   │   ├── bitflags.md
│   │   │   │   ├── driver.md
│   │   │   │   └── registers.md
│   │   │   ├── better-uart.md
│   │   │   ├── entry-point.md
│   │   │   ├── examples/
│   │   │   │   ├── .cargo/
│   │   │   │   │   └── config.toml
│   │   │   │   ├── Cargo.toml
│   │   │   │   ├── Makefile
│   │   │   │   ├── image.ld
│   │   │   │   └── src/
│   │   │   │       ├── asm.rs
│   │   │   │       ├── entry.S
│   │   │   │       ├── exceptions.S
│   │   │   │       ├── exceptions.rs
│   │   │   │       ├── exceptions_rt.rs
│   │   │   │       ├── idmap.S
│   │   │   │       ├── logger.rs
│   │   │   │       ├── main_improved.rs
│   │   │   │       ├── main_logger.rs
│   │   │   │       ├── main_minimal.rs
│   │   │   │       ├── main_psci.rs
│   │   │   │       ├── main_rt.rs
│   │   │   │       ├── main_safemmio.rs
│   │   │   │       ├── pl011.rs
│   │   │   │       ├── pl011_minimal.rs
│   │   │   │       └── pl011_struct.rs
│   │   │   ├── exceptions.md
│   │   │   ├── inline-assembly.md
│   │   │   ├── logging/
│   │   │   │   └── using.md
│   │   │   ├── logging.md
│   │   │   ├── mmio.md
│   │   │   ├── other-projects.md
│   │   │   ├── safemmio/
│   │   │   │   ├── driver.md
│   │   │   │   ├── registers.md
│   │   │   │   └── using.md
│   │   │   ├── uart/
│   │   │   │   ├── traits.md
│   │   │   │   └── using.md
│   │   │   └── uart.md
│   │   ├── aps.md
│   │   ├── microcontrollers/
│   │   │   ├── board-support.md
│   │   │   ├── debugging.md
│   │   │   ├── embedded-hal.md
│   │   │   ├── examples/
│   │   │   │   ├── .cargo/
│   │   │   │   │   └── config.toml
│   │   │   │   ├── Cargo.toml
│   │   │   │   ├── Embed.toml
│   │   │   │   └── src/
│   │   │   │       └── bin/
│   │   │   │           ├── board_support.rs
│   │   │   │           ├── hal.rs
│   │   │   │           ├── interrupts/
│   │   │   │           │   └── mod.rs
│   │   │   │           ├── minimal.rs
│   │   │   │           ├── mmio.rs
│   │   │   │           ├── pac.rs
│   │   │   │           └── typestate.rs
│   │   │   ├── hals.md
│   │   │   ├── mmio.md
│   │   │   ├── other-projects.md
│   │   │   ├── pacs.md
│   │   │   ├── probe-rs.md
│   │   │   └── type-state.md
│   │   ├── microcontrollers.md
│   │   ├── minimal.md
│   │   ├── no_std.md
│   │   ├── useful-crates/
│   │   │   ├── aarch64-paging.md
│   │   │   ├── allocator-example/
│   │   │   │   ├── Cargo.toml
│   │   │   │   └── src/
│   │   │   │       └── main.rs
│   │   │   ├── buddy_system_allocator.md
│   │   │   ├── spin.md
│   │   │   ├── tinyvec.md
│   │   │   ├── zerocopy-example/
│   │   │   │   ├── Cargo.toml
│   │   │   │   └── src/
│   │   │   │       └── main.rs
│   │   │   └── zerocopy.md
│   │   └── useful-crates.md
│   ├── bare-metal.md
│   ├── borrowing/
│   │   ├── Cargo.toml
│   │   ├── borrowck.md
│   │   ├── examples.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── interior-mutability/
│   │   │   ├── cell.md
│   │   │   └── refcell.md
│   │   ├── interior-mutability.md
│   │   ├── shared.md
│   │   └── solution.md
│   ├── borrowing.md
│   ├── cargo/
│   │   ├── code-samples.md
│   │   ├── running-locally.md
│   │   └── rust-ecosystem.md
│   ├── cargo.md
│   ├── chromium/
│   │   ├── adding-third-party-crates/
│   │   │   ├── checking-in.md
│   │   │   ├── configuring-cargo-toml.md
│   │   │   ├── configuring-gnrt-config-toml.md
│   │   │   ├── depending-on-a-crate.md
│   │   │   ├── downloading-crates.md
│   │   │   ├── generating-gn-build-rules.md
│   │   │   ├── keeping-up-to-date.md
│   │   │   ├── resolving-problems/
│   │   │   │   ├── build-scripts-which-generate-code.md
│   │   │   │   └── build-scripts-which-take-arbitrary-actions.md
│   │   │   ├── resolving-problems.md
│   │   │   └── reviews-and-audits.md
│   │   ├── adding-third-party-crates.md
│   │   ├── build-rules/
│   │   │   ├── depending.md
│   │   │   ├── unsafe.md
│   │   │   └── vscode.md
│   │   ├── build-rules.md
│   │   ├── cargo.md
│   │   ├── interoperability-with-cpp/
│   │   │   ├── error-handling-png.md
│   │   │   ├── error-handling-qr.md
│   │   │   ├── error-handling.md
│   │   │   ├── example-bindings.md
│   │   │   ├── limitations-of-cxx.md
│   │   │   └── using-cxx-in-chromium.md
│   │   ├── interoperability-with-cpp.md
│   │   ├── policy.md
│   │   ├── setup.md
│   │   ├── testing/
│   │   │   ├── build-gn.md
│   │   │   ├── chromium-import-macro.md
│   │   │   └── rust-gtest-interop.md
│   │   └── testing.md
│   ├── chromium.md
│   ├── closures/
│   │   ├── capturing.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── solution.md
│   │   ├── syntax.md
│   │   └── traits.md
│   ├── closures.md
│   ├── concurrency/
│   │   ├── async/
│   │   │   ├── async-await.md
│   │   │   ├── futures.md
│   │   │   ├── runtimes/
│   │   │   │   └── tokio.md
│   │   │   ├── runtimes.md
│   │   │   ├── state-machine.md
│   │   │   └── tasks.md
│   │   ├── async-control-flow/
│   │   │   ├── channels.md
│   │   │   ├── join.md
│   │   │   └── select.md
│   │   ├── async-control-flow.md
│   │   ├── async-exercises/
│   │   │   ├── afternoon.md
│   │   │   ├── chat-app.md
│   │   │   ├── chat-async/
│   │   │   │   ├── Cargo.toml
│   │   │   │   └── src/
│   │   │   │       └── bin/
│   │   │   │           ├── client.rs
│   │   │   │           └── server.rs
│   │   │   ├── dining-philosophers.md
│   │   │   ├── dining-philosophers.rs
│   │   │   └── solutions.md
│   │   ├── async-exercises.md
│   │   ├── async-pitfalls/
│   │   │   ├── async-traits.md
│   │   │   ├── blocking-executor.md
│   │   │   ├── cancellation.md
│   │   │   └── pin.md
│   │   ├── async-pitfalls.md
│   │   ├── async.md
│   │   ├── channels/
│   │   │   ├── bounded.md
│   │   │   ├── senders-receivers.md
│   │   │   └── unbounded.md
│   │   ├── channels.md
│   │   ├── send-sync/
│   │   │   ├── examples.md
│   │   │   ├── marker-traits.md
│   │   │   ├── send.md
│   │   │   └── sync.md
│   │   ├── send-sync.md
│   │   ├── shared-state/
│   │   │   ├── arc.md
│   │   │   ├── example.md
│   │   │   └── mutex.md
│   │   ├── shared-state.md
│   │   ├── sync-exercises/
│   │   │   ├── Cargo.toml
│   │   │   ├── dining-philosophers.md
│   │   │   ├── dining-philosophers.rs
│   │   │   ├── link-checker.md
│   │   │   ├── link-checker.rs
│   │   │   └── solutions.md
│   │   ├── sync-exercises.md
│   │   ├── threads/
│   │   │   ├── plain.md
│   │   │   └── scoped.md
│   │   ├── threads.md
│   │   ├── welcome-async.md
│   │   └── welcome.md
│   ├── control-flow-basics/
│   │   ├── Cargo.toml
│   │   ├── blocks-and-scopes.md
│   │   ├── break-continue/
│   │   │   └── labels.md
│   │   ├── break-continue.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── functions.md
│   │   ├── if.md
│   │   ├── loops/
│   │   │   ├── for.md
│   │   │   └── loop.md
│   │   ├── loops.md
│   │   ├── macros.md
│   │   ├── match.md
│   │   └── solution.md
│   ├── control-flow-basics.md
│   ├── credits.md
│   ├── error-handling/
│   │   ├── Cargo.toml
│   │   ├── anyhow.md
│   │   ├── error.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── panics.md
│   │   ├── result.md
│   │   ├── solution.md
│   │   ├── thiserror.md
│   │   ├── try-conversions.md
│   │   └── try.md
│   ├── error-handling.md
│   ├── exercises/
│   │   ├── bare-metal/
│   │   │   ├── afternoon.md
│   │   │   ├── compass/
│   │   │   │   ├── .cargo/
│   │   │   │   │   └── config.toml
│   │   │   │   ├── Cargo.toml
│   │   │   │   ├── Embed.toml
│   │   │   │   └── src/
│   │   │   │       └── main.rs
│   │   │   ├── compass.md
│   │   │   ├── morning.md
│   │   │   ├── rtc/
│   │   │   │   ├── .cargo/
│   │   │   │   │   └── config.toml
│   │   │   │   ├── Cargo.toml
│   │   │   │   ├── Makefile
│   │   │   │   ├── build.rs
│   │   │   │   ├── memory.ld
│   │   │   │   └── src/
│   │   │   │       ├── exceptions.rs
│   │   │   │       ├── logger.rs
│   │   │   │       ├── main.rs
│   │   │   │       └── pl031.rs
│   │   │   ├── rtc.md
│   │   │   ├── solutions-afternoon.md
│   │   │   └── solutions-morning.md
│   │   └── chromium/
│   │       ├── bringing-it-together.md
│   │       ├── build-rules.md
│   │       ├── interoperability-with-cpp.md
│   │       ├── solutions.md
│   │       ├── testing.md
│   │       └── third-party.md
│   ├── generics/
│   │   ├── Cargo.toml
│   │   ├── dyn-trait.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── generic-data.md
│   │   ├── generic-functions.md
│   │   ├── generic-traits.md
│   │   ├── impl-trait.md
│   │   ├── solution.md
│   │   └── trait-bounds.md
│   ├── generics.md
│   ├── glossary.md
│   ├── hello-world/
│   │   ├── benefits.md
│   │   ├── playground.md
│   │   └── what-is-rust.md
│   ├── hello-world.md
│   ├── idiomatic/
│   │   ├── foundations-api-design/
│   │   │   ├── meaningful-doc-comments/
│   │   │   │   ├── anatomy-of-a-doc-comment.md
│   │   │   │   ├── avoid-redundancy.md
│   │   │   │   ├── exercise.md
│   │   │   │   ├── library-vs-application-docs.md
│   │   │   │   ├── name-drop-signpost.md
│   │   │   │   ├── what-isnt-docs.md
│   │   │   │   ├── what-why-not-how-where.md
│   │   │   │   └── who-are-you-writing-for.md
│   │   │   ├── meaningful-doc-comments.md
│   │   │   ├── predictable-api/
│   │   │   │   ├── common-traits/
│   │   │   │   │   ├── clone.md
│   │   │   │   │   ├── copy.md
│   │   │   │   │   ├── debug.md
│   │   │   │   │   ├── display.md
│   │   │   │   │   ├── from-into.md
│   │   │   │   │   ├── hash.md
│   │   │   │   │   ├── partialeq-eq.md
│   │   │   │   │   ├── partialord-ord.md
│   │   │   │   │   ├── serde.md
│   │   │   │   │   └── try-from-into.md
│   │   │   │   ├── common-traits.md
│   │   │   │   ├── naming-conventions/
│   │   │   │   │   ├── as-and-ref.md
│   │   │   │   │   ├── by.md
│   │   │   │   │   ├── exercise.md
│   │   │   │   │   ├── from.md
│   │   │   │   │   ├── get.md
│   │   │   │   │   ├── into.md
│   │   │   │   │   ├── into_inner.md
│   │   │   │   │   ├── is.md
│   │   │   │   │   ├── mut.md
│   │   │   │   │   ├── new.md
│   │   │   │   │   ├── push.md
│   │   │   │   │   ├── raw_parts.md
│   │   │   │   │   ├── to.md
│   │   │   │   │   ├── try.md
│   │   │   │   │   ├── unchecked.md
│   │   │   │   │   ├── with-closure.md
│   │   │   │   │   ├── with-constructor.md
│   │   │   │   │   ├── with-copy-setter.md
│   │   │   │   │   └── with-word.md
│   │   │   │   └── naming-conventions.md
│   │   │   └── predictable-api.md
│   │   ├── foundations-api-design.md
│   │   ├── leveraging-the-type-system/
│   │   │   ├── borrow-checker-invariants/
│   │   │   │   ├── aliasing-xor-mutability.md
│   │   │   │   ├── generalizing-ownership.md
│   │   │   │   ├── phantomdata-01-types.md
│   │   │   │   ├── phantomdata-02-types-implemented.md
│   │   │   │   ├── phantomdata-03-lifetimes.md
│   │   │   │   ├── phantomdata-04-borrowedfd.md
│   │   │   │   └── single-use-values.md
│   │   │   ├── borrow-checker-invariants.md
│   │   │   ├── extension-traits/
│   │   │   │   ├── extending-foreign-types.md
│   │   │   │   ├── extending-other-traits.md
│   │   │   │   ├── method-resolution-conflicts.md
│   │   │   │   ├── should-i-define-an-extension-trait.md
│   │   │   │   └── trait-method-conflicts.md
│   │   │   ├── extension-traits.md
│   │   │   ├── newtype-pattern/
│   │   │   │   ├── is-it-encapsulated.md
│   │   │   │   ├── parse-don-t-validate.md
│   │   │   │   └── semantic-confusion.md
│   │   │   ├── newtype-pattern.md
│   │   │   ├── raii/
│   │   │   │   ├── drop_bomb.md
│   │   │   │   ├── drop_bomb_forget.md
│   │   │   │   ├── drop_guards.md
│   │   │   │   ├── drop_option.md
│   │   │   │   ├── drop_skipped.md
│   │   │   │   ├── forget_and_drop.md
│   │   │   │   ├── mutex.md
│   │   │   │   └── scope_guard.md
│   │   │   ├── raii.md
│   │   │   ├── token-types/
│   │   │   │   ├── branded-01-motivation.md
│   │   │   │   ├── branded-02-phantomdata.md
│   │   │   │   ├── branded-03-impl.md
│   │   │   │   ├── branded-04-in-action.md
│   │   │   │   ├── mutex-guard.md
│   │   │   │   └── permission-tokens.md
│   │   │   ├── token-types.md
│   │   │   ├── typestate-pattern/
│   │   │   │   ├── typestate-advanced.md
│   │   │   │   ├── typestate-example.md
│   │   │   │   ├── typestate-generics/
│   │   │   │   │   ├── complete.md
│   │   │   │   │   ├── property.md
│   │   │   │   │   ├── root.md
│   │   │   │   │   └── struct.md
│   │   │   │   ├── typestate-generics.md
│   │   │   │   └── typestate-generics.rs
│   │   │   └── typestate-pattern.md
│   │   ├── leveraging-the-type-system.md
│   │   ├── polymorphism/
│   │   │   ├── from-oop-to-rust/
│   │   │   │   ├── composition.md
│   │   │   │   ├── dynamic-dispatch/
│   │   │   │   │   ├── any-trait.md
│   │   │   │   │   ├── dyn-compatible.md
│   │   │   │   │   ├── dyn-trait.md
│   │   │   │   │   ├── dyn-vs-generics.md
│   │   │   │   │   ├── heterogeneous.md
│   │   │   │   │   ├── limits.md
│   │   │   │   │   └── pitfalls.md
│   │   │   │   ├── inheritance.md
│   │   │   │   ├── problem-solving.md
│   │   │   │   ├── sealed-traits.md
│   │   │   │   ├── sealing-with-enums.md
│   │   │   │   ├── sticking-with-traits.md
│   │   │   │   ├── supertraits.md
│   │   │   │   ├── switch-perspective.md
│   │   │   │   └── why-no-inheritance.md
│   │   │   ├── from-oop-to-rust.md
│   │   │   ├── refresher/
│   │   │   │   ├── blanket-impls.md
│   │   │   │   ├── conditional-methods.md
│   │   │   │   ├── default-impls.md
│   │   │   │   ├── deriving-traits.md
│   │   │   │   ├── monomorphization.md
│   │   │   │   ├── orphan-rule.md
│   │   │   │   ├── sized.md
│   │   │   │   ├── supertraits.md
│   │   │   │   ├── trait-bounds.md
│   │   │   │   └── traits.md
│   │   │   └── refresher.md
│   │   ├── polymorphism.md
│   │   └── welcome.md
│   ├── index.md
│   ├── iterators/
│   │   ├── Cargo.toml
│   │   ├── collect.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── helpers.md
│   │   ├── intoiterator.md
│   │   ├── iterator.md
│   │   ├── motivation.md
│   │   └── solution.md
│   ├── iterators.md
│   ├── lifetimes/
│   │   ├── Cargo.toml
│   │   ├── borrow-both.md
│   │   ├── borrow-one.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── lifetime-elision.md
│   │   ├── multiple-borrows.md
│   │   ├── returning-borrows.md
│   │   ├── simple-borrows.md
│   │   ├── solution.md
│   │   └── struct-lifetimes.md
│   ├── lifetimes.md
│   ├── memory-management/
│   │   ├── Cargo.toml
│   │   ├── approaches.md
│   │   ├── clone.md
│   │   ├── copy-types.md
│   │   ├── drop.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── move.md
│   │   ├── ownership.md
│   │   ├── review.md
│   │   └── solution.md
│   ├── memory-management.md
│   ├── methods-and-traits/
│   │   ├── Cargo.toml
│   │   ├── deriving.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── methods.md
│   │   ├── solution.md
│   │   ├── traits/
│   │   │   ├── associated-types.md
│   │   │   ├── implementing.md
│   │   │   └── supertraits.md
│   │   └── traits.md
│   ├── methods-and-traits.md
│   ├── modules/
│   │   ├── Cargo.toml
│   │   ├── encapsulation.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── filesystem.md
│   │   ├── modules.md
│   │   ├── paths.md
│   │   ├── solution.md
│   │   └── visibility.md
│   ├── modules.md
│   ├── other-resources.md
│   ├── pattern-matching/
│   │   ├── Cargo.toml
│   │   ├── destructuring-enums.md
│   │   ├── destructuring-structs.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── infallible.md
│   │   ├── let-control-flow/
│   │   │   ├── if-let.md
│   │   │   ├── let-else.md
│   │   │   └── while-let.md
│   │   ├── let-control-flow.md
│   │   ├── match.md
│   │   └── solution.md
│   ├── pattern-matching.md
│   ├── references/
│   │   ├── Cargo.toml
│   │   ├── dangling.md
│   │   ├── exclusive.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── shared.md
│   │   ├── slices.md
│   │   ├── solution.md
│   │   └── strings.md
│   ├── references.md
│   ├── running-the-course/
│   │   ├── course-structure.md
│   │   ├── keyboard-shortcuts.md
│   │   └── translations.md
│   ├── running-the-course.md
│   ├── smart-pointers/
│   │   ├── Cargo.toml
│   │   ├── box.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── rc.md
│   │   ├── solution.md
│   │   └── trait-objects.md
│   ├── smart-pointers.md
│   ├── std-traits/
│   │   ├── Cargo.toml
│   │   ├── casting.md
│   │   ├── comparisons.md
│   │   ├── default.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── from-and-into.md
│   │   ├── operators.md
│   │   ├── read-and-write.md
│   │   └── solution.md
│   ├── std-traits.md
│   ├── std-types/
│   │   ├── Cargo.toml
│   │   ├── docs.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── hashmap.md
│   │   ├── option.md
│   │   ├── result.md
│   │   ├── solution.md
│   │   ├── std.md
│   │   ├── string.md
│   │   └── vec.md
│   ├── std-types.md
│   ├── testing/
│   │   ├── Cargo.toml
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── lints.md
│   │   ├── other.md
│   │   ├── solution.md
│   │   └── unit-tests.md
│   ├── testing.md
│   ├── thanks.md
│   ├── tuples-and-arrays/
│   │   ├── Cargo.toml
│   │   ├── arrays.md
│   │   ├── destructuring.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── iteration.md
│   │   ├── solution.md
│   │   └── tuples.md
│   ├── tuples-and-arrays.md
│   ├── types-and-values/
│   │   ├── Cargo.toml
│   │   ├── arithmetic.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── hello-world.md
│   │   ├── inference.md
│   │   ├── solution.md
│   │   ├── values.md
│   │   └── variables.md
│   ├── types-and-values.md
│   ├── unsafe-deep-dive/
│   │   ├── Cargo.toml
│   │   ├── case-studies/
│   │   │   └── intrusive-linked-list.md
│   │   ├── case-studies.md
│   │   ├── ffi/
│   │   │   ├── README.md
│   │   │   ├── abs.md
│   │   │   ├── c-library-example.md
│   │   │   ├── cpp-library-example.md
│   │   │   ├── language-differences/
│   │   │   │   ├── cpp-and-c.md
│   │   │   │   ├── representations.md
│   │   │   │   ├── rust-and-c.md
│   │   │   │   ├── rust-and-cpp.md
│   │   │   │   └── semantics.md
│   │   │   ├── language-differences.md
│   │   │   ├── language-interop.md
│   │   │   ├── rand.md
│   │   │   ├── strategies.md
│   │   │   └── type-safety.md
│   │   ├── ffi.md
│   │   ├── initialization/
│   │   │   ├── how-to-initialize-memory.md
│   │   │   ├── maybeuninit/
│   │   │   │   ├── arrays.md
│   │   │   │   ├── write-vs-assignment.md
│   │   │   │   └── zeroed-method.md
│   │   │   ├── maybeuninit.md
│   │   │   └── partial-initialization.md
│   │   ├── initialization.md
│   │   ├── introduction/
│   │   │   ├── characteristics-of-unsafe-rust/
│   │   │   │   ├── dangerous.md
│   │   │   │   ├── sometimes-necessary.md
│   │   │   │   └── sometimes-useful.md
│   │   │   ├── characteristics-of-unsafe-rust.md
│   │   │   ├── defining-unsafe-rust.md
│   │   │   ├── definition.md
│   │   │   ├── impact-on-workflow.md
│   │   │   ├── may_overflow.md
│   │   │   ├── purpose.md
│   │   │   ├── responsibility-shift.md
│   │   │   ├── two-roles.md
│   │   │   ├── warm-up/
│   │   │   │   ├── unsafe-block.md
│   │   │   │   ├── unsafe-fn.md
│   │   │   │   ├── unsafe-impl.md
│   │   │   │   └── unsafe-trait.md
│   │   │   └── warm-up.md
│   │   ├── introduction.md
│   │   ├── memory-lifecycle.md
│   │   ├── motivations.md
│   │   ├── pinning/
│   │   │   ├── README.md
│   │   │   ├── definition-of-pin.md
│   │   │   ├── drop-and-not-unpin-worked-example.md
│   │   │   ├── phantompinned.md
│   │   │   ├── pin-and-drop.md
│   │   │   ├── self-referential-buffer/
│   │   │   │   ├── cpp.md
│   │   │   │   ├── rust-offset.md
│   │   │   │   ├── rust-pin.md
│   │   │   │   ├── rust-raw-pointers.md
│   │   │   │   └── rust.md
│   │   │   ├── self-referential-buffer.md
│   │   │   ├── unpin-trait.md
│   │   │   ├── what-a-move-is.md
│   │   │   ├── what-pinning-is.md
│   │   │   └── why-difficult.md
│   │   ├── pinning.md
│   │   ├── rules-of-the-game/
│   │   │   ├── 3-shapes-of-sound-rust.md
│   │   │   ├── copying-memory/
│   │   │   │   ├── crying-wolf.md
│   │   │   │   ├── documented-safety-preconditions.md
│   │   │   │   ├── encapsulated-unsafe.md
│   │   │   │   ├── exposed-unsafe.md
│   │   │   │   └── safe.md
│   │   │   ├── copying-memory.md
│   │   │   ├── rust-is-sound.md
│   │   │   ├── soundness-proof/
│   │   │   │   ├── corollary.md
│   │   │   │   ├── soundness.md
│   │   │   │   └── unsoundness.md
│   │   │   └── soundness-proof.md
│   │   ├── rules-of-the-game.md
│   │   ├── safety-preconditions/
│   │   │   ├── ascii.md
│   │   │   ├── common-preconditions.md
│   │   │   ├── defining.md
│   │   │   ├── determining.md
│   │   │   ├── getter.md
│   │   │   ├── references.md
│   │   │   ├── semantic-preconditions.md
│   │   │   └── u8-to-bool.md
│   │   ├── safety-preconditions.md
│   │   ├── setup.md
│   │   └── welcome.md
│   ├── unsafe-rust/
│   │   ├── Cargo.toml
│   │   ├── dereferencing.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── mutable-static.md
│   │   ├── solution.md
│   │   ├── unions.md
│   │   ├── unsafe-functions/
│   │   │   ├── calling.md
│   │   │   ├── extern-c.md
│   │   │   └── rust.md
│   │   ├── unsafe-functions.md
│   │   ├── unsafe-traits.md
│   │   └── unsafe.md
│   ├── unsafe-rust.md
│   ├── user-defined-types/
│   │   ├── Cargo.toml
│   │   ├── aliases.md
│   │   ├── const.md
│   │   ├── enums.md
│   │   ├── exercise.md
│   │   ├── exercise.rs
│   │   ├── named-structs.md
│   │   ├── solution.md
│   │   ├── static.md
│   │   └── tuple-structs.md
│   ├── user-defined-types.md
│   ├── welcome-day-1-afternoon.md
│   ├── welcome-day-1.md
│   ├── welcome-day-2-afternoon.md
│   ├── welcome-day-2.md
│   ├── welcome-day-3-afternoon.md
│   ├── welcome-day-3.md
│   ├── welcome-day-4-afternoon.md
│   └── welcome-day-4.md
├── tests/
│   ├── README.md
│   ├── package.json
│   ├── src/
│   │   ├── generic-page.test.ts
│   │   ├── objects/
│   │   │   ├── playground.ts
│   │   │   └── slide.ts
│   │   ├── playground.test.ts
│   │   ├── redbox.test.ts
│   │   ├── slide-style-guide.test.ts
│   │   ├── slides/
│   │   │   ├── slide-exemptions.list.ts
│   │   │   └── slides.list.ts
│   │   └── speaker-notes.test.ts
│   ├── tsconfig.json
│   ├── wdio.conf-mdbook.ts
│   └── wdio.conf.ts
├── theme/
│   ├── book.js
│   ├── css/
│   │   ├── language-picker.css
│   │   ├── redbox.css
│   │   ├── rtl.css
│   │   ├── speaker-notes.css
│   │   └── svgbob.css
│   ├── head.hbs
│   ├── index.hbs
│   ├── redbox.js
│   ├── save-playgrounds.js
│   └── speaker-notes.js
├── third_party/
│   ├── README.md
│   ├── cxx/
│   │   ├── LICENSE-APACHE
│   │   ├── LICENSE-MIT
│   │   ├── README.md
│   │   ├── blobstore/
│   │   │   ├── Android.bp
│   │   │   ├── BUILD
│   │   │   ├── Cargo.toml
│   │   │   ├── build.rs
│   │   │   ├── include/
│   │   │   │   └── blobstore.h
│   │   │   └── src/
│   │   │       ├── blobstore.cc
│   │   │       └── main.rs
│   │   └── book/
│   │       ├── snippets.cc
│   │       └── snippets.rs
│   └── mdbook/
│       ├── LICENSE
│       └── README.md
└── xtask/
    ├── Cargo.toml
    ├── README.md
    └── src/
        └── main.rs
Download .txt
SYMBOL INDEX (84 symbols across 11 files)

FILE: mdbook-course/src/bin/course-content.rs
  function main (line 21) | fn main() {

FILE: mdbook-course/src/bin/course-schedule.rs
  function main (line 21) | fn main() {
  function timediff (line 42) | fn timediff(actual: u64, target: u64, slop: u64) -> String {
  function session_summary (line 56) | fn session_summary(courses: &Courses) {
  function pr_summary (line 76) | fn pr_summary(courses: &Courses) {

FILE: mdbook-course/src/bin/mdbook-course.rs
  function main (line 24) | fn main() {
  function preprocess (line 44) | fn preprocess() -> anyhow::Result<()> {

FILE: mdbook-course/src/course.rs
  constant BREAK_DURATION (line 46) | const BREAK_DURATION: u64 = 10;
  type Courses (line 53) | pub struct Courses {
    method extract_structure (line 104) | pub fn extract_structure(mut book: Book) -> anyhow::Result<(Self, Book...
    method course_mut (line 157) | fn course_mut(&mut self, name: impl AsRef<str>) -> &mut Course {
    method find_course (line 170) | pub fn find_course(&self, name: impl AsRef<str>) -> Option<&Course> {
    method find_slide (line 177) | pub fn find_slide(
  type Course (line 62) | pub struct Course {
    method new (line 209) | fn new(name: impl Into<String>) -> Self {
    method session_mut (line 215) | fn session_mut(&mut self, name: impl AsRef<str>) -> &mut Session {
    method minutes (line 232) | pub fn minutes(&self) -> u64 {
    method target_minutes (line 241) | pub fn target_minutes(&self) -> u64 {
    method schedule (line 247) | pub fn schedule(&self) -> String {
  type Session (line 73) | pub struct Session {
    method new (line 282) | fn new(name: impl Into<String>) -> Self {
    method add_segment (line 287) | fn add_segment(
    method outline (line 309) | pub fn outline(&self) -> String {
    method minutes (line 326) | pub fn minutes(&self) -> u64 {
    method target_minutes (line 340) | pub fn target_minutes(&self) -> u64 {
  type Segment (line 83) | pub struct Segment {
    method new (line 355) | fn new(name: impl Into<String>) -> Self {
    method add_slide (line 361) | fn add_slide(
    method minutes (line 378) | pub fn minutes(&self) -> u64 {
    method outline (line 382) | pub fn outline(&self) -> String {
  type Slide (line 93) | pub struct Slide {
    method new (line 408) | fn new(frontmatter: Frontmatter, chapter: &Chapter) -> Self {
    method add_frontmatter (line 415) | fn add_frontmatter(&mut self, frontmatter: &Frontmatter) {
    method push_source_path (line 419) | fn push_source_path(&mut self, source_path: &Option<PathBuf>) {
    method add_sub_chapters (line 426) | fn add_sub_chapters(&mut self, chapter: &mut Chapter) -> anyhow::Resul...
    method is_sub_chapter (line 448) | pub fn is_sub_chapter(&self, chapter: &Chapter) -> bool {
    method minutes (line 455) | pub fn minutes(&self) -> u64 {
  type Item (line 200) | type Item = &'a Course;
  type IntoIter (line 201) | type IntoIter = std::slice::Iter<'a, Course>;
  method into_iter (line 203) | fn into_iter(self) -> Self::IntoIter {
  type Item (line 273) | type Item = &'a Session;
  type IntoIter (line 274) | type IntoIter = std::slice::Iter<'a, Session>;
  method into_iter (line 276) | fn into_iter(self) -> Self::IntoIter {
  type Item (line 346) | type Item = &'a Segment;
  type IntoIter (line 347) | type IntoIter = std::slice::Iter<'a, Segment>;
  method into_iter (line 349) | fn into_iter(self) -> Self::IntoIter {
  type Item (line 399) | type Item = &'a Slide;
  type IntoIter (line 400) | type IntoIter = std::slice::Iter<'a, Slide>;
  method into_iter (line 402) | fn into_iter(self) -> Self::IntoIter {

FILE: mdbook-course/src/frontmatter.rs
  type Frontmatter (line 22) | pub struct Frontmatter {
  function split_frontmatter (line 30) | pub fn split_frontmatter(

FILE: mdbook-course/src/markdown.rs
  function relative_link (line 21) | pub fn relative_link(
  function duration (line 45) | pub fn duration(mut minutes: u64) -> String {
  type Table (line 64) | pub struct Table<const N: usize> {
  function new (line 70) | pub fn new(header: [String; N]) -> Self {
  function add_row (line 74) | pub fn add_row(&mut self, row: [String; N]) {
  function write_row (line 78) | fn write_row<'a, I: Iterator<Item = &'a str>>(
  function fmt (line 92) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  function relative_link_same_dir (line 107) | fn relative_link_same_dir() {
  function relative_link_subdir (line 115) | fn relative_link_subdir() {
  function relative_link_parent_dir (line 126) | fn relative_link_parent_dir() {
  function relative_link_deep_parent_dir (line 137) | fn relative_link_deep_parent_dir() {
  function relative_link_peer_dir (line 148) | fn relative_link_peer_dir() {
  function duration_no_time (line 159) | fn duration_no_time() {
  function duration_single_minute (line 164) | fn duration_single_minute() {
  function duration_two_minutes (line 169) | fn duration_two_minutes() {
  function duration_seven_minutes (line 174) | fn duration_seven_minutes() {
  function duration_hour (line 179) | fn duration_hour() {
  function duration_hour_mins (line 184) | fn duration_hour_mins() {
  function duration_hours (line 189) | fn duration_hours() {
  function duration_hours_mins (line 194) | fn duration_hours_mins() {
  function table (line 199) | fn table() {

FILE: mdbook-course/src/replacements.rs
  function replace (line 28) | pub fn replace(

FILE: mdbook-course/src/timing_info.rs
  function insert_timing_info (line 20) | pub fn insert_timing_info(slide: &Slide, chapter: &mut Chapter) {

FILE: mdbook-exerciser/src/lib.rs
  constant FILENAME_START (line 22) | const FILENAME_START: &str = "<!-- File ";
  constant FILENAME_END (line 23) | const FILENAME_END: &str = " -->";
  function process (line 25) | pub fn process(output_directory: &Path, input_contents: &str) -> anyhow:...

FILE: mdbook-exerciser/src/main.rs
  function main (line 26) | fn main() -> anyhow::Result<()> {
  function process_all (line 56) | fn process_all(book: &Book, output_directory: &Path) -> anyhow::Result<(...

FILE: src/android/aidl/birthday_service/src/client.rs
  constant SERVICE_IDENTIFIER (line 28) | const SERVICE_IDENTIFIER: &str = "birthdayservice";
  function main (line 31) | fn main() -> Result<(), Box<dyn Error>> {
  type InfoProvider (line 81) | struct InfoProvider {
  method name (line 89) | fn name(&self) -> binder::Result<String> {
  method years (line 93) | fn years(&self) -> binder::Result<i32> {
Copy disabled (too large) Download .json
Condensed preview — 824 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (17,276K chars).
[
  {
    "path": ".cargo/config.toml",
    "chars": 255,
    "preview": "[alias]\nxtask = \"run --package xtask --\"\n\n[env]\n# To provide an anchor to the root of the workspace when working with pa"
  },
  {
    "path": ".github/CODEOWNERS",
    "chars": 1724,
    "preview": "# Translations\npo/ar.po @younies\npo/bn.po @mirwasi @sudiptachatterjee\npo/da.po @mgeisler @voss @thedataking\npo/de.po @ro"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 1893,
    "preview": "# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repositor"
  },
  {
    "path": ".github/labeler.yml",
    "chars": 1705,
    "preview": "translation:\n  - changed-files:\n      - any-glob-to-any-file: po/*.po\n\n\"translation/ar\":\n  - changed-files:\n      - any-"
  },
  {
    "path": ".github/pandoc/README.md",
    "chars": 179,
    "preview": "# Config Overrides for `mdbook-pandoc`\n\nThe configuration file fragments here are used to override the configuration in\n"
  },
  {
    "path": ".github/pandoc/ja.yaml",
    "chars": 119,
    "preview": "variables:\n  CJKmainfont: \"Noto Serif CJK JP\"\n  CJKsansfont: \"Noto Sans CJK JP\"\n  CJKmonofont: \"Noto Sans Mono CJK JP\"\n"
  },
  {
    "path": ".github/pandoc/ko.yaml",
    "chars": 119,
    "preview": "variables:\n  CJKmainfont: \"Noto Serif CJK KR\"\n  CJKsansfont: \"Noto Sans CJK KR\"\n  CJKmonofont: \"Noto Sans Mono CJK KR\"\n"
  },
  {
    "path": ".github/pandoc/zh-CN.yaml",
    "chars": 119,
    "preview": "variables:\n  CJKmainfont: \"Noto Serif CJK SC\"\n  CJKsansfont: \"Noto Sans CJK SC\"\n  CJKmonofont: \"Noto Sans Mono CJK SC\"\n"
  },
  {
    "path": ".github/pandoc/zh-TW.yaml",
    "chars": 119,
    "preview": "variables:\n  CJKmainfont: \"Noto Serif CJK TC\"\n  CJKsansfont: \"Noto Sans CJK TC\"\n  CJKmonofont: \"Noto Sans Mono CJK TC\"\n"
  },
  {
    "path": ".github/typos.toml",
    "chars": 402,
    "preview": "[default.extend-identifiers]\n# False positives.\nmis = \"mis\"\nMIS = \"MIS\"\ninout = \"inout\"\nesource = \"esource\"\nBARs = \"BARs"
  },
  {
    "path": ".github/workflows/apt-get-install/action.yml",
    "chars": 1356,
    "preview": "name: Setup Apt and Install Packages\ndescription: Configures apt, runs update once per job, and installs packages.\n\ninpu"
  },
  {
    "path": ".github/workflows/build.sh",
    "chars": 1900,
    "preview": "#!/usr/bin/env bash\nset -Eeuo pipefail\n\n# Usage: build.sh <book-lang> <dest-dir>\n#\n# Build the course as of the date spe"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 5489,
    "preview": "name: Test\npermissions:\n  contents: read\n\non:\n  pull_request:\n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\ne"
  },
  {
    "path": ".github/workflows/check-msgid-changes.py",
    "chars": 3331,
    "preview": "# Copyright 2023 Google LLC\n# SPDX-License-Identifier: Apache-2.0\n#\n# Licensed under the Apache License, Version 2.0 (th"
  },
  {
    "path": ".github/workflows/check-msgid-changes.yml",
    "chars": 442,
    "preview": "name: Prevent unintended msgid changes\npermissions:\n  contents: read\n\non:\n  pull_request:\n    paths:\n      - \"po/*.po\"\n\n"
  },
  {
    "path": ".github/workflows/install-mdbook/action.yml",
    "chars": 1008,
    "preview": "name: Install mdbook and dependencies\n\ndescription: Install mdbook with the dependencies we need.\n\nruns:\n  using: compos"
  },
  {
    "path": ".github/workflows/labeler.yml",
    "chars": 252,
    "preview": "name: \"Pull Request Labeler\"\non:\n  - pull_request_target\n\njobs:\n  triage:\n    permissions:\n      contents: read\n      pu"
  },
  {
    "path": ".github/workflows/lint.yml",
    "chars": 1186,
    "preview": "name: Lint\npermissions:\n  contents: read\n\non:\n  pull_request:\n  push:\n    branches:\n      - main\n\nenv:\n  CARGO_TERM_COLO"
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 2182,
    "preview": "name: Publish\n\n# See also TRANSLATIONS.md.\n\non:\n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\npermissions:\n  "
  },
  {
    "path": ".github/workflows/setup-rust-cache/action.yml",
    "chars": 521,
    "preview": "name: Setup Rust cache\n\ndescription: Configure the rust-cache workflow.\n\ninputs:\n  key:\n    description: Additional cach"
  },
  {
    "path": ".gitignore",
    "chars": 506,
    "preview": "# Build artifacts\n/book/\ntarget/\n*.bin\n\n# Translation artifacts\npo/*.mo\npo/*.po~\n\n# macOS artifacts\n.DS_Store\n\n# Jetbrai"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 4701,
    "preview": "# How to Contribute\n\nWe'd love to accept your patches and contributions to this project. There are\njust a few small guid"
  },
  {
    "path": "Cargo.toml",
    "chars": 808,
    "preview": "[workspace]\n# Please keep the workspace members sorted.\nmembers = [\n  \"mdbook-course\",\n  \"mdbook-exerciser\",\n  \"src/andr"
  },
  {
    "path": "GEMINI.md",
    "chars": 11785,
    "preview": "# Project Overview\n\nThis repository contains the source code for Comprehensive Rust, a family of\ncourses on Rust develop"
  },
  {
    "path": "LICENSE",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "LICENSE-CC-BY",
    "chars": 18653,
    "preview": "Attribution 4.0 International\n\n=======================================================================\n\nCreative Commons"
  },
  {
    "path": "README.md",
    "chars": 7999,
    "preview": "# Comprehensive Rust 🦀\n\n[![Build workflow](https://img.shields.io/github/actions/workflow/status/google/comprehensive-ru"
  },
  {
    "path": "STYLE.md",
    "chars": 17637,
    "preview": "# Comprehensive Rust 🦀 Style Guide\n\nThe course has been expanded and improved by tons of volunteers like you! Thank\nyou "
  },
  {
    "path": "TRANSLATIONS.md",
    "chars": 11387,
    "preview": "# Translations of Comprehensive Rust 🦀\n\nWe would love to have your help with translating the course into other\nlanguages"
  },
  {
    "path": "book.toml",
    "chars": 16034,
    "preview": "[book]\nauthors = [\"Martin Geisler\"]\nlanguage = \"en\"\nsrc = \"src\"\ntitle = \"Comprehensive Rust 🦀\"\n\n[rust]\nedition = \"2024\"\n"
  },
  {
    "path": "dprint.json",
    "chars": 797,
    "preview": "{\n  \"lineWidth\": 80,\n  \"json\": {},\n  \"markdown\": {\n    \"textWrap\": \"always\"\n  },\n  \"exec\": {\n    \"commands\": [{\n      \"c"
  },
  {
    "path": "mdbook-course/Cargo.toml",
    "chars": 513,
    "preview": "[package]\nname = \"mdbook-course\"\nversion = \"0.1.0\"\nauthors = [\"Dustin Mitchell <djmitche@google.com>\"]\nedition = \"2024\"\n"
  },
  {
    "path": "mdbook-course/README.md",
    "chars": 3009,
    "preview": "# mdbook-course\n\nThis is an mdBook preprocessor to handle some specific details of Comprehensive\nRust.\n\nIt provides thre"
  },
  {
    "path": "mdbook-course/src/bin/course-content.rs",
    "chars": 1657,
    "preview": "// Copyright 2024 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-course/src/bin/course-schedule.rs",
    "chars": 3152,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-course/src/bin/mdbook-course.rs",
    "chars": 2290,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-course/src/course.rs",
    "chars": 15803,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-course/src/frontmatter.rs",
    "chars": 1482,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-course/src/lib.rs",
    "chars": 726,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-course/src/markdown.rs",
    "chars": 5462,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-course/src/replacements.rs",
    "chars": 2325,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-course/src/timing_info.rs",
    "chars": 1489,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-exerciser/Cargo.toml",
    "chars": 452,
    "preview": "[package]\nname = \"mdbook-exerciser\"\nversion = \"0.1.0\"\nauthors = [\"Andrew Walbran <qwandor@google.com>\"]\nedition = \"2024\""
  },
  {
    "path": "mdbook-exerciser/README.md",
    "chars": 592,
    "preview": "# exerciser\n\nThis is an mdBook renderer to generate templates for exercises from the Markdown\nsource. Given a Markdown f"
  },
  {
    "path": "mdbook-exerciser/src/lib.rs",
    "chars": 2901,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "mdbook-exerciser/src/main.rs",
    "chars": 2501,
    "preview": "// Copyright 2023 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "po/ar.po",
    "chars": 629004,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-07-09T12:20:23-07:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/bn.po",
    "chars": 616094,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-03-03T20:37:57+05:30\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/da.po",
    "chars": 585177,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-01-24T13:24:49+01:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/de.po",
    "chars": 781117,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2025-01-11T19:48:31+01:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/el.po",
    "chars": 732923,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-01-24T13:24:49+01:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/es.po",
    "chars": 1129407,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-07-19T19:45:30Z\\n\"\n\"PO-Revision"
  },
  {
    "path": "po/fa.po",
    "chars": 968588,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-09-11T22:10:46Z\\n\"\n\"PO-Revision"
  },
  {
    "path": "po/fr.po",
    "chars": 673661,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-04-05T16:37:18-04:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/it.po",
    "chars": 821243,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-01-24T11:55:41+01:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/ja.po",
    "chars": 866440,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-11-23T04:33:49Z\\n\"\n\"PO-Revision"
  },
  {
    "path": "po/pl.po",
    "chars": 893509,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-01-24T13:24:49+01:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/pt-BR.po",
    "chars": 1065425,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-07-09T12:20:23-07:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/ro.po",
    "chars": 950404,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-05-15T20:58:33+03:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/ru.po",
    "chars": 655078,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-05-04T15:55:40+03:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/tr.po",
    "chars": 986401,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2025-11-15T12:48:01+03:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/uk.po",
    "chars": 1083054,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-12-06T09:01:41-05:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/vi.po",
    "chars": 622389,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-05-21T22:14:00+09:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/zh-CN.po",
    "chars": 906929,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-04-15T18:42:46+08:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "po/zh-TW.po",
    "chars": 870407,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Comprehensive Rust 🦀\\n\"\n\"POT-Creation-Date: 2024-03-06T16:11:58-08:00\\n\"\n\"PO-Rev"
  },
  {
    "path": "rustfmt.toml",
    "chars": 289,
    "preview": "# Please use a nightly rustfmt for these settings.\nunstable_features = true\nimports_granularity = \"Module\"\nwrap_comments"
  },
  {
    "path": "src/README.md",
    "chars": 630,
    "preview": "<!--\nCopyright 2024 Google LLC\nSPDX-License-Identifier: CC-BY-4.0\n-->\n\n# Course Content\n\nThe files in this directory mak"
  },
  {
    "path": "src/android/aidl/birthday-service.md",
    "chars": 244,
    "preview": "<!--\nCopyright 2024 Google LLC\nSPDX-License-Identifier: CC-BY-4.0\n-->\n\n# Birthday Service Tutorial\n\nTo illustrate using "
  },
  {
    "path": "src/android/aidl/birthday_service/aidl/com/example/birthdayservice/BirthdayInfo.aidl",
    "chars": 98,
    "preview": "package com.example.birthdayservice;\n\nparcelable BirthdayInfo {\n    String name;\n    int years;\n}\n"
  },
  {
    "path": "src/android/aidl/birthday_service/aidl/com/example/birthdayservice/IBirthdayInfoProvider.aidl",
    "chars": 771,
    "preview": "// Copyright 2024 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "src/android/aidl/birthday_service/src/client.rs",
    "chars": 3284,
    "preview": "// Copyright 2022 Google LLC\n// SPDX-License-Identifier: Apache-2.0\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "src/android/aidl/example-service/deploy.md",
    "chars": 1070,
    "preview": "<!--\nCopyright 2024 Google LLC\nSPDX-License-Identifier: CC-BY-4.0\n-->\n\n# Deploy\n\nWe can now build, push, and start the s"
  },
  {
    "path": "src/unsafe-deep-dive/Cargo.toml",
    "chars": 0,
    "preview": ""
  }
]

// ... and 751 more files (download for full content)

About this extraction

This page contains the full source code of the google/comprehensive-rust GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 824 files (18.2 MB), approximately 4.1M tokens, and a symbol index with 84 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!