From 7e0cfd24739cee94b3d9979d81b74ac74b09ddc8 Mon Sep 17 00:00:00 2001 From: Amin Sharifi Date: Sat, 11 Nov 2023 13:27:16 +0330 Subject: [PATCH 1/2] Update translation file with v2 of book --- po/fa.po | 11504 +++++++++++++++++++---------------------------------- 1 file changed, 4185 insertions(+), 7319 deletions(-) diff --git a/po/fa.po b/po/fa.po index 397cfe072be..1191754be92 100644 --- a/po/fa.po +++ b/po/fa.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: Comprehensive Rust 🦀\n" -"POT-Creation-Date: 2023-08-23\n" +"POT-Creation-Date: 2023-11-11T13:22:58+03:30\n" "PO-Revision-Date: 2023-08-08 21:41+0330\n" "Last-Translator: danny \n" "Language-Team: Persian\n" @@ -12,6 +12,10 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.3.2\n" +#: src/SUMMARY.md:1 +msgid "Summary" +msgstr "" + #: src/SUMMARY.md:4 src/index.md:1 msgid "Welcome to Comprehensive Rust 🦀" msgstr "به Comprehensive Rust خوش آمدید 🦀" @@ -53,7 +57,7 @@ msgid "Day 1: Morning" msgstr "روز اول: صبح" #: src/SUMMARY.md:19 src/SUMMARY.md:80 src/SUMMARY.md:135 src/SUMMARY.md:193 -#: src/SUMMARY.md:219 src/SUMMARY.md:269 +#: src/SUMMARY.md:231 src/SUMMARY.md:281 msgid "Welcome" msgstr "خوش آمدید" @@ -135,8 +139,8 @@ msgid "Overloading" msgstr "سربارگذاری" #: src/SUMMARY.md:39 src/SUMMARY.md:72 src/SUMMARY.md:106 src/SUMMARY.md:126 -#: src/SUMMARY.md:155 src/SUMMARY.md:185 src/SUMMARY.md:212 src/SUMMARY.md:233 -#: src/SUMMARY.md:261 src/SUMMARY.md:283 src/SUMMARY.md:304 +#: src/SUMMARY.md:155 src/SUMMARY.md:185 src/SUMMARY.md:224 src/SUMMARY.md:245 +#: src/SUMMARY.md:273 src/SUMMARY.md:295 src/SUMMARY.md:316 #: src/exercises/android/morning.md:1 src/exercises/bare-metal/morning.md:1 #: src/exercises/bare-metal/afternoon.md:1 #: src/exercises/concurrency/morning.md:1 @@ -156,7 +160,7 @@ msgstr "آرایه ها و حلقه های for" msgid "Day 1: Afternoon" msgstr "روز ۱: بعد از ظهر" -#: src/SUMMARY.md:45 src/SUMMARY.md:296 src/control-flow.md:1 +#: src/SUMMARY.md:45 src/SUMMARY.md:308 src/control-flow.md:1 msgid "Control Flow" msgstr "کنترل جریان" @@ -345,7 +349,7 @@ msgstr "نحو اختصاری فیلد" msgid "Method Receiver" msgstr "متد دریافتی" -#: src/SUMMARY.md:105 src/SUMMARY.md:167 src/SUMMARY.md:282 +#: src/SUMMARY.md:105 src/SUMMARY.md:167 src/SUMMARY.md:294 #: src/methods/example.md:1 src/concurrency/shared_state/example.md:1 msgid "Example" msgstr "مثال" @@ -618,7 +622,7 @@ msgstr "پیاده سازی صفات (Traits) ناامن" msgid "Safe FFI Wrapper" msgstr "امن بودن FFI Wrapper" -#: src/SUMMARY.md:189 src/SUMMARY.md:259 src/bare-metal/android.md:1 +#: src/SUMMARY.md:189 src/SUMMARY.md:271 src/bare-metal/android.md:1 msgid "Android" msgstr "اندروید" @@ -666,7 +670,7 @@ msgstr "کاربر" msgid "Changing API" msgstr "تغییر دادن API" -#: src/SUMMARY.md:205 src/SUMMARY.md:249 src/android/logging.md:1 +#: src/SUMMARY.md:205 src/SUMMARY.md:261 src/android/logging.md:1 #: src/bare-metal/aps/logging.md:1 msgid "Logging" msgstr "لاگ" @@ -687,348 +691,402 @@ msgstr "فراخوانی C با Bindgen" msgid "Calling Rust from C" msgstr "فراخوانی Rust از C" -#: src/SUMMARY.md:210 src/android/interoperability/cpp.md:1 -msgid "With C++" +#: src/SUMMARY.md:210 +#, fuzzy +msgid "With C++)" msgstr "با C++" -#: src/SUMMARY.md:211 +#: src/SUMMARY.md:211 src/android/interoperability/cpp/bridge.md:1 +#, fuzzy +msgid "The Bridge Module" +msgstr "تست‌ ماژول‌ها" + +#: src/SUMMARY.md:212 +#, fuzzy +msgid "Rust Bridge" +msgstr "Rust در اندروید" + +#: src/SUMMARY.md:213 src/android/interoperability/cpp/generated-cpp.md:1 +msgid "Generated C++" +msgstr "" + +#: src/SUMMARY.md:214 +msgid "C++ Bridge" +msgstr "" + +#: src/SUMMARY.md:215 src/android/interoperability/cpp/shared-types.md:1 +#, fuzzy +msgid "Shared Types" +msgstr "تایپ‌های عددی" + +#: src/SUMMARY.md:216 src/android/interoperability/cpp/shared-enums.md:1 +msgid "Shared Enums" +msgstr "" + +#: src/SUMMARY.md:217 src/android/interoperability/cpp/rust-result.md:1 +#, fuzzy +msgid "Rust Error Handling" +msgstr "مدیریت خطا (Error Handling)" + +#: src/SUMMARY.md:218 src/android/interoperability/cpp/cpp-exception.md:1 +#, fuzzy +msgid "C++ Error Handling" +msgstr "مدیریت خطا (Error Handling)" + +#: src/SUMMARY.md:219 src/android/interoperability/cpp/type-mapping.md:1 +msgid "Additional Types" +msgstr "" + +#: src/SUMMARY.md:220 +msgid "Building for Android: C++" +msgstr "" + +#: src/SUMMARY.md:221 +msgid "Building for Android: Genrules" +msgstr "" + +#: src/SUMMARY.md:222 +msgid "Building for Android: Rust" +msgstr "" + +#: src/SUMMARY.md:223 msgid "With Java" msgstr "با جاوا" -#: src/SUMMARY.md:215 +#: src/SUMMARY.md:227 msgid "Bare Metal: Morning" msgstr "با Bare Metal: صبح" -#: src/SUMMARY.md:220 +#: src/SUMMARY.md:232 msgid "no_std" msgstr "no_std" -#: src/SUMMARY.md:221 +#: src/SUMMARY.md:233 msgid "A Minimal Example" msgstr "یک مثال ساده" -#: src/SUMMARY.md:222 +#: src/SUMMARY.md:234 msgid "alloc" msgstr "alloc" -#: src/SUMMARY.md:223 src/bare-metal/microcontrollers.md:1 +#: src/SUMMARY.md:235 src/bare-metal/microcontrollers.md:1 msgid "Microcontrollers" msgstr "میکروکنترلرها" -#: src/SUMMARY.md:224 src/bare-metal/microcontrollers/mmio.md:1 +#: src/SUMMARY.md:236 src/bare-metal/microcontrollers/mmio.md:1 msgid "Raw MMIO" msgstr "Raw MMIO" -#: src/SUMMARY.md:225 +#: src/SUMMARY.md:237 msgid "PACs" msgstr "PACs" -#: src/SUMMARY.md:226 +#: src/SUMMARY.md:238 msgid "HAL Crates" msgstr "HAL Crates" -#: src/SUMMARY.md:227 +#: src/SUMMARY.md:239 msgid "Board Support Crates" msgstr "Board Support Crates" -#: src/SUMMARY.md:228 +#: src/SUMMARY.md:240 msgid "The Type State Pattern" msgstr "انواع State Pattern" -#: src/SUMMARY.md:229 +#: src/SUMMARY.md:241 msgid "embedded-hal" msgstr "embedded-hal" -#: src/SUMMARY.md:230 +#: src/SUMMARY.md:242 msgid "probe-rs, cargo-embed" msgstr "probe-rs, cargo-embed" -#: src/SUMMARY.md:231 src/bare-metal/microcontrollers/debugging.md:1 +#: src/SUMMARY.md:243 src/bare-metal/microcontrollers/debugging.md:1 msgid "Debugging" msgstr "اشکال یابی (Debugging)" -#: src/SUMMARY.md:232 src/SUMMARY.md:252 +#: src/SUMMARY.md:244 src/SUMMARY.md:264 msgid "Other Projects" msgstr "باقی پروژه‌ها" -#: src/SUMMARY.md:234 src/exercises/bare-metal/compass.md:1 +#: src/SUMMARY.md:246 src/exercises/bare-metal/compass.md:1 #: src/exercises/bare-metal/solutions-morning.md:3 msgid "Compass" msgstr "قطب‌نما" -#: src/SUMMARY.md:236 +#: src/SUMMARY.md:248 msgid "Bare Metal: Afternoon" msgstr "با Bare Metal: عصر" -#: src/SUMMARY.md:238 +#: src/SUMMARY.md:250 msgid "Application Processors" msgstr "پردازنده‌های برنامه" -#: src/SUMMARY.md:239 src/bare-metal/aps/entry-point.md:1 +#: src/SUMMARY.md:251 src/bare-metal/aps/entry-point.md:1 msgid "Getting Ready to Rust" msgstr "آماده شدن برای Rust" -#: src/SUMMARY.md:240 +#: src/SUMMARY.md:252 msgid "Inline Assembly" msgstr "اسمبلی درونی" -#: src/SUMMARY.md:241 +#: src/SUMMARY.md:253 msgid "MMIO" msgstr "MMIO" -#: src/SUMMARY.md:242 +#: src/SUMMARY.md:254 msgid "Let's Write a UART Driver" msgstr "بریم یک درایور UART بنویسیم" -#: src/SUMMARY.md:243 +#: src/SUMMARY.md:255 msgid "More Traits" msgstr "صفت‌های بیشتر" -#: src/SUMMARY.md:244 +#: src/SUMMARY.md:256 msgid "A Better UART Driver" msgstr "یک درایور بهتر UART" -#: src/SUMMARY.md:245 src/bare-metal/aps/better-uart/bitflags.md:1 +#: src/SUMMARY.md:257 src/bare-metal/aps/better-uart/bitflags.md:1 msgid "Bitflags" msgstr "پرچم‌های بیتی (Bitflags)" -#: src/SUMMARY.md:246 +#: src/SUMMARY.md:258 msgid "Multiple Registers" msgstr "رجیستر‌های چندگانه" -#: src/SUMMARY.md:247 src/bare-metal/aps/better-uart/driver.md:1 +#: src/SUMMARY.md:259 src/bare-metal/aps/better-uart/driver.md:1 msgid "Driver" msgstr "درایور" -#: src/SUMMARY.md:248 src/SUMMARY.md:250 +#: src/SUMMARY.md:260 src/SUMMARY.md:262 msgid "Using It" msgstr "استفاده از آن" -#: src/SUMMARY.md:251 src/bare-metal/aps/exceptions.md:1 +#: src/SUMMARY.md:263 src/bare-metal/aps/exceptions.md:1 msgid "Exceptions" msgstr "استثناها" -#: src/SUMMARY.md:253 +#: src/SUMMARY.md:265 msgid "Useful Crates" msgstr "جعبه‌های (Crates) کاربردی" -#: src/SUMMARY.md:254 +#: src/SUMMARY.md:266 msgid "zerocopy" msgstr "صفر کپی (zerocopy)" -#: src/SUMMARY.md:255 +#: src/SUMMARY.md:267 msgid "aarch64-paging" msgstr "aarch64-paging" -#: src/SUMMARY.md:256 +#: src/SUMMARY.md:268 msgid "buddy_system_allocator" msgstr "buddy_system_allocator" -#: src/SUMMARY.md:257 +#: src/SUMMARY.md:269 msgid "tinyvec" msgstr "tinyvec" -#: src/SUMMARY.md:258 +#: src/SUMMARY.md:270 msgid "spin" msgstr "چرخش" -#: src/SUMMARY.md:260 src/bare-metal/android/vmbase.md:1 +#: src/SUMMARY.md:272 src/bare-metal/android/vmbase.md:1 msgid "vmbase" msgstr "vmbase" -#: src/SUMMARY.md:262 +#: src/SUMMARY.md:274 msgid "RTC Driver" msgstr "درایور RTC" -#: src/SUMMARY.md:265 +#: src/SUMMARY.md:277 msgid "Concurrency: Morning" msgstr "همزمانی: صبح" -#: src/SUMMARY.md:270 src/concurrency/threads.md:1 +#: src/SUMMARY.md:282 src/concurrency/threads.md:1 msgid "Threads" msgstr "تردها" -#: src/SUMMARY.md:271 src/concurrency/scoped-threads.md:1 +#: src/SUMMARY.md:283 src/concurrency/scoped-threads.md:1 msgid "Scoped Threads" msgstr "محدوده تردها" -#: src/SUMMARY.md:272 src/concurrency/channels.md:1 +#: src/SUMMARY.md:284 src/concurrency/channels.md:1 msgid "Channels" msgstr "کانال‌ها" -#: src/SUMMARY.md:273 src/concurrency/channels/unbounded.md:1 +#: src/SUMMARY.md:285 src/concurrency/channels/unbounded.md:1 msgid "Unbounded Channels" msgstr "کانال‌های نامحدود" -#: src/SUMMARY.md:274 src/concurrency/channels/bounded.md:1 +#: src/SUMMARY.md:286 src/concurrency/channels/bounded.md:1 msgid "Bounded Channels" msgstr "کانال‌های محدود" -#: src/SUMMARY.md:275 +#: src/SUMMARY.md:287 msgid "Send and Sync" msgstr "ارسال و همگام سازی" -#: src/SUMMARY.md:275 +#: src/SUMMARY.md:288 msgid "Send" msgstr "ارسال" -#: src/SUMMARY.md:275 +#: src/SUMMARY.md:289 msgid "Sync" msgstr "همگام سازی" -#: src/SUMMARY.md:278 src/concurrency/send-sync/examples.md:1 +#: src/SUMMARY.md:290 src/concurrency/send-sync/examples.md:1 msgid "Examples" msgstr "مثال‌ها" -#: src/SUMMARY.md:279 src/concurrency/shared_state.md:1 +#: src/SUMMARY.md:291 src/concurrency/shared_state.md:1 msgid "Shared State" msgstr "ناحیه‌های مشترک" -#: src/SUMMARY.md:280 +#: src/SUMMARY.md:292 msgid "Arc" msgstr "Shared State" -#: src/SUMMARY.md:281 +#: src/SUMMARY.md:293 msgid "Mutex" msgstr "Mutex" -#: src/SUMMARY.md:284 src/SUMMARY.md:305 +#: src/SUMMARY.md:296 src/SUMMARY.md:317 #: src/exercises/concurrency/dining-philosophers.md:1 #: src/exercises/concurrency/solutions-morning.md:3 msgid "Dining Philosophers" msgstr "فلسفه Dining" -#: src/SUMMARY.md:285 src/exercises/concurrency/link-checker.md:1 +#: src/SUMMARY.md:297 src/exercises/concurrency/link-checker.md:1 msgid "Multi-threaded Link Checker" msgstr "جستجوگر پیوند چند تِردی" -#: src/SUMMARY.md:287 +#: src/SUMMARY.md:299 msgid "Concurrency: Afternoon" msgstr "همزمانی: عصر" -#: src/SUMMARY.md:289 +#: src/SUMMARY.md:301 msgid "Async Basics" msgstr "مبانی Async" -#: src/SUMMARY.md:290 +#: src/SUMMARY.md:302 msgid "async/await" msgstr "async/await" -#: src/SUMMARY.md:291 src/async/futures.md:1 +#: src/SUMMARY.md:303 src/async/futures.md:1 msgid "Futures" msgstr "Futures" -#: src/SUMMARY.md:292 src/async/runtimes.md:1 +#: src/SUMMARY.md:304 src/async/runtimes.md:1 msgid "Runtimes" msgstr "Runtimes" -#: src/SUMMARY.md:293 src/async/runtimes/tokio.md:1 +#: src/SUMMARY.md:305 src/async/runtimes/tokio.md:1 msgid "Tokio" msgstr "Tokio" -#: src/SUMMARY.md:294 src/exercises/concurrency/link-checker.md:126 +#: src/SUMMARY.md:306 src/exercises/concurrency/link-checker.md:126 #: src/async/tasks.md:1 src/exercises/concurrency/chat-app.md:143 msgid "Tasks" msgstr "Task" -#: src/SUMMARY.md:295 src/async/channels.md:1 +#: src/SUMMARY.md:307 src/async/channels.md:1 msgid "Async Channels" msgstr "کانال‌های Async" -#: src/SUMMARY.md:297 src/async/control-flow/join.md:1 +#: src/SUMMARY.md:309 src/async/control-flow/join.md:1 msgid "Join" msgstr "Join" -#: src/SUMMARY.md:298 src/async/control-flow/select.md:1 +#: src/SUMMARY.md:310 src/async/control-flow/select.md:1 msgid "Select" msgstr "Select" -#: src/SUMMARY.md:299 +#: src/SUMMARY.md:311 msgid "Pitfalls" msgstr "مشکل‌ها" -#: src/SUMMARY.md:300 +#: src/SUMMARY.md:312 msgid "Blocking the Executor" msgstr "مسدود کردن Executor" -#: src/SUMMARY.md:301 src/async/pitfalls/pin.md:1 +#: src/SUMMARY.md:313 src/async/pitfalls/pin.md:1 msgid "Pin" msgstr "Pin" -#: src/SUMMARY.md:302 src/async/pitfalls/async-traits.md:1 +#: src/SUMMARY.md:314 src/async/pitfalls/async-traits.md:1 msgid "Async Traits" msgstr "صفات Async" -#: src/SUMMARY.md:303 src/async/pitfalls/cancellation.md:1 +#: src/SUMMARY.md:315 src/async/pitfalls/cancellation.md:1 msgid "Cancellation" msgstr "لغو" -#: src/SUMMARY.md:306 src/exercises/concurrency/chat-app.md:1 +#: src/SUMMARY.md:318 src/exercises/concurrency/chat-app.md:1 #: src/exercises/concurrency/solutions-afternoon.md:95 msgid "Broadcast Chat Application" msgstr "پخش برنامه چت" -#: src/SUMMARY.md:309 +#: src/SUMMARY.md:321 msgid "Final Words" msgstr "کلمات آخر" -#: src/SUMMARY.md:313 src/thanks.md:1 +#: src/SUMMARY.md:325 src/thanks.md:1 msgid "Thanks!" msgstr "سپاس!" -#: src/SUMMARY.md:314 src/glossary.md:1 +#: src/SUMMARY.md:326 src/glossary.md:1 msgid "Glossary" msgstr "واژه نامه" -#: src/SUMMARY.md:315 +#: src/SUMMARY.md:327 msgid "Other Resources" msgstr "منابع دیگر" -#: src/SUMMARY.md:316 src/credits.md:1 +#: src/SUMMARY.md:328 src/credits.md:1 msgid "Credits" msgstr "اعتبارها" -#: src/SUMMARY.md:319 src/exercises/solutions.md:1 +#: src/SUMMARY.md:331 src/SUMMARY.md:335 src/exercises/solutions.md:1 msgid "Solutions" msgstr "راه حل‌ها" -#: src/SUMMARY.md:324 +#: src/SUMMARY.md:336 msgid "Day 1 Morning" msgstr "روز ۱ صبح" -#: src/SUMMARY.md:325 +#: src/SUMMARY.md:337 msgid "Day 1 Afternoon" msgstr "روز ۱ عصر" -#: src/SUMMARY.md:326 +#: src/SUMMARY.md:338 msgid "Day 2 Morning" msgstr "روز ۲ صبح" -#: src/SUMMARY.md:327 +#: src/SUMMARY.md:339 msgid "Day 2 Afternoon" msgstr "روز ۲ عصر" -#: src/SUMMARY.md:328 +#: src/SUMMARY.md:340 msgid "Day 3 Morning" msgstr "روز ۳ صبح" -#: src/SUMMARY.md:329 +#: src/SUMMARY.md:341 msgid "Day 3 Afternoon" msgstr "روز ۳ عصر" -#: src/SUMMARY.md:330 +#: src/SUMMARY.md:342 msgid "Bare Metal Rust Morning" msgstr "صبح‌گاه با Bare Metal Rust" -#: src/SUMMARY.md:331 src/exercises/bare-metal/solutions-afternoon.md:1 +#: src/SUMMARY.md:343 src/exercises/bare-metal/solutions-afternoon.md:1 msgid "Bare Metal Rust Afternoon" msgstr "عصرانه با Bare Metal Rust" -#: src/SUMMARY.md:332 +#: src/SUMMARY.md:344 msgid "Concurrency Morning" msgstr "صبح‌گاه با همزمانی (Concurrency)" -#: src/SUMMARY.md:333 +#: src/SUMMARY.md:345 msgid "Concurrency Afternoon" msgstr "همزمانی: عصر" @@ -1892,19 +1950,9 @@ msgstr "" msgid "The code blocks in this course are fully interactive:" msgstr "بلوک های کد در این دوره کاملاً تعاملی(interactive) هستند:" -#: src/cargo/code-samples.md:13 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" println!(\"Edit me!\");\n" -"}\n" -"```" +#: src/cargo/code-samples.md:15 src/cargo/running-locally.md:45 +msgid "\"Edit me!\"" msgstr "" -"```rust,editable\n" -"fn main() {\n" -" println!(\"Edit me!\");\n" -"}\n" -"```" #: src/cargo/code-samples.md:19 msgid "You can use " @@ -2001,20 +2049,6 @@ msgstr "" "کد صفحه دیگر را در `src/main.rs` با کد خود جایگزین کنید. برای مثال، با " "استفاده از مثال در صفحه قبل، `src/main.rs` را شبیه به آن کنید." -#: src/cargo/running-locally.md:43 -msgid "" -"```rust\n" -"fn main() {\n" -" println!(\"Edit me!\");\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"fn main() {\n" -" println!(\"Edit me!\");\n" -"}\n" -"```" - #: src/cargo/running-locally.md:49 msgid "Use `cargo run` to build and run your updated binary:" msgstr "برای ساختن و اجرای باینری به روز شده خود از `cargo run` استفاده کنید:" @@ -2254,13 +2288,8 @@ msgstr "" "بیایید به ساده ترین برنامه Rust ممکن یعنی یک برنامه Hello World کلاسیک " "بپردازیم:" -#: src/hello-world.md:6 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" println!(\"Hello 🌍!\");\n" -"}\n" -"```" +#: src/hello-world.md:8 +msgid "\"Hello 🌍!\"" msgstr "" #: src/hello-world.md:12 @@ -2353,39 +2382,33 @@ msgstr "" msgid "Here is a small example program in Rust:" msgstr "یک برنامه کوچیک در Rust:" -#: src/hello-world/small-example.md:5 -msgid "" -"```rust,editable\n" -"fn main() { // Program entry point\n" -" let mut x: i32 = 6; // Mutable variable binding\n" -" print!(\"{x}\"); // Macro for printing, like printf\n" -" while x != 1 { // No parenthesis around expression\n" -" if x % 2 == 0 { // Math like in other languages\n" -" x = x / 2;\n" -" } else {\n" -" x = 3 * x + 1;\n" -" }\n" -" print!(\" -> {x}\");\n" -" }\n" -" println!();\n" -"}\n" -"```" +#: src/hello-world/small-example.md:6 +msgid "// Program entry point" +msgstr "" + +#: src/hello-world/small-example.md:7 +msgid "// Mutable variable binding" +msgstr "" + +#: src/hello-world/small-example.md:8 src/traits/impl-trait.md:15 +msgid "\"{x}\"" +msgstr "" + +#: src/hello-world/small-example.md:8 +msgid "// Macro for printing, like printf" +msgstr "" + +#: src/hello-world/small-example.md:9 +msgid "// No parenthesis around expression" +msgstr "" + +#: src/hello-world/small-example.md:10 +msgid "// Math like in other languages" +msgstr "" + +#: src/hello-world/small-example.md:15 +msgid "\" -> {x}\"" msgstr "" -"```rust,editable\n" -"fn main() { // نقطه ورودی برنامه\n" -" let mut x: i32 = 6; //انتساب متغیر قابل تغییر\n" -" print!(\"{x}\"); // ماکرویی برای چاپ‌کردن به مانند printf\n" -" while x != 1 { // هیچ پرانتزی اطراف دستور نیست\n" -" if x % 2 == 0 { // محاسبات مانند بقیه زبان ها \n" -" x = x / 2;\n" -" } else {\n" -" x = 3 * x + 1;\n" -" }\n" -" print!(\" -> {x}\");\n" -" }\n" -" println!();\n" -"}\n" -"```" #: src/hello-world/small-example.md:23 msgid "" @@ -2499,49 +2522,41 @@ msgstr "" msgid "Let's consider the following \"minimum wrong example\" program in C:" msgstr "بیایید برنامه «نمونه ای از حداقل اشتباهات» زیر را در C در نظر بگیریم:" -#: src/why-rust/an-example-in-c.md:6 -msgid "" -"```c,editable\n" -"#include \n" -"#include \n" -"#include \n" -"\n" -"int main(int argc, char* argv[]) {\n" -"\tchar *buf, *filename;\n" -"\tFILE *fp;\n" -"\tsize_t bytes, len;\n" -"\tstruct stat st;\n" -"\n" -"\tswitch (argc) {\n" -"\t\tcase 1:\n" -"\t\t\tprintf(\"Too few arguments!\\n\");\n" -"\t\t\treturn 1;\n" -"\n" -"\t\tcase 2:\n" -"\t\t\tfilename = argv[argc];\n" -"\t\t\tstat(filename, &st);\n" -"\t\t\tlen = st.st_size;\n" -"\t\t\t\n" -"\t\t\tbuf = (char*)malloc(len);\n" -"\t\t\tif (!buf)\n" -"\t\t\t\tprintf(\"malloc failed!\\n\", len);\n" -"\t\t\t\treturn 1;\n" -"\n" -"\t\t\tfp = fopen(filename, \"rb\");\n" -"\t\t\tbytes = fread(buf, 1, len, fp);\n" -"\t\t\tif (bytes = st.st_size)\n" -"\t\t\t\tprintf(\"%s\", buf);\n" -"\t\t\telse\n" -"\t\t\t\tprintf(\"fread failed!\\n\");\n" -"\n" -"\t\tcase 3:\n" -"\t\t\tprintf(\"Too many arguments!\\n\");\n" -"\t\t\treturn 1;\n" -"\t}\n" -"\n" -"\treturn 0;\n" -"}\n" -"```" +#: src/why-rust/an-example-in-c.md:7 +#: src/android/interoperability/with-c/bindgen.md:22 +msgid "" +msgstr "" + +#: src/why-rust/an-example-in-c.md:8 +msgid "" +msgstr "" + +#: src/why-rust/an-example-in-c.md:9 +msgid "" +msgstr "" + +#: src/why-rust/an-example-in-c.md:19 +msgid "\"Too few arguments!\\n\"" +msgstr "" + +#: src/why-rust/an-example-in-c.md:29 +msgid "\"malloc failed!\\n\"" +msgstr "" + +#: src/why-rust/an-example-in-c.md:32 +msgid "\"rb\"" +msgstr "" + +#: src/why-rust/an-example-in-c.md:35 +msgid "\"%s\"" +msgstr "" + +#: src/why-rust/an-example-in-c.md:37 +msgid "\"fread failed!\\n\"" +msgstr "" + +#: src/why-rust/an-example-in-c.md:40 +msgid "\"Too many arguments!\\n\"" msgstr "" #: src/why-rust/an-example-in-c.md:48 @@ -2634,10 +2649,11 @@ msgstr "" "dwheeler.com/essays/apple-goto-fail.html)" #: src/why-rust/an-example-in-c.md:73 +#, fuzzy msgid "" "Forgotten `break` in a `switch` statement: [The break that broke sudo]" -"(https://nakedsecurity.sophos.com/2012/05/21/anatomy-of-a-security-hole-the-" -"break-that-broke-sudo)" +"(https://www.lufsec.com/anatomy-of-a-security-hole-the-break-that-broke-" +"sudo/)" msgstr "" "فراموشی گذاشتن `break` در `switch`: [The break that broke sudo]" "(https://nakedsecurity.sophos.com/2012/05/21/anatomy-of-a-security-hole-the-" @@ -3069,6 +3085,7 @@ msgid "Strings" msgstr "رشته‌ها" #: src/basic-syntax/scalar-types.md:8 +#: src/android/interoperability/cpp/type-mapping.md:6 msgid "`&str`" msgstr "&str" @@ -3396,22 +3413,28 @@ msgstr "" msgid "We can now understand the two string types in Rust:" msgstr "" -#: src/basic-syntax/string-slices.md:5 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let s1: &str = \"World\";\n" -" println!(\"s1: {s1}\");\n" -"\n" -" let mut s2: String = String::from(\"Hello \");\n" -" println!(\"s2: {s2}\");\n" -" s2.push_str(s1);\n" -" println!(\"s2: {s2}\");\n" -" \n" -" let s3: &str = &s2[6..];\n" -" println!(\"s3: {s3}\");\n" -"}\n" -"```" +#: src/basic-syntax/string-slices.md:7 src/traits/read-write.md:36 +#: src/testing/test-modules.md:12 +msgid "\"World\"" +msgstr "" + +#: src/basic-syntax/string-slices.md:8 +msgid "\"s1: {s1}\"" +msgstr "" + +#: src/basic-syntax/string-slices.md:10 src/memory-management/scope-based.md:16 +#: src/memory-management/garbage-collection.md:15 +#, fuzzy +msgid "\"Hello \"" +msgstr "سلام دنیا" + +#: src/basic-syntax/string-slices.md:11 src/basic-syntax/string-slices.md:13 +#: src/ownership/move-semantics.md:9 +msgid "\"s2: {s2}\"" +msgstr "" + +#: src/basic-syntax/string-slices.md:16 +msgid "\"s3: {s3}\"" msgstr "" #: src/basic-syntax/string-slices.md:20 @@ -3507,26 +3530,41 @@ msgid "" "All language items in Rust can be documented using special `///` syntax." msgstr "" -#: src/basic-syntax/rustdoc.md:5 -msgid "" -"```rust,editable\n" -"/// Determine whether the first argument is divisible by the second " -"argument.\n" -"///\n" -"/// If the second argument is zero, the result is false.\n" -"///\n" -"/// # Example\n" -"/// ```\n" -"/// assert!(is_divisible_by(42, 2));\n" -"/// ```\n" -"fn is_divisible_by(lhs: u32, rhs: u32) -> bool {\n" -" if rhs == 0 {\n" -" return false; // Corner case, early return\n" -" }\n" -" lhs % rhs == 0 // The last expression in a block is the return " -"value\n" -"}\n" -"```" +#: src/basic-syntax/rustdoc.md:6 +msgid "" +"/// Determine whether the first argument is divisible by the second argument." +msgstr "" + +#: src/basic-syntax/rustdoc.md:6 src/basic-syntax/rustdoc.md:8 +#: src/testing/doc-tests.md:6 src/unsafe/writing-unsafe-functions.md:7 +#: src/unsafe/writing-unsafe-functions.md:9 +msgid "///" +msgstr "" + +#: src/basic-syntax/rustdoc.md:7 +msgid "/// If the second argument is zero, the result is false." +msgstr "" + +#: src/basic-syntax/rustdoc.md:9 +#, fuzzy +msgid "/// # Example" +msgstr "مثال" + +#: src/basic-syntax/rustdoc.md:10 src/basic-syntax/rustdoc.md:12 +#: src/testing/doc-tests.md:7 src/testing/doc-tests.md:11 +msgid "/// ```" +msgstr "" + +#: src/basic-syntax/rustdoc.md:11 +msgid "/// assert!(is_divisible_by(42, 2));" +msgstr "" + +#: src/basic-syntax/rustdoc.md:16 +msgid "// Corner case, early return" +msgstr "" + +#: src/basic-syntax/rustdoc.md:18 +msgid "// The last expression in a block is the return value" msgstr "" #: src/basic-syntax/rustdoc.md:22 @@ -3569,31 +3607,12 @@ msgid "" "method is an instance of the type it is associated with:" msgstr "" -#: src/basic-syntax/methods.md:6 -msgid "" -"```rust,editable\n" -"struct Rectangle {\n" -" width: u32,\n" -" height: u32,\n" -"}\n" -"\n" -"impl Rectangle {\n" -" fn area(&self) -> u32 {\n" -" self.width * self.height\n" -" }\n" -"\n" -" fn inc_width(&mut self, delta: u32) {\n" -" self.width += delta;\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let mut rect = Rectangle { width: 10, height: 5 };\n" -" println!(\"old area: {}\", rect.area());\n" -" rect.inc_width(5);\n" -" println!(\"new area: {}\", rect.area());\n" -"}\n" -"```" +#: src/basic-syntax/methods.md:24 +msgid "\"old area: {}\"" +msgstr "" + +#: src/basic-syntax/methods.md:26 +msgid "\"new area: {}\"" msgstr "" #: src/basic-syntax/methods.md:30 @@ -3656,18 +3675,21 @@ msgstr "" msgid "However, function parameters can be generic:" msgstr "" -#: src/basic-syntax/functions-interlude.md:14 -msgid "" -"```rust,editable\n" -"fn pick_one(a: T, b: T) -> T {\n" -" if std::process::id() % 2 == 0 { a } else { b }\n" -"}\n" -"\n" -"fn main() {\n" -" println!(\"coin toss: {}\", pick_one(\"heads\", \"tails\"));\n" -" println!(\"cash prize: {}\", pick_one(500, 1000));\n" -"}\n" -"```" +#: src/basic-syntax/functions-interlude.md:20 +msgid "\"coin toss: {}\"" +msgstr "" + +#: src/basic-syntax/functions-interlude.md:20 +#, fuzzy +msgid "\"heads\"" +msgstr "تردها" + +#: src/basic-syntax/functions-interlude.md:20 +msgid "\"tails\"" +msgstr "" + +#: src/basic-syntax/functions-interlude.md:21 +msgid "\"cash prize: {}\"" msgstr "" #: src/basic-syntax/functions-interlude.md:27 @@ -3793,24 +3815,20 @@ msgid "" "keyword:" msgstr "" -#: src/exercises/day-1/for-loops.md:22 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let array = [10, 20, 30];\n" -" print!(\"Iterating over array:\");\n" -" for n in &array {\n" -" print!(\" {n}\");\n" -" }\n" -" println!();\n" -"\n" -" print!(\"Iterating over range:\");\n" -" for i in 0..3 {\n" -" print!(\" {}\", array[i]);\n" -" }\n" -" println!();\n" -"}\n" -"```" +#: src/exercises/day-1/for-loops.md:25 +msgid "\"Iterating over array:\"" +msgstr "" + +#: src/exercises/day-1/for-loops.md:27 +msgid "\" {n}\"" +msgstr "" + +#: src/exercises/day-1/for-loops.md:31 +msgid "\"Iterating over range:\"" +msgstr "" + +#: src/exercises/day-1/for-loops.md:33 +msgid "\" {}\"" msgstr "" #: src/exercises/day-1/for-loops.md:39 @@ -3830,35 +3848,28 @@ msgid "" "functions:" msgstr "" -#: src/exercises/day-1/for-loops.md:54 -msgid "" -"```rust,should_panic\n" -"// TODO: remove this when you're done with your implementation.\n" -"#![allow(unused_variables, dead_code)]\n" -"\n" -"fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {\n" -" unimplemented!()\n" -"}\n" -"\n" -"fn pretty_print(matrix: &[[i32; 3]; 3]) {\n" -" unimplemented!()\n" -"}\n" -"\n" -"fn main() {\n" -" let matrix = [\n" -" [101, 102, 103], // <-- the comment makes rustfmt add a newline\n" -" [201, 202, 203],\n" -" [301, 302, 303],\n" -" ];\n" -"\n" -" println!(\"matrix:\");\n" -" pretty_print(&matrix);\n" -"\n" -" let transposed = transpose(matrix);\n" -" println!(\"transposed:\");\n" -" pretty_print(&transposed);\n" -"}\n" -"```" +#: src/exercises/day-1/for-loops.md:55 src/exercises/day-1/luhn.md:26 +#: src/exercises/day-2/health-statistics.md:14 +#: src/exercises/day-2/strings-iterators.md:13 +#: src/exercises/day-3/simple-gui.md:20 +#: src/exercises/day-3/points-polygons.md:8 +#: src/exercises/day-3/safe-ffi-wrapper.md:49 +msgid "// TODO: remove this when you're done with your implementation." +msgstr "" + +#: src/exercises/day-1/for-loops.md:68 +#: src/exercises/day-1/solutions-morning.md:44 +msgid "// <-- the comment makes rustfmt add a newline\n" +msgstr "" + +#: src/exercises/day-1/for-loops.md:73 +#: src/exercises/day-1/solutions-morning.md:49 +msgid "\"matrix:\"" +msgstr "" + +#: src/exercises/day-1/for-loops.md:77 +#: src/exercises/day-1/solutions-morning.md:53 +msgid "\"transposed:\"" msgstr "" #: src/exercises/day-1/for-loops.md:82 @@ -4161,15 +4172,13 @@ msgid "" "therefore will not move:" msgstr "" -#: src/basic-syntax/static-and-const.md:38 -msgid "" -"```rust,editable\n" -"static BANNER: &str = \"Welcome to RustOS 3.14\";\n" -"\n" -"fn main() {\n" -" println!(\"{BANNER}\");\n" -"}\n" -"```" +#: src/basic-syntax/static-and-const.md:39 +#, fuzzy +msgid "\"Welcome to RustOS 3.14\"" +msgstr "به روز ۱ خوش آمدید" + +#: src/basic-syntax/static-and-const.md:42 +msgid "\"{BANNER}\"" msgstr "" #: src/basic-syntax/static-and-const.md:46 @@ -4285,24 +4294,25 @@ msgid "" "the same scope:" msgstr "" -#: src/basic-syntax/scopes-shadowing.md:6 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let a = 10;\n" -" println!(\"before: {a}\");\n" -"\n" -" {\n" -" let a = \"hello\";\n" -" println!(\"inner scope: {a}\");\n" -"\n" -" let a = true;\n" -" println!(\"shadowed in inner scope: {a}\");\n" -" }\n" -"\n" -" println!(\"after: {a}\");\n" -"}\n" -"```" +#: src/basic-syntax/scopes-shadowing.md:9 +msgid "\"before: {a}\"" +msgstr "" + +#: src/basic-syntax/scopes-shadowing.md:12 src/traits/from-into.md:7 +#: src/traits/from-into.md:19 +msgid "\"hello\"" +msgstr "" + +#: src/basic-syntax/scopes-shadowing.md:13 +msgid "\"inner scope: {a}\"" +msgstr "" + +#: src/basic-syntax/scopes-shadowing.md:16 +msgid "\"shadowed in inner scope: {a}\"" +msgstr "" + +#: src/basic-syntax/scopes-shadowing.md:19 +msgid "\"after: {a}\"" msgstr "" #: src/basic-syntax/scopes-shadowing.md:25 @@ -4335,33 +4345,16 @@ msgid "" "variants:" msgstr "" -#: src/enums.md:6 -msgid "" -"```rust,editable\n" -"fn generate_random_number() -> i32 {\n" -" // Implementation based on https://xkcd.com/221/\n" -" 4 // Chosen by fair dice roll. Guaranteed to be random.\n" -"}\n" -"\n" -"#[derive(Debug)]\n" -"enum CoinFlip {\n" -" Heads,\n" -" Tails,\n" -"}\n" -"\n" -"fn flip_coin() -> CoinFlip {\n" -" let random_number = generate_random_number();\n" -" if random_number % 2 == 0 {\n" -" return CoinFlip::Heads;\n" -" } else {\n" -" return CoinFlip::Tails;\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" println!(\"You got: {:?}\", flip_coin());\n" -"}\n" -"```" +#: src/enums.md:8 +msgid "// Implementation based on https://xkcd.com/221/" +msgstr "" + +#: src/enums.md:9 +msgid "// Chosen by fair dice roll. Guaranteed to be random." +msgstr "" + +#: src/enums.md:28 +msgid "\"You got: {:?}\"" msgstr "" #: src/enums.md:36 @@ -4401,40 +4394,39 @@ msgid "" "the `match` statement to extract the data from each variant:" msgstr "" -#: src/enums/variant-payloads.md:6 -msgid "" -"```rust,editable\n" -"enum WebEvent {\n" -" PageLoad, // Variant without payload\n" -" KeyPress(char), // Tuple struct variant\n" -" Click { x: i64, y: i64 }, // Full struct variant\n" -"}\n" -"\n" -"#[rustfmt::skip]\n" -"fn inspect(event: WebEvent) {\n" -" match event {\n" -" WebEvent::PageLoad => println!(\"page loaded\"),\n" -" WebEvent::KeyPress(c) => println!(\"pressed '{c}'\"),\n" -" WebEvent::Click { x, y } => println!(\"clicked at x={x}, y={y}\"),\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let load = WebEvent::PageLoad;\n" -" let press = WebEvent::KeyPress('x');\n" -" let click = WebEvent::Click { x: 20, y: 80 };\n" -"\n" -" inspect(load);\n" -" inspect(press);\n" -" inspect(click);\n" -"}\n" -"```" +#: src/enums/variant-payloads.md:8 +#, fuzzy +msgid "// Variant without payload\n" +msgstr "Variant Payloads" + +#: src/enums/variant-payloads.md:9 +msgid "// Tuple struct variant\n" msgstr "" -#: src/enums/variant-payloads.md:35 -msgid "" -"The values in the enum variants can only be accessed after being pattern " -"matched. The pattern binds references to the fields in the \"match arm\" " +#: src/enums/variant-payloads.md:10 +msgid "// Full struct variant\n" +msgstr "" + +#: src/enums/variant-payloads.md:16 +msgid "\"page loaded\"" +msgstr "" + +#: src/enums/variant-payloads.md:17 +msgid "\"pressed '{c}'\"" +msgstr "" + +#: src/enums/variant-payloads.md:18 +msgid "\"clicked at x={x}, y={y}\"" +msgstr "" + +#: src/enums/variant-payloads.md:24 src/pattern-matching.md:10 +msgid "'x'" +msgstr "" + +#: src/enums/variant-payloads.md:35 +msgid "" +"The values in the enum variants can only be accessed after being pattern " +"matched. The pattern binds references to the fields in the \"match arm\" " "after the `=>`." msgstr "" @@ -4491,26 +4483,8 @@ msgid "" "account:" msgstr "" -#: src/enums/sizes.md:5 -msgid "" -"```rust,editable\n" -"use std::any::type_name;\n" -"use std::mem::{align_of, size_of};\n" -"\n" -"fn dbg_size() {\n" -" println!(\"{}: size {} bytes, align: {} bytes\",\n" -" type_name::(), size_of::(), align_of::());\n" -"}\n" -"\n" -"enum Foo {\n" -" A,\n" -" B,\n" -"}\n" -"\n" -"fn main() {\n" -" dbg_size::();\n" -"}\n" -"```" +#: src/enums/sizes.md:10 +msgid "\"{}: size {} bytes, align: {} bytes\"" msgstr "" #: src/enums/sizes.md:24 @@ -4622,18 +4596,12 @@ msgid "" "whether a value matches a pattern:" msgstr "" -#: src/control-flow/if-let-expressions.md:7 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let arg = std::env::args().next();\n" -" if let Some(value) = arg {\n" -" println!(\"Program name: {value}\");\n" -" } else {\n" -" println!(\"Missing name?\");\n" -" }\n" -"}\n" -"```" +#: src/control-flow/if-let-expressions.md:11 +msgid "\"Program name: {value}\"" +msgstr "" + +#: src/control-flow/if-let-expressions.md:13 +msgid "\"Missing name?\"" msgstr "" #: src/control-flow/if-let-expressions.md:18 @@ -4706,20 +4674,44 @@ msgid "" "sense, it works like a series of `if let` expressions:" msgstr "" -#: src/control-flow/match-expressions.md:7 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" match std::env::args().next().as_deref() {\n" -" Some(\"cat\") => println!(\"Will do cat things\"),\n" -" Some(\"ls\") => println!(\"Will ls some files\"),\n" -" Some(\"mv\") => println!(\"Let's move some files\"),\n" -" Some(\"rm\") => println!(\"Uh, dangerous!\"),\n" -" None => println!(\"Hmm, no program name?\"),\n" -" _ => println!(\"Unknown program name!\"),\n" -" }\n" -"}\n" -"```" +#: src/control-flow/match-expressions.md:10 +msgid "\"cat\"" +msgstr "" + +#: src/control-flow/match-expressions.md:10 +msgid "\"Will do cat things\"" +msgstr "" + +#: src/control-flow/match-expressions.md:11 +msgid "\"ls\"" +msgstr "" + +#: src/control-flow/match-expressions.md:11 +msgid "\"Will ls some files\"" +msgstr "" + +#: src/control-flow/match-expressions.md:12 +msgid "\"mv\"" +msgstr "" + +#: src/control-flow/match-expressions.md:12 +msgid "\"Let's move some files\"" +msgstr "" + +#: src/control-flow/match-expressions.md:13 +msgid "\"rm\"" +msgstr "" + +#: src/control-flow/match-expressions.md:13 +msgid "\"Uh, dangerous!\"" +msgstr "" + +#: src/control-flow/match-expressions.md:14 +msgid "\"Hmm, no program name?\"" +msgstr "" + +#: src/control-flow/match-expressions.md:15 +msgid "\"Unknown program name!\"" msgstr "" #: src/control-flow/match-expressions.md:20 @@ -4763,20 +4755,48 @@ msgstr "" msgid "The patterns can be simple values, similarly to `switch` in C and C++:" msgstr "" -#: src/pattern-matching.md:8 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let input = 'x';\n" -"\n" -" match input {\n" -" 'q' => println!(\"Quitting\"),\n" -" 'a' | 's' | 'w' | 'd' => println!(\"Moving around\"),\n" -" '0'..='9' => println!(\"Number input\"),\n" -" _ => println!(\"Something else\"),\n" -" }\n" -"}\n" -"```" +#: src/pattern-matching.md:13 +msgid "'q'" +msgstr "" + +#: src/pattern-matching.md:13 +msgid "\"Quitting\"" +msgstr "" + +#: src/pattern-matching.md:14 +msgid "'a'" +msgstr "" + +#: src/pattern-matching.md:14 +msgid "'s'" +msgstr "" + +#: src/pattern-matching.md:14 +msgid "'w'" +msgstr "" + +#: src/pattern-matching.md:14 +msgid "'d'" +msgstr "" + +#: src/pattern-matching.md:14 +msgid "\"Moving around\"" +msgstr "" + +#: src/pattern-matching.md:15 +msgid "'0'" +msgstr "" + +#: src/pattern-matching.md:15 +msgid "'9'" +msgstr "" + +#: src/pattern-matching.md:15 +msgid "\"Number input\"" +msgstr "" + +#: src/pattern-matching.md:16 +msgid "\"Something else\"" msgstr "" #: src/pattern-matching.md:21 @@ -4828,30 +4848,16 @@ msgid "" "`enum` type:" msgstr "" -#: src/pattern-matching/destructuring-enums.md:6 -msgid "" -"```rust,editable\n" -"enum Result {\n" -" Ok(i32),\n" -" Err(String),\n" -"}\n" -"\n" -"fn divide_in_two(n: i32) -> Result {\n" -" if n % 2 == 0 {\n" -" Result::Ok(n / 2)\n" -" } else {\n" -" Result::Err(format!(\"cannot divide {n} into two equal parts\"))\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let n = 100;\n" -" match divide_in_two(n) {\n" -" Result::Ok(half) => println!(\"{n} divided in two is {half}\"),\n" -" Result::Err(msg) => println!(\"sorry, an error happened: {msg}\"),\n" -" }\n" -"}\n" -"```" +#: src/pattern-matching/destructuring-enums.md:16 +msgid "\"cannot divide {n} into two equal parts\"" +msgstr "" + +#: src/pattern-matching/destructuring-enums.md:23 +msgid "\"{n} divided in two is {half}\"" +msgstr "" + +#: src/pattern-matching/destructuring-enums.md:24 +msgid "\"sorry, an error happened: {msg}\"" msgstr "" #: src/pattern-matching/destructuring-enums.md:29 @@ -4878,25 +4884,16 @@ msgstr "" msgid "You can also destructure `structs`:" msgstr "" -#: src/pattern-matching/destructuring-structs.md:5 -msgid "" -"```rust,editable\n" -"struct Foo {\n" -" x: (u32, u32),\n" -" y: u32,\n" -"}\n" -"\n" -"#[rustfmt::skip]\n" -"fn main() {\n" -" let foo = Foo { x: (1, 2), y: 3 };\n" -" match foo {\n" -" Foo { x: (1, b), y } => println!(\"x.0 = 1, b = {b}, y = {y}\"),\n" -" Foo { y: 2, x: i } => println!(\"y = 2, x = {i:?}\"),\n" -" Foo { y, .. } => println!(\"y = {y}, other fields were " -"ignored\"),\n" -" }\n" -"}\n" -"```" +#: src/pattern-matching/destructuring-structs.md:15 +msgid "\"x.0 = 1, b = {b}, y = {y}\"" +msgstr "" + +#: src/pattern-matching/destructuring-structs.md:16 +msgid "\"y = 2, x = {i:?}\"" +msgstr "" + +#: src/pattern-matching/destructuring-structs.md:17 +msgid "\"y = {y}, other fields were ignored\"" msgstr "" #: src/pattern-matching/destructuring-structs.md:23 @@ -4919,20 +4916,23 @@ msgid "" "You can destructure arrays, tuples, and slices by matching on their elements:" msgstr "" -#: src/pattern-matching/destructuring-arrays.md:5 -msgid "" -"```rust,editable\n" -"#[rustfmt::skip]\n" -"fn main() {\n" -" let triple = [0, -2, 3];\n" -" println!(\"Tell me about {triple:?}\");\n" -" match triple {\n" -" [0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n" -" [1, ..] => println!(\"First is 1 and the rest were ignored\"),\n" -" _ => println!(\"All elements were ignored\"),\n" -" }\n" -"}\n" -"```" +#: src/pattern-matching/destructuring-arrays.md:9 +msgid "\"Tell me about {triple:?}\"" +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:11 +#: src/pattern-matching/destructuring-arrays.md:34 +msgid "\"First is 0, y = {y}, and z = {z}\"" +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:12 +#: src/pattern-matching/destructuring-arrays.md:35 +msgid "\"First is 1 and the rest were ignored\"" +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:13 +#: src/pattern-matching/destructuring-arrays.md:36 +msgid "\"All elements were ignored\"" msgstr "" #: src/pattern-matching/destructuring-arrays.md:21 @@ -4941,24 +4941,8 @@ msgid "" "length." msgstr "" -#: src/pattern-matching/destructuring-arrays.md:24 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" inspect(&[0, -2, 3]);\n" -" inspect(&[0, -2, 3, 4]);\n" -"}\n" -"\n" -"#[rustfmt::skip]\n" -"fn inspect(slice: &[i32]) {\n" -" println!(\"Tell me about {slice:?}\");\n" -" match slice {\n" -" &[0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n" -" &[1, ..] => println!(\"First is 1 and the rest were ignored\"),\n" -" _ => println!(\"All elements were ignored\"),\n" -" }\n" -"}\n" -"```" +#: src/pattern-matching/destructuring-arrays.md:32 +msgid "\"Tell me about {slice:?}\"" msgstr "" #: src/pattern-matching/destructuring-arrays.md:41 @@ -4985,21 +4969,24 @@ msgid "" "Boolean expression which will be executed if the pattern matches:" msgstr "" -#: src/pattern-matching/match-guards.md:6 -msgid "" -"```rust,editable\n" -"#[rustfmt::skip]\n" -"fn main() {\n" -" let pair = (2, -2);\n" -" println!(\"Tell me about {pair:?}\");\n" -" match pair {\n" -" (x, y) if x == y => println!(\"These are twins\"),\n" -" (x, y) if x + y == 0 => println!(\"Antimatter, kaboom!\"),\n" -" (x, _) if x % 2 == 1 => println!(\"The first one is odd\"),\n" -" _ => println!(\"No correlation...\"),\n" -" }\n" -"}\n" -"```" +#: src/pattern-matching/match-guards.md:10 +msgid "\"Tell me about {pair:?}\"" +msgstr "" + +#: src/pattern-matching/match-guards.md:12 +msgid "\"These are twins\"" +msgstr "" + +#: src/pattern-matching/match-guards.md:13 +msgid "\"Antimatter, kaboom!\"" +msgstr "" + +#: src/pattern-matching/match-guards.md:14 +msgid "\"The first one is odd\"" +msgstr "" + +#: src/pattern-matching/match-guards.md:15 +msgid "\"No correlation...\"" msgstr "" #: src/pattern-matching/match-guards.md:23 @@ -5095,57 +5082,72 @@ msgid "" "integers. Then, revisit the solution and try to implement it with iterators." msgstr "" -#: src/exercises/day-1/luhn.md:25 -msgid "" -"```rust\n" -"// TODO: remove this when you're done with your implementation.\n" -"#![allow(unused_variables, dead_code)]\n" -"\n" -"pub fn luhn(cc_number: &str) -> bool {\n" -" unimplemented!()\n" -"}\n" -"\n" -"#[test]\n" -"fn test_non_digit_cc_number() {\n" -" assert!(!luhn(\"foo\"));\n" -" assert!(!luhn(\"foo 0 0\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_empty_cc_number() {\n" -" assert!(!luhn(\"\"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_single_digit_cc_number() {\n" -" assert!(!luhn(\"0\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_two_digit_cc_number() {\n" -" assert!(luhn(\" 0 0 \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_valid_cc_number() {\n" -" assert!(luhn(\"4263 9826 4026 9299\"));\n" -" assert!(luhn(\"4539 3195 0343 6467\"));\n" -" assert!(luhn(\"7992 7398 713\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_invalid_cc_number() {\n" -" assert!(!luhn(\"4223 9826 4026 9299\"));\n" -" assert!(!luhn(\"4539 3195 0343 6476\"));\n" -" assert!(!luhn(\"8273 1232 7352 0569\"));\n" -"}\n" -"\n" -"#[allow(dead_code)]\n" -"fn main() {}\n" -"```" +#: src/exercises/day-1/luhn.md:35 +#: src/exercises/day-2/iterators-and-ownership.md:75 +#: src/exercises/day-2/iterators-and-ownership.md:91 +#: src/traits/trait-bounds.md:22 src/traits/impl-trait.md:14 +#: src/exercises/day-3/simple-gui.md:148 src/exercises/day-3/simple-gui.md:149 +#: src/exercises/day-3/simple-gui.md:150 src/testing/test-modules.md:21 +#: src/exercises/day-1/solutions-afternoon.md:49 +msgid "\"foo\"" +msgstr "" + +#: src/exercises/day-1/luhn.md:36 src/exercises/day-1/solutions-afternoon.md:50 +msgid "\"foo 0 0\"" +msgstr "" + +#: src/exercises/day-1/luhn.md:41 src/testing/unit-tests.md:15 +#: src/exercises/day-1/solutions-afternoon.md:55 +#: src/exercises/day-3/solutions-morning.md:90 +#: src/exercises/day-3/solutions-morning.md:92 +#: src/exercises/day-3/solutions-morning.md:96 +#: src/exercises/day-3/solutions-morning.md:110 +#: src/exercises/day-3/solutions-morning.md:114 +msgid "\"\"" +msgstr "" + +#: src/exercises/day-1/luhn.md:42 src/exercises/day-1/solutions-afternoon.md:56 +msgid "\" \"" +msgstr "" + +#: src/exercises/day-1/luhn.md:43 src/exercises/day-1/solutions-afternoon.md:57 +msgid "\" \"" +msgstr "" + +#: src/exercises/day-1/luhn.md:44 src/exercises/day-1/solutions-afternoon.md:58 +msgid "\" \"" +msgstr "" + +#: src/exercises/day-1/luhn.md:49 src/exercises/day-1/solutions-afternoon.md:63 +msgid "\"0\"" +msgstr "" + +#: src/exercises/day-1/luhn.md:54 src/exercises/day-1/solutions-afternoon.md:68 +msgid "\" 0 0 \"" +msgstr "" + +#: src/exercises/day-1/luhn.md:59 src/exercises/day-1/solutions-afternoon.md:73 +msgid "\"4263 9826 4026 9299\"" +msgstr "" + +#: src/exercises/day-1/luhn.md:60 src/exercises/day-1/solutions-afternoon.md:74 +msgid "\"4539 3195 0343 6467\"" +msgstr "" + +#: src/exercises/day-1/luhn.md:61 src/exercises/day-1/solutions-afternoon.md:75 +msgid "\"7992 7398 713\"" +msgstr "" + +#: src/exercises/day-1/luhn.md:66 src/exercises/day-1/solutions-afternoon.md:80 +msgid "\"4223 9826 4026 9299\"" +msgstr "" + +#: src/exercises/day-1/luhn.md:67 src/exercises/day-1/solutions-afternoon.md:81 +msgid "\"4539 3195 0343 6476\"" +msgstr "" + +#: src/exercises/day-1/luhn.md:68 src/exercises/day-1/solutions-afternoon.md:82 +msgid "\"8273 1232 7352 0569\"" msgstr "" #: src/exercises/day-1/pattern-matching.md:1 @@ -5156,102 +5158,50 @@ msgstr "" msgid "Let's write a simple recursive evaluator for arithmetic expressions. " msgstr "" -#: src/exercises/day-1/pattern-matching.md:5 -msgid "" -"```rust\n" -"/// An operation to perform on two subexpressions.\n" -"#[derive(Debug)]\n" -"enum Operation {\n" -" Add,\n" -" Sub,\n" -" Mul,\n" -" Div,\n" -"}\n" -"\n" -"/// An expression, in tree form.\n" -"#[derive(Debug)]\n" -"enum Expression {\n" -" /// An operation on two subexpressions.\n" -" Op {\n" -" op: Operation,\n" -" left: Box,\n" -" right: Box,\n" -" },\n" -"\n" -" /// A literal value\n" -" Value(i64),\n" -"}\n" -"\n" -"/// The result of evaluating an expression.\n" -"#[derive(Debug, PartialEq, Eq)]\n" -"enum Res {\n" -" /// Evaluation was successful, with the given result.\n" -" Ok(i64),\n" -" /// Evaluation failed, with the given error message.\n" -" Err(String),\n" -"}\n" -"// Allow `Ok` and `Err` as shorthands for `Res::Ok` and `Res::Err`.\n" -"use Res::{Err, Ok};\n" -"\n" -"fn eval(e: Expression) -> Res {\n" -" todo!()\n" -"}\n" -"\n" -"#[test]\n" -"fn test_value() {\n" -" assert_eq!(eval(Expression::Value(19)), Ok(19));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_sum() {\n" -" assert_eq!(\n" -" eval(Expression::Op {\n" -" op: Operation::Add,\n" -" left: Box::new(Expression::Value(10)),\n" -" right: Box::new(Expression::Value(20)),\n" -" }),\n" -" Ok(30)\n" -" );\n" -"}\n" -"\n" -"#[test]\n" -"fn test_recursion() {\n" -" let term1 = Expression::Op {\n" -" op: Operation::Mul,\n" -" left: Box::new(Expression::Value(10)),\n" -" right: Box::new(Expression::Value(9)),\n" -" };\n" -" let term2 = Expression::Op {\n" -" op: Operation::Mul,\n" -" left: Box::new(Expression::Op {\n" -" op: Operation::Sub,\n" -" left: Box::new(Expression::Value(3)),\n" -" right: Box::new(Expression::Value(4)),\n" -" }),\n" -" right: Box::new(Expression::Value(5)),\n" -" };\n" -" assert_eq!(\n" -" eval(Expression::Op {\n" -" op: Operation::Add,\n" -" left: Box::new(term1),\n" -" right: Box::new(term2),\n" -" }),\n" -" Ok(85)\n" -" );\n" -"}\n" -"\n" -"#[test]\n" -"fn test_error() {\n" -" assert_eq!(\n" -" eval(Expression::Op {\n" -" op: Operation::Div,\n" -" left: Box::new(Expression::Value(99)),\n" -" right: Box::new(Expression::Value(0)),\n" -" }),\n" -" Err(String::from(\"division by zero\"))\n" -" );\n" -"}\n" -"```" +#: src/exercises/day-1/pattern-matching.md:6 +#: src/exercises/day-1/solutions-afternoon.md:89 +msgid "/// An operation to perform on two subexpressions.\n" +msgstr "" + +#: src/exercises/day-1/pattern-matching.md:14 +#: src/exercises/day-1/solutions-afternoon.md:97 +msgid "/// An expression, in tree form.\n" +msgstr "" + +#: src/exercises/day-1/pattern-matching.md:18 +#: src/exercises/day-1/solutions-afternoon.md:101 +msgid "/// An operation on two subexpressions.\n" +msgstr "" + +#: src/exercises/day-1/pattern-matching.md:25 +#: src/exercises/day-1/solutions-afternoon.md:108 +msgid "/// A literal value\n" +msgstr "" + +#: src/exercises/day-1/pattern-matching.md:28 +#: src/exercises/day-1/solutions-afternoon.md:111 +msgid "/// The result of evaluating an expression.\n" +msgstr "" + +#: src/exercises/day-1/pattern-matching.md:32 +#: src/exercises/day-1/solutions-afternoon.md:115 +msgid "/// Evaluation was successful, with the given result.\n" +msgstr "" + +#: src/exercises/day-1/pattern-matching.md:34 +#: src/exercises/day-1/solutions-afternoon.md:117 +msgid "/// Evaluation failed, with the given error message.\n" +msgstr "" + +#: src/exercises/day-1/pattern-matching.md:36 +#: src/exercises/day-1/solutions-afternoon.md:119 +msgid "// Allow `Ok` and `Err` as shorthands for `Res::Ok` and `Res::Err`.\n" +msgstr "" + +#: src/exercises/day-1/pattern-matching.md:95 +#: src/exercises/day-1/solutions-afternoon.md:140 +#: src/exercises/day-1/solutions-afternoon.md:202 +msgid "\"division by zero\"" msgstr "" #: src/exercises/day-1/pattern-matching.md:100 @@ -5400,13 +5350,11 @@ msgid "" "sized data, the actual string, on the heap:" msgstr "" -#: src/memory-management/stack.md:6 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let s1 = String::from(\"Hello\");\n" -"}\n" -"```" +#: src/memory-management/stack.md:8 src/memory-management/stack.md:39 +#: src/std/string.md:8 src/traits/read-write.md:35 src/testing/unit-tests.md:20 +#: src/testing/unit-tests.md:25 src/testing/test-modules.md:12 +#: src/concurrency/scoped-threads.md:9 src/concurrency/scoped-threads.md:26 +msgid "\"Hello\"" msgstr "" #: src/memory-management/stack.md:28 @@ -5429,24 +5377,31 @@ msgid "" "point out that this is rightfully unsafe!" msgstr "" -#: src/memory-management/stack.md:37 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut s1 = String::from(\"Hello\");\n" -" s1.push(' ');\n" -" s1.push_str(\"world\");\n" -" // DON'T DO THIS AT HOME! For educational purposes only.\n" -" // String provides no guarantees about its layout, so this could lead " -"to\n" -" // undefined behavior.\n" -" unsafe {\n" -" let (ptr, capacity, len): (usize, usize, usize) = std::mem::" -"transmute(s1);\n" -" println!(\"ptr = {ptr:#x}, len = {len}, capacity = {capacity}\");\n" -" }\n" -"}\n" -"```" +#: src/memory-management/stack.md:40 src/testing/unit-tests.md:7 +#: src/exercises/day-1/solutions-afternoon.md:13 +msgid "' '" +msgstr "" + +#: src/memory-management/stack.md:41 +msgid "\"world\"" +msgstr "" + +#: src/memory-management/stack.md:42 +msgid "// DON'T DO THIS AT HOME! For educational purposes only." +msgstr "" + +#: src/memory-management/stack.md:43 +msgid "" +"// String provides no guarantees about its layout, so this could lead to" +msgstr "" + +#: src/memory-management/stack.md:44 +#, fuzzy +msgid "// undefined behavior." +msgstr "عدم وجود رفتار نامشخص در زمان اجرا." + +#: src/memory-management/stack.md:47 +msgid "\"ptr = {ptr:#x}, len = {len}, capacity = {capacity}\"" msgstr "" #: src/memory-management/manual.md:3 @@ -5467,17 +5422,12 @@ msgstr "" msgid "You must call `free` on every pointer you allocate with `malloc`:" msgstr "" -#: src/memory-management/manual.md:11 -msgid "" -"```c\n" -"void foo(size_t n) {\n" -" int* int_array = malloc(n * sizeof(int));\n" -" //\n" -" // ... lots of code\n" -" //\n" -" free(int_array);\n" -"}\n" -"```" +#: src/memory-management/manual.md:14 src/memory-management/manual.md:16 +msgid "//" +msgstr "" + +#: src/memory-management/manual.md:15 +msgid "// ... lots of code" msgstr "" #: src/memory-management/manual.md:21 @@ -5510,15 +5460,6 @@ msgstr "" msgid "C++ Example" msgstr "" -#: src/memory-management/scope-based.md:14 -msgid "" -"```c++\n" -"void say_hello(std::unique_ptr person) {\n" -" std::cout << \"Hello \" << person->name << std::endl;\n" -"}\n" -"```" -msgstr "" - #: src/memory-management/scope-based.md:20 msgid "" "The `std::unique_ptr` object is allocated on the stack, and points to memory " @@ -5566,15 +5507,6 @@ msgstr "" msgid "The `person` object is not deallocated after `sayHello` returns:" msgstr "" -#: src/memory-management/garbage-collection.md:13 -msgid "" -"```java\n" -"void sayHello(Person person) {\n" -" System.out.println(\"Hello \" + person.getName());\n" -"}\n" -"```" -msgstr "" - #: src/memory-management/rust.md:1 msgid "Memory Management in Rust" msgstr "" @@ -5641,16 +5573,13 @@ msgstr "" msgid "An assignment will transfer _ownership_ between variables:" msgstr "" -#: src/ownership/move-semantics.md:5 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let s1: String = String::from(\"Hello!\");\n" -" let s2: String = s1;\n" -" println!(\"s2: {s2}\");\n" -" // println!(\"s1: {s1}\");\n" -"}\n" -"```" +#: src/ownership/move-semantics.md:7 +#, fuzzy +msgid "\"Hello!\"" +msgstr "سلام دنیا" + +#: src/ownership/move-semantics.md:10 +msgid "// println!(\"s1: {s1}\");" msgstr "" #: src/ownership/move-semantics.md:14 @@ -5740,12 +5669,12 @@ msgstr "آزاد سازی مضاعف در مدرن سی++" msgid "Modern C++ solves this differently:" msgstr "" -#: src/ownership/double-free-modern-cpp.md:5 -msgid "" -"```c++\n" -"std::string s1 = \"Cpp\";\n" -"std::string s2 = s1; // Duplicate the data in s1.\n" -"```" +#: src/ownership/double-free-modern-cpp.md:6 +msgid "\"Cpp\"" +msgstr "" + +#: src/ownership/double-free-modern-cpp.md:7 +msgid "// Duplicate the data in s1." msgstr "" #: src/ownership/double-free-modern-cpp.md:10 @@ -5793,19 +5722,18 @@ msgid "" "parameter. This transfers ownership:" msgstr "" -#: src/ownership/moves-function-calls.md:6 -msgid "" -"```rust,editable\n" -"fn say_hello(name: String) {\n" -" println!(\"Hello {name}\")\n" -"}\n" -"\n" -"fn main() {\n" -" let name = String::from(\"Alice\");\n" -" say_hello(name);\n" -" // say_hello(name);\n" -"}\n" -"```" +#: src/ownership/moves-function-calls.md:8 src/traits/impl-trait.md:10 +msgid "\"Hello {name}\"" +msgstr "" + +#: src/ownership/moves-function-calls.md:12 +#: src/android/interoperability/java.md:56 +#, fuzzy +msgid "\"Alice\"" +msgstr "برش ها" + +#: src/ownership/moves-function-calls.md:14 +msgid "// say_hello(name);" msgstr "" #: src/ownership/moves-function-calls.md:20 @@ -6082,32 +6010,30 @@ msgid "" "If a data type stores borrowed data, it must be annotated with a lifetime:" msgstr "" -#: src/ownership/lifetimes-data-structures.md:5 -msgid "" -"```rust,editable\n" -"#[derive(Debug)]\n" -"struct Highlight<'doc>(&'doc str);\n" -"\n" -"fn erase(text: String) {\n" -" println!(\"Bye {text}!\");\n" -"}\n" -"\n" -"fn main() {\n" -" let text = String::from(\"The quick brown fox jumps over the lazy dog." -"\");\n" -" let fox = Highlight(&text[4..19]);\n" -" let dog = Highlight(&text[35..43]);\n" -" // erase(text);\n" -" println!(\"{fox:?}\");\n" -" println!(\"{dog:?}\");\n" -"}\n" -"```" +#: src/ownership/lifetimes-data-structures.md:10 +msgid "\"Bye {text}!\"" msgstr "" -#: src/ownership/lifetimes-data-structures.md:25 -msgid "" -"In the above example, the annotation on `Highlight` enforces that the data " -"underlying the contained `&str` lives at least as long as any instance of " +#: src/ownership/lifetimes-data-structures.md:14 +msgid "\"The quick brown fox jumps over the lazy dog.\"" +msgstr "" + +#: src/ownership/lifetimes-data-structures.md:17 +msgid "// erase(text);" +msgstr "" + +#: src/ownership/lifetimes-data-structures.md:18 +msgid "\"{fox:?}\"" +msgstr "" + +#: src/ownership/lifetimes-data-structures.md:19 +msgid "\"{dog:?}\"" +msgstr "" + +#: src/ownership/lifetimes-data-structures.md:25 +msgid "" +"In the above example, the annotation on `Highlight` enforces that the data " +"underlying the contained `&str` lives at least as long as any instance of " "`Highlight` that uses that data." msgstr "" @@ -6140,31 +6066,17 @@ msgstr "" msgid "Like C and C++, Rust has support for custom structs:" msgstr "" -#: src/structs.md:5 -msgid "" -"```rust,editable\n" -"struct Person {\n" -" name: String,\n" -" age: u8,\n" -"}\n" -"\n" -"fn main() {\n" -" let mut peter = Person {\n" -" name: String::from(\"Peter\"),\n" -" age: 27,\n" -" };\n" -" println!(\"{} is {} years old\", peter.name, peter.age);\n" -" \n" -" peter.age = 28;\n" -" println!(\"{} is {} years old\", peter.name, peter.age);\n" -" \n" -" let jackie = Person {\n" -" name: String::from(\"Jackie\"),\n" -" ..peter\n" -" };\n" -" println!(\"{} is {} years old\", jackie.name, jackie.age);\n" -"}\n" -"```" +#: src/structs.md:13 src/structs/field-shorthand.md:20 src/methods.md:21 +#: src/android/interoperability/with-c/bindgen.md:87 +msgid "\"Peter\"" +msgstr "" + +#: src/structs.md:16 src/structs.md:19 src/structs.md:25 +msgid "\"{} is {} years old\"" +msgstr "" + +#: src/structs.md:22 +msgid "\"Jackie\"" msgstr "" #: src/structs.md:33 @@ -6215,42 +6127,22 @@ msgstr "" msgid "If the field names are unimportant, you can use a tuple struct:" msgstr "" -#: src/structs/tuple-structs.md:5 -msgid "" -"```rust,editable\n" -"struct Point(i32, i32);\n" -"\n" -"fn main() {\n" -" let p = Point(17, 23);\n" -" println!(\"({}, {})\", p.0, p.1);\n" -"}\n" -"```" +#: src/structs/tuple-structs.md:10 +msgid "\"({}, {})\"" msgstr "" #: src/structs/tuple-structs.md:14 msgid "This is often used for single-field wrappers (called newtypes):" msgstr "" -#: src/structs/tuple-structs.md:16 -msgid "" -"```rust,editable,compile_fail\n" -"struct PoundsOfForce(f64);\n" -"struct Newtons(f64);\n" -"\n" -"fn compute_thruster_force() -> PoundsOfForce {\n" -" todo!(\"Ask a rocket scientist at NASA\")\n" -"}\n" -"\n" -"fn set_thruster_force(force: Newtons) {\n" -" // ...\n" -"}\n" -"\n" -"fn main() {\n" -" let force = compute_thruster_force();\n" -" set_thruster_force(force);\n" -"}\n" -"\n" -"```" +#: src/structs/tuple-structs.md:21 +msgid "\"Ask a rocket scientist at NASA\"" +msgstr "" + +#: src/structs/tuple-structs.md:25 +#: src/android/interoperability/cpp/cpp-bridge.md:50 +#: src/async/pitfalls/cancellation.md:96 src/async/pitfalls/cancellation.md:99 +msgid "// ..." msgstr "" #: src/structs/tuple-structs.md:37 @@ -6297,26 +6189,8 @@ msgid "" "struct using a shorthand:" msgstr "" -#: src/structs/field-shorthand.md:6 -msgid "" -"```rust,editable\n" -"#[derive(Debug)]\n" -"struct Person {\n" -" name: String,\n" -" age: u8,\n" -"}\n" -"\n" -"impl Person {\n" -" fn new(name: String, age: u8) -> Person {\n" -" Person { name, age }\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let peter = Person::new(String::from(\"Peter\"), 27);\n" -" println!(\"{peter:?}\");\n" -"}\n" -"```" +#: src/structs/field-shorthand.md:21 +msgid "\"{peter:?}\"" msgstr "" #: src/structs/field-shorthand.md:27 @@ -6331,32 +6205,12 @@ msgid "" "default values for the other fields." msgstr "" -#: src/structs/field-shorthand.md:43 -msgid "" -"```rust,editable\n" -"#[derive(Debug)]\n" -"struct Person {\n" -" name: String,\n" -" age: u8,\n" -"}\n" -"impl Default for Person {\n" -" fn default() -> Person {\n" -" Person {\n" -" name: \"Bot\".to_string(),\n" -" age: 0,\n" -" }\n" -" }\n" -"}\n" -"fn create_default() {\n" -" let tmp = Person {\n" -" ..Person::default()\n" -" };\n" -" let tmp = Person {\n" -" name: \"Sam\".to_string(),\n" -" ..Person::default()\n" -" };\n" -"}\n" -"```" +#: src/structs/field-shorthand.md:52 +msgid "\"Bot\"" +msgstr "" + +#: src/structs/field-shorthand.md:62 +msgid "\"Sam\"" msgstr "" #: src/structs/field-shorthand.md:68 @@ -6380,29 +6234,8 @@ msgid "" "an `impl` block:" msgstr "" -#: src/methods.md:6 -msgid "" -"```rust,editable\n" -"#[derive(Debug)]\n" -"struct Person {\n" -" name: String,\n" -" age: u8,\n" -"}\n" -"\n" -"impl Person {\n" -" fn say_hello(&self) {\n" -" println!(\"Hello, my name is {}\", self.name);\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let peter = Person {\n" -" name: String::from(\"Peter\"),\n" -" age: 27,\n" -" };\n" -" peter.say_hello();\n" -"}\n" -"```" +#: src/methods.md:15 +msgid "\"Hello, my name is {}\"" msgstr "" #: src/methods.md:31 @@ -6505,50 +6338,40 @@ msgid "" "multiple locations and call a mutating (`&mut self`) method on it." msgstr "" -#: src/methods/example.md:3 -msgid "" -"```rust,editable\n" -"#[derive(Debug)]\n" -"struct Race {\n" -" name: String,\n" -" laps: Vec,\n" -"}\n" -"\n" -"impl Race {\n" -" fn new(name: &str) -> Race { // No receiver, a static method\n" -" Race { name: String::from(name), laps: Vec::new() }\n" -" }\n" -"\n" -" fn add_lap(&mut self, lap: i32) { // Exclusive borrowed read-write " -"access to self\n" -" self.laps.push(lap);\n" -" }\n" -"\n" -" fn print_laps(&self) { // Shared and read-only borrowed access to self\n" -" println!(\"Recorded {} laps for {}:\", self.laps.len(), self.name);\n" -" for (idx, lap) in self.laps.iter().enumerate() {\n" -" println!(\"Lap {idx}: {lap} sec\");\n" -" }\n" -" }\n" -"\n" -" fn finish(self) { // Exclusive ownership of self\n" -" let total = self.laps.iter().sum::();\n" -" println!(\"Race {} is finished, total lap time: {}\", self.name, " -"total);\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let mut race = Race::new(\"Monaco Grand Prix\");\n" -" race.add_lap(70);\n" -" race.add_lap(68);\n" -" race.print_laps();\n" -" race.add_lap(71);\n" -" race.print_laps();\n" -" race.finish();\n" -" // race.add_lap(42);\n" -"}\n" -"```" +#: src/methods/example.md:11 +msgid "// No receiver, a static method" +msgstr "" + +#: src/methods/example.md:15 +msgid "// Exclusive borrowed read-write access to self" +msgstr "" + +#: src/methods/example.md:19 +msgid "// Shared and read-only borrowed access to self" +msgstr "" + +#: src/methods/example.md:20 +msgid "\"Recorded {} laps for {}:\"" +msgstr "" + +#: src/methods/example.md:22 +msgid "\"Lap {idx}: {lap} sec\"" +msgstr "" + +#: src/methods/example.md:26 +msgid "// Exclusive ownership of self" +msgstr "" + +#: src/methods/example.md:28 +msgid "\"Race {} is finished, total lap time: {}\"" +msgstr "" + +#: src/methods/example.md:33 +msgid "\"Monaco Grand Prix\"" +msgstr "" + +#: src/methods/example.md:40 +msgid "// race.add_lap(42);" msgstr "" #: src/methods/example.md:47 @@ -6602,19 +6425,12 @@ msgid "" "now, you just need to know part of its API:" msgstr "" -#: src/exercises/day-2/book-library.md:6 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut vec = vec![10, 20];\n" -" vec.push(30);\n" -" let midpoint = vec.len() / 2;\n" -" println!(\"middle value: {}\", vec[midpoint]);\n" -" for item in &vec {\n" -" println!(\"item: {item}\");\n" -" }\n" -"}\n" -"```" +#: src/exercises/day-2/book-library.md:11 +msgid "\"middle value: {}\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:13 +msgid "\"item: {item}\"" msgstr "" #: src/exercises/day-2/book-library.md:18 @@ -6623,28 +6439,14 @@ msgid "" " and update the types to make it compile:" msgstr "" -#: src/exercises/day-2/book-library.md:21 +#: src/exercises/day-2/book-library.md:32 +#: src/exercises/day-2/solutions-morning.md:18 +msgid "// This is a constructor, used below.\n" +msgstr "" + +#: src/exercises/day-2/book-library.md:40 +#: src/exercises/day-2/solutions-morning.md:26 msgid "" -"```rust,should_panic\n" -"struct Library {\n" -" books: Vec,\n" -"}\n" -"\n" -"struct Book {\n" -" title: String,\n" -" year: u16,\n" -"}\n" -"\n" -"impl Book {\n" -" // This is a constructor, used below.\n" -" fn new(title: &str, year: u16) -> Book {\n" -" Book {\n" -" title: String::from(title),\n" -" year,\n" -" }\n" -" }\n" -"}\n" -"\n" "// Implement the methods below. Notice how the `self` parameter\n" "// changes type to indicate the method's required level of ownership\n" "// over the object:\n" @@ -6652,61 +6454,74 @@ msgid "" "// - `&self` for shared read-only access,\n" "// - `&mut self` for unique and mutable access,\n" "// - `self` for unique access by value.\n" -"impl Library {\n" -" fn new() -> Library {\n" -" todo!(\"Initialize and return a `Library` value\")\n" -" }\n" -"\n" -" fn len(&self) -> usize {\n" -" todo!(\"Return the length of `self.books`\")\n" -" }\n" -"\n" -" fn is_empty(&self) -> bool {\n" -" todo!(\"Return `true` if `self.books` is empty\")\n" -" }\n" -"\n" -" fn add_book(&mut self, book: Book) {\n" -" todo!(\"Add a new book to `self.books`\")\n" -" }\n" -"\n" -" fn print_books(&self) {\n" -" todo!(\"Iterate over `self.books` and print each book's title and " -"year\")\n" -" }\n" -"\n" -" fn oldest_book(&self) -> Option<&Book> {\n" -" todo!(\"Return a reference to the oldest book (if any)\")\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let mut library = Library::new();\n" -"\n" -" println!(\n" -" \"The library is empty: library.is_empty() -> {}\",\n" -" library.is_empty()\n" -" );\n" -"\n" -" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n" -" library.add_book(Book::new(\"Alice's Adventures in Wonderland\", " -"1865));\n" -"\n" -" println!(\n" -" \"The library is no longer empty: library.is_empty() -> {}\",\n" -" library.is_empty()\n" -" );\n" -"\n" -" library.print_books();\n" -"\n" -" match library.oldest_book() {\n" -" Some(book) => println!(\"The oldest book is {}\", book.title),\n" -" None => println!(\"The library is empty!\"),\n" -" }\n" -"\n" -" println!(\"The library has {} books\", library.len());\n" -" library.print_books();\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/day-2/book-library.md:50 +msgid "\"Initialize and return a `Library` value\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:54 +msgid "\"Return the length of `self.books`\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:58 +msgid "\"Return `true` if `self.books` is empty\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:62 +msgid "\"Add a new book to `self.books`\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:66 +msgid "\"Iterate over `self.books` and print each book's title and year\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:70 +msgid "\"Return a reference to the oldest book (if any)\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:78 +#: src/exercises/day-2/solutions-morning.md:78 +msgid "\"The library is empty: library.is_empty() -> {}\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:82 +#: src/exercises/day-2/solutions-morning.md:82 +#: src/exercises/day-2/solutions-morning.md:107 +#: src/exercises/day-2/solutions-morning.md:118 +#: src/exercises/day-2/solutions-morning.md:125 +#: src/exercises/day-2/solutions-morning.md:137 +#: src/exercises/day-2/solutions-morning.md:140 +msgid "\"Lord of the Rings\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:83 +#: src/exercises/day-2/solutions-morning.md:83 +#: src/exercises/day-2/solutions-morning.md:108 +#: src/exercises/day-2/solutions-morning.md:126 +#: src/exercises/day-2/solutions-morning.md:143 +#: src/exercises/day-2/solutions-morning.md:146 +msgid "\"Alice's Adventures in Wonderland\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:86 +#: src/exercises/day-2/solutions-morning.md:86 +msgid "\"The library is no longer empty: library.is_empty() -> {}\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:93 +#: src/exercises/day-2/solutions-morning.md:93 +msgid "\"The oldest book is {}\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:94 +#: src/exercises/day-2/solutions-morning.md:94 +msgid "\"The library is empty!\"" +msgstr "" + +#: src/exercises/day-2/book-library.md:97 +#: src/exercises/day-2/solutions-morning.md:97 +msgid "\"The library has {} books\"" msgstr "" #: src/exercises/day-2/health-statistics.md:3 @@ -6728,109 +6543,57 @@ msgid "" "methods:" msgstr "" -#: src/exercises/day-2/health-statistics.md:13 +#: src/exercises/day-2/health-statistics.md:39 +msgid "\"Create a new User instance\"" +msgstr "" + +#: src/exercises/day-2/health-statistics.md:43 +msgid "\"Return the user's name\"" +msgstr "" + +#: src/exercises/day-2/health-statistics.md:47 +msgid "\"Return the user's age\"" +msgstr "" + +#: src/exercises/day-2/health-statistics.md:51 +msgid "\"Return the user's height\"" +msgstr "" + +#: src/exercises/day-2/health-statistics.md:55 +msgid "\"Return the number of time the user has visited the doctor\"" +msgstr "" + +#: src/exercises/day-2/health-statistics.md:59 +msgid "\"Set the user's age\"" +msgstr "" + +#: src/exercises/day-2/health-statistics.md:63 +msgid "\"Set the user's height\"" +msgstr "" + +#: src/exercises/day-2/health-statistics.md:67 msgid "" -"```rust,should_panic\n" -"// TODO: remove this when you're done with your implementation.\n" -"#![allow(unused_variables, dead_code)]\n" -"\n" -"pub struct User {\n" -" name: String,\n" -" age: u32,\n" -" height: f32,\n" -" visit_count: usize,\n" -" last_blood_pressure: Option<(u32, u32)>,\n" -"}\n" -"\n" -"pub struct Measurements {\n" -" height: f32,\n" -" blood_pressure: (u32, u32),\n" -"}\n" -"\n" -"pub struct HealthReport<'a> {\n" -" patient_name: &'a str,\n" -" visit_count: u32,\n" -" height_change: f32,\n" -" blood_pressure_change: Option<(i32, i32)>,\n" -"}\n" -"\n" -"impl User {\n" -" pub fn new(name: String, age: u32, height: f32) -> Self {\n" -" todo!(\"Create a new User instance\")\n" -" }\n" -"\n" -" pub fn name(&self) -> &str {\n" -" todo!(\"Return the user's name\")\n" -" }\n" -"\n" -" pub fn age(&self) -> u32 {\n" -" todo!(\"Return the user's age\")\n" -" }\n" -"\n" -" pub fn height(&self) -> f32 {\n" -" todo!(\"Return the user's height\")\n" -" }\n" -"\n" -" pub fn doctor_visits(&self) -> u32 {\n" -" todo!(\"Return the number of time the user has visited the " -"doctor\")\n" -" }\n" -"\n" -" pub fn set_age(&mut self, new_age: u32) {\n" -" todo!(\"Set the user's age\")\n" -" }\n" -"\n" -" pub fn set_height(&mut self, new_height: f32) {\n" -" todo!(\"Set the user's height\")\n" -" }\n" -"\n" -" pub fn visit_doctor(&mut self, measurements: Measurements) -> " -"HealthReport {\n" -" todo!(\"Update a user's statistics based on measurements from a " -"visit to the doctor\")\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let bob = User::new(String::from(\"Bob\"), 32, 155.2);\n" -" println!(\"I'm {} and my age is {}\", bob.name(), bob.age());\n" -"}\n" -"\n" -"#[test]\n" -"fn test_height() {\n" -" let bob = User::new(String::from(\"Bob\"), 32, 155.2);\n" -" assert_eq!(bob.height(), 155.2);\n" -"}\n" -"\n" -"#[test]\n" -"fn test_set_age() {\n" -" let mut bob = User::new(String::from(\"Bob\"), 32, 155.2);\n" -" assert_eq!(bob.age(), 32);\n" -" bob.set_age(33);\n" -" assert_eq!(bob.age(), 33);\n" -"}\n" -"\n" -"#[test]\n" -"fn test_visit() {\n" -" let mut bob = User::new(String::from(\"Bob\"), 32, 155.2);\n" -" assert_eq!(bob.doctor_visits(), 0);\n" -" let report = bob.visit_doctor(Measurements {\n" -" height: 156.1,\n" -" blood_pressure: (120, 80),\n" -" });\n" -" assert_eq!(report.patient_name, \"Bob\");\n" -" assert_eq!(report.visit_count, 1);\n" -" assert_eq!(report.blood_pressure_change, None);\n" -"\n" -" let report = bob.visit_doctor(Measurements {\n" -" height: 156.1,\n" -" blood_pressure: (115, 76),\n" -" });\n" -"\n" -" assert_eq!(report.visit_count, 2);\n" -" assert_eq!(report.blood_pressure_change, Some((-5, -4)));\n" -"}\n" -"```" +"\"Update a user's statistics based on measurements from a visit to the " +"doctor\"" +msgstr "" + +#: src/exercises/day-2/health-statistics.md:72 +#: src/exercises/day-2/health-statistics.md:78 +#: src/exercises/day-2/health-statistics.md:84 +#: src/exercises/day-2/health-statistics.md:92 +#: src/exercises/day-2/health-statistics.md:98 +#: src/android/build-rules/library.md:43 src/android/aidl/client.md:23 +#: src/exercises/day-2/solutions-morning.md:233 +#: src/exercises/day-2/solutions-morning.md:239 +#: src/exercises/day-2/solutions-morning.md:245 +#: src/exercises/day-2/solutions-morning.md:253 +#: src/exercises/day-2/solutions-morning.md:259 +msgid "\"Bob\"" +msgstr "" + +#: src/exercises/day-2/health-statistics.md:73 +#: src/exercises/day-2/solutions-morning.md:234 +msgid "\"I'm {} and my age is {}\"" msgstr "" #: src/std.md:3 @@ -6905,18 +6668,12 @@ msgstr "" msgid "The types represent optional data:" msgstr "" -#: src/std/option-result.md:5 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let numbers = vec![10, 20, 30];\n" -" let first: Option<&i8> = numbers.first();\n" -" println!(\"first: {first:?}\");\n" -"\n" -" let arr: Result<[i8; 3], Vec> = numbers.try_into();\n" -" println!(\"arr: {arr:?}\");\n" -"}\n" -"```" +#: src/std/option-result.md:9 +msgid "\"first: {first:?}\"" +msgstr "" + +#: src/std/option-result.md:12 +msgid "\"arr: {arr:?}\"" msgstr "" #: src/std/option-result.md:18 @@ -6954,24 +6711,24 @@ msgid "" "standard heap-allocated growable UTF-8 string buffer:" msgstr "" -#: src/std/string.md:5 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut s1 = String::new();\n" -" s1.push_str(\"Hello\");\n" -" println!(\"s1: len = {}, capacity = {}\", s1.len(), s1.capacity());\n" -"\n" -" let mut s2 = String::with_capacity(s1.len() + 1);\n" -" s2.push_str(&s1);\n" -" s2.push('!');\n" -" println!(\"s2: len = {}, capacity = {}\", s2.len(), s2.capacity());\n" -"\n" -" let s3 = String::from(\"🇨🇭\");\n" -" println!(\"s3: len = {}, number of chars = {}\", s3.len(),\n" -" s3.chars().count());\n" -"}\n" -"```" +#: src/std/string.md:9 +msgid "\"s1: len = {}, capacity = {}\"" +msgstr "" + +#: src/std/string.md:13 +msgid "'!'" +msgstr "" + +#: src/std/string.md:14 +msgid "\"s2: len = {}, capacity = {}\"" +msgstr "" + +#: src/std/string.md:16 +msgid "\"🇨🇭\"" +msgstr "" + +#: src/std/string.md:17 +msgid "\"s3: len = {}, number of chars = {}\"" msgstr "" #: src/std/string.md:22 @@ -7056,31 +6813,28 @@ msgid "" "resizable heap-allocated buffer:" msgstr "" -#: src/std/vec.md:5 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut v1 = Vec::new();\n" -" v1.push(42);\n" -" println!(\"v1: len = {}, capacity = {}\", v1.len(), v1.capacity());\n" -"\n" -" let mut v2 = Vec::with_capacity(v1.len() + 1);\n" -" v2.extend(v1.iter());\n" -" v2.push(9999);\n" -" println!(\"v2: len = {}, capacity = {}\", v2.len(), v2.capacity());\n" -"\n" -" // Canonical macro to initialize a vector with elements.\n" -" let mut v3 = vec![0, 0, 1, 2, 3, 4];\n" -"\n" -" // Retain only the even elements.\n" -" v3.retain(|x| x % 2 == 0);\n" -" println!(\"{v3:?}\");\n" -"\n" -" // Remove consecutive duplicates.\n" -" v3.dedup();\n" -" println!(\"{v3:?}\");\n" -"}\n" -"```" +#: src/std/vec.md:9 +msgid "\"v1: len = {}, capacity = {}\"" +msgstr "" + +#: src/std/vec.md:14 +msgid "\"v2: len = {}, capacity = {}\"" +msgstr "" + +#: src/std/vec.md:16 +msgid "// Canonical macro to initialize a vector with elements." +msgstr "" + +#: src/std/vec.md:19 +msgid "// Retain only the even elements." +msgstr "" + +#: src/std/vec.md:21 src/std/vec.md:25 +msgid "\"{v3:?}\"" +msgstr "" + +#: src/std/vec.md:23 +msgid "// Remove consecutive duplicates." msgstr "" #: src/std/vec.md:29 @@ -7131,42 +6885,44 @@ msgstr "" msgid "Standard hash map with protection against HashDoS attacks:" msgstr "" -#: src/std/hashmap.md:5 -msgid "" -"```rust,editable\n" -"use std::collections::HashMap;\n" -"\n" -"fn main() {\n" -" let mut page_counts = HashMap::new();\n" -" page_counts.insert(\"Adventures of Huckleberry Finn\".to_string(), " -"207);\n" -" page_counts.insert(\"Grimms' Fairy Tales\".to_string(), 751);\n" -" page_counts.insert(\"Pride and Prejudice\".to_string(), 303);\n" -"\n" -" if !page_counts.contains_key(\"Les Misérables\") {\n" -" println!(\"We know about {} books, but not Les Misérables.\",\n" -" page_counts.len());\n" -" }\n" -"\n" -" for book in [\"Pride and Prejudice\", \"Alice's Adventure in " -"Wonderland\"] {\n" -" match page_counts.get(book) {\n" -" Some(count) => println!(\"{book}: {count} pages\"),\n" -" None => println!(\"{book} is unknown.\")\n" -" }\n" -" }\n" -"\n" -" // Use the .entry() method to insert a value if nothing is found.\n" -" for book in [\"Pride and Prejudice\", \"Alice's Adventure in " -"Wonderland\"] {\n" -" let page_count: &mut i32 = page_counts.entry(book.to_string())." -"or_insert(0);\n" -" *page_count += 1;\n" -" }\n" -"\n" -" println!(\"{page_counts:#?}\");\n" -"}\n" -"```" +#: src/std/hashmap.md:10 +msgid "\"Adventures of Huckleberry Finn\"" +msgstr "" + +#: src/std/hashmap.md:11 +msgid "\"Grimms' Fairy Tales\"" +msgstr "" + +#: src/std/hashmap.md:12 src/std/hashmap.md:19 src/std/hashmap.md:27 +msgid "\"Pride and Prejudice\"" +msgstr "" + +#: src/std/hashmap.md:14 +msgid "\"Les Misérables\"" +msgstr "" + +#: src/std/hashmap.md:15 +msgid "\"We know about {} books, but not Les Misérables.\"" +msgstr "" + +#: src/std/hashmap.md:19 src/std/hashmap.md:27 +msgid "\"Alice's Adventure in Wonderland\"" +msgstr "" + +#: src/std/hashmap.md:21 +msgid "\"{book}: {count} pages\"" +msgstr "" + +#: src/std/hashmap.md:22 +msgid "\"{book} is unknown.\"" +msgstr "" + +#: src/std/hashmap.md:26 +msgid "// Use the .entry() method to insert a value if nothing is found." +msgstr "" + +#: src/std/hashmap.md:32 +msgid "\"{page_counts:#?}\"" msgstr "" #: src/std/hashmap.md:38 @@ -7181,16 +6937,12 @@ msgid "" "the alternative value in the hashmap if the book is not found." msgstr "" -#: src/std/hashmap.md:41 -msgid "" -"```rust,ignore\n" -" let pc1 = page_counts\n" -" .get(\"Harry Potter and the Sorcerer's Stone\")\n" -" .unwrap_or(&336);\n" -" let pc2 = page_counts\n" -" .entry(\"The Hunger Games\".to_string())\n" -" .or_insert(374);\n" -"```" +#: src/std/hashmap.md:43 src/std/hashmap.md:54 +msgid "\"Harry Potter and the Sorcerer's Stone\"" +msgstr "" + +#: src/std/hashmap.md:46 src/std/hashmap.md:55 +msgid "\"The Hunger Games\"" msgstr "" #: src/std/hashmap.md:49 @@ -7205,16 +6957,6 @@ msgid "" "us to easily initialize a hash map from a literal array:" msgstr "" -#: src/std/hashmap.md:52 -msgid "" -"```rust,ignore\n" -" let page_counts = HashMap::from([\n" -" (\"Harry Potter and the Sorcerer's Stone\".to_string(), 336),\n" -" (\"The Hunger Games\".to_string(), 374),\n" -" ]);\n" -"```" -msgstr "" - #: src/std/hashmap.md:59 msgid "" "Alternatively HashMap can be built from any `Iterator` which yields key-" @@ -7252,14 +6994,8 @@ msgid "" "pointer to data on the heap:" msgstr "" -#: src/std/box.md:5 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let five = Box::new(5);\n" -" println!(\"five: {}\", *five);\n" -"}\n" -"```" +#: src/std/box.md:8 +msgid "\"five: {}\"" msgstr "" #: src/std/box.md:26 @@ -7307,21 +7043,8 @@ msgid "" "Recursive data types or data types with dynamic sizes need to use a `Box`:" msgstr "" -#: src/std/box-recursive.md:5 src/std/box-niche.md:3 -msgid "" -"```rust,editable\n" -"#[derive(Debug)]\n" -"enum List {\n" -" Cons(T, Box>),\n" -" Nil,\n" -"}\n" -"\n" -"fn main() {\n" -" let list: List = List::Cons(1, Box::new(List::Cons(2, Box::" -"new(List::Nil))));\n" -" println!(\"{list:?}\");\n" -"}\n" -"```" +#: src/std/box-recursive.md:14 src/std/box-niche.md:12 +msgid "\"{list:?}\"" msgstr "" #: src/std/box-recursive.md:18 @@ -7405,19 +7128,12 @@ msgid "" "from multiple places:" msgstr "" -#: src/std/rc.md:6 -msgid "" -"```rust,editable\n" -"use std::rc::Rc;\n" -"\n" -"fn main() {\n" -" let mut a = Rc::new(10);\n" -" let mut b = Rc::clone(&a);\n" -"\n" -" println!(\"a: {a}\");\n" -" println!(\"b: {b}\");\n" -"}\n" -"```" +#: src/std/rc.md:13 +msgid "\"a: {a}\"" +msgstr "" + +#: src/std/rc.md:14 +msgid "\"b: {b}\"" msgstr "" #: src/std/rc.md:18 @@ -7485,41 +7201,12 @@ msgid "" "shared and exclusive references at runtime and panics if they are misused." msgstr "" -#: src/std/cell.md:12 -msgid "" -"```rust,editable\n" -"use std::cell::RefCell;\n" -"use std::rc::Rc;\n" -"\n" -"#[derive(Debug, Default)]\n" -"struct Node {\n" -" value: i64,\n" -" children: Vec>>,\n" -"}\n" -"\n" -"impl Node {\n" -" fn new(value: i64) -> Rc> {\n" -" Rc::new(RefCell::new(Node { value, ..Node::default() }))\n" -" }\n" -"\n" -" fn sum(&self) -> i64 {\n" -" self.value + self.children.iter().map(|c| c.borrow().sum()).sum::" -"()\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let root = Node::new(1);\n" -" root.borrow_mut().children.push(Node::new(5));\n" -" let subtree = Node::new(10);\n" -" subtree.borrow_mut().children.push(Node::new(11));\n" -" subtree.borrow_mut().children.push(Node::new(12));\n" -" root.borrow_mut().children.push(subtree);\n" -"\n" -" println!(\"graph: {root:#?}\");\n" -" println!(\"graph sum: {}\", root.borrow().sum());\n" -"}\n" -"```" +#: src/std/cell.md:40 +msgid "\"graph: {root:#?}\"" +msgstr "" + +#: src/std/cell.md:41 +msgid "\"graph sum: {}\"" msgstr "" #: src/std/cell.md:47 @@ -7558,26 +7245,12 @@ msgstr "" msgid "Similarly, `mod` lets us namespace types and functions:" msgstr "" -#: src/modules.md:7 -msgid "" -"```rust,editable\n" -"mod foo {\n" -" pub fn do_something() {\n" -" println!(\"In the foo module\");\n" -" }\n" -"}\n" -"\n" -"mod bar {\n" -" pub fn do_something() {\n" -" println!(\"In the bar module\");\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" foo::do_something();\n" -" bar::do_something();\n" -"}\n" -"```" +#: src/modules.md:10 +msgid "\"In the foo module\"" +msgstr "" + +#: src/modules.md:16 +msgid "\"In the bar module\"" msgstr "" #: src/modules.md:28 @@ -7614,34 +7287,20 @@ msgid "" "the descendants of `foo`." msgstr "" -#: src/modules/visibility.md:10 -msgid "" -"```rust,editable\n" -"mod outer {\n" -" fn private() {\n" -" println!(\"outer::private\");\n" -" }\n" -"\n" -" pub fn public() {\n" -" println!(\"outer::public\");\n" -" }\n" -"\n" -" mod inner {\n" -" fn private() {\n" -" println!(\"outer::inner::private\");\n" -" }\n" -"\n" -" pub fn public() {\n" -" println!(\"outer::inner::public\");\n" -" super::private();\n" -" }\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" outer::public();\n" -"}\n" -"```" +#: src/modules/visibility.md:13 +msgid "\"outer::private\"" +msgstr "" + +#: src/modules/visibility.md:17 +msgid "\"outer::public\"" +msgstr "" + +#: src/modules/visibility.md:22 +msgid "\"outer::inner::private\"" +msgstr "" + +#: src/modules/visibility.md:26 +msgid "\"outer::inner::public\"" msgstr "" #: src/modules/visibility.md:39 @@ -7739,23 +7398,27 @@ msgid "" "module." msgstr "" -#: src/modules/filesystem.md:20 +#: src/modules/filesystem.md:21 msgid "" -"```rust,editable,compile_fail\n" "//! This module implements the garden, including a highly performant " -"germination\n" -"//! implementation.\n" -"\n" -"// Re-export types from this module.\n" -"pub use seeds::SeedPacket;\n" -"pub use garden::Garden;\n" -"\n" -"/// Sow the given seed packets.\n" -"pub fn sow(seeds: Vec) { todo!() }\n" -"\n" -"/// Harvest the produce in the garden that is ready.\n" -"pub fn harvest(garden: &mut Garden) { todo!() }\n" -"```" +"germination" +msgstr "" + +#: src/modules/filesystem.md:21 +#, fuzzy +msgid "//! implementation." +msgstr "پیاده سازی" + +#: src/modules/filesystem.md:23 +msgid "// Re-export types from this module." +msgstr "" + +#: src/modules/filesystem.md:27 +msgid "/// Sow the given seed packets." +msgstr "" + +#: src/modules/filesystem.md:30 +msgid "/// Harvest the produce in the garden that is ready." msgstr "" #: src/modules/filesystem.md:37 @@ -7780,12 +7443,8 @@ msgid "" "directive:" msgstr "" -#: src/modules/filesystem.md:54 -msgid "" -"```rust,ignore\n" -"#[path = \"some/path.rs\"]\n" -"mod some_module;\n" -"```" +#: src/modules/filesystem.md:55 +msgid "\"some/path.rs\"" msgstr "" #: src/modules/filesystem.md:59 @@ -7825,36 +7484,29 @@ msgstr "" msgid "You use this trait like this:" msgstr "" -#: src/exercises/day-2/iterators-and-ownership.md:22 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let v: Vec = vec![10, 20, 30];\n" -" let mut iter = v.iter();\n" -"\n" -" println!(\"v[0]: {:?}\", iter.next());\n" -" println!(\"v[1]: {:?}\", iter.next());\n" -" println!(\"v[2]: {:?}\", iter.next());\n" -" println!(\"No more items: {:?}\", iter.next());\n" -"}\n" -"```" +#: src/exercises/day-2/iterators-and-ownership.md:27 +msgid "\"v[0]: {:?}\"" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:28 +msgid "\"v[1]: {:?}\"" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:29 +msgid "\"v[2]: {:?}\"" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:30 +msgid "\"No more items: {:?}\"" msgstr "" #: src/exercises/day-2/iterators-and-ownership.md:34 msgid "What is the type returned by the iterator? Test your answer here:" msgstr "" -#: src/exercises/day-2/iterators-and-ownership.md:36 -msgid "" -"```rust,editable,compile_fail\n" -"fn main() {\n" -" let v: Vec = vec![10, 20, 30];\n" -" let mut iter = v.iter();\n" -"\n" -" let v0: Option<..> = iter.next();\n" -" println!(\"v0: {v0:?}\");\n" -"}\n" -"```" +#: src/exercises/day-2/iterators-and-ownership.md:42 +#: src/exercises/day-2/iterators-and-ownership.md:79 +msgid "\"v0: {v0:?}\"" msgstr "" #: src/exercises/day-2/iterators-and-ownership.md:46 @@ -7896,18 +7548,10 @@ msgstr "" msgid "Like before, what is the type returned by the iterator?" msgstr "" -#: src/exercises/day-2/iterators-and-ownership.md:73 -msgid "" -"```rust,editable,compile_fail\n" -"fn main() {\n" -" let v: Vec = vec![String::from(\"foo\"), String::" -"from(\"bar\")];\n" -" let mut iter = v.into_iter();\n" -"\n" -" let v0: Option<..> = iter.next();\n" -" println!(\"v0: {v0:?}\");\n" -"}\n" -"```" +#: src/exercises/day-2/iterators-and-ownership.md:75 +#: src/exercises/day-2/iterators-and-ownership.md:91 +#: src/testing/test-modules.md:21 +msgid "\"bar\"" msgstr "" #: src/exercises/day-2/iterators-and-ownership.md:83 @@ -7921,22 +7565,9 @@ msgid "" "resulting iterator:" msgstr "" -#: src/exercises/day-2/iterators-and-ownership.md:89 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let v: Vec = vec![String::from(\"foo\"), String::" -"from(\"bar\")];\n" -"\n" -" for word in &v {\n" -" println!(\"word: {word}\");\n" -" }\n" -"\n" -" for word in v {\n" -" println!(\"word: {word}\");\n" -" }\n" -"}\n" -"```" +#: src/exercises/day-2/iterators-and-ownership.md:94 +#: src/exercises/day-2/iterators-and-ownership.md:98 +msgid "\"word: {word}\"" msgstr "" #: src/exercises/day-2/iterators-and-ownership.md:103 @@ -7966,53 +7597,79 @@ msgid "" "pass. Try avoiding allocating a `Vec` for your intermediate results:" msgstr "" -#: src/exercises/day-2/strings-iterators.md:12 -msgid "" -"```rust\n" -"// TODO: remove this when you're done with your implementation.\n" -"#![allow(unused_variables, dead_code)]\n" -"\n" -"pub fn prefix_matches(prefix: &str, request_path: &str) -> bool {\n" -" unimplemented!()\n" -"}\n" -"\n" -"#[test]\n" -"fn test_matches_without_wildcard() {\n" -" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers\"));\n" -" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/" -"abc-123\"));\n" -" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/abc/" -"books\"));\n" -"\n" -" assert!(!prefix_matches(\"/v1/publishers\", \"/v1\"));\n" -" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/publishersBooks\"));\n" -" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/parent/" -"publishers\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_matches_with_wildcard() {\n" -" assert!(prefix_matches(\n" -" \"/v1/publishers/*/books\",\n" -" \"/v1/publishers/foo/books\"\n" -" ));\n" -" assert!(prefix_matches(\n" -" \"/v1/publishers/*/books\",\n" -" \"/v1/publishers/bar/books\"\n" -" ));\n" -" assert!(prefix_matches(\n" -" \"/v1/publishers/*/books\",\n" -" \"/v1/publishers/foo/books/book1\"\n" -" ));\n" -"\n" -" assert!(!prefix_matches(\"/v1/publishers/*/books\", \"/v1/" -"publishers\"));\n" -" assert!(!prefix_matches(\n" -" \"/v1/publishers/*/books\",\n" -" \"/v1/publishers/foo/booksByAuthor\"\n" -" ));\n" -"}\n" -"```" +#: src/exercises/day-2/strings-iterators.md:22 +#: src/exercises/day-2/strings-iterators.md:23 +#: src/exercises/day-2/strings-iterators.md:24 +#: src/exercises/day-2/strings-iterators.md:26 +#: src/exercises/day-2/strings-iterators.md:27 +#: src/exercises/day-2/strings-iterators.md:28 +#: src/exercises/day-2/strings-iterators.md:46 +#: src/exercises/day-2/solutions-afternoon.md:32 +#: src/exercises/day-2/solutions-afternoon.md:33 +#: src/exercises/day-2/solutions-afternoon.md:34 +#: src/exercises/day-2/solutions-afternoon.md:36 +#: src/exercises/day-2/solutions-afternoon.md:37 +#: src/exercises/day-2/solutions-afternoon.md:38 +#: src/exercises/day-2/solutions-afternoon.md:56 +msgid "\"/v1/publishers\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:23 +#: src/exercises/day-2/solutions-afternoon.md:33 +msgid "\"/v1/publishers/abc-123\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:24 +#: src/exercises/day-2/solutions-afternoon.md:34 +msgid "\"/v1/publishers/abc/books\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:26 +#: src/exercises/day-2/solutions-afternoon.md:36 +msgid "\"/v1\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:27 +#: src/exercises/day-2/solutions-afternoon.md:37 +msgid "\"/v1/publishersBooks\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:28 +#: src/exercises/day-2/solutions-afternoon.md:38 +msgid "\"/v1/parent/publishers\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:34 +#: src/exercises/day-2/strings-iterators.md:38 +#: src/exercises/day-2/strings-iterators.md:42 +#: src/exercises/day-2/strings-iterators.md:46 +#: src/exercises/day-2/strings-iterators.md:48 +#: src/exercises/day-2/solutions-afternoon.md:44 +#: src/exercises/day-2/solutions-afternoon.md:48 +#: src/exercises/day-2/solutions-afternoon.md:52 +#: src/exercises/day-2/solutions-afternoon.md:56 +#: src/exercises/day-2/solutions-afternoon.md:58 +msgid "\"/v1/publishers/*/books\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:35 +#: src/exercises/day-2/solutions-afternoon.md:45 +msgid "\"/v1/publishers/foo/books\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:39 +#: src/exercises/day-2/solutions-afternoon.md:49 +msgid "\"/v1/publishers/bar/books\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:43 +#: src/exercises/day-2/solutions-afternoon.md:53 +msgid "\"/v1/publishers/foo/books/book1\"" +msgstr "" + +#: src/exercises/day-2/strings-iterators.md:49 +#: src/exercises/day-2/solutions-afternoon.md:59 +msgid "\"/v1/publishers/foo/booksByAuthor\"" msgstr "" #: src/welcome-day-3.md:1 @@ -8059,21 +7716,8 @@ msgstr "" msgid "You can use generics to abstract over the concrete field type:" msgstr "" -#: src/generics/data-types.md:5 -msgid "" -"```rust,editable\n" -"#[derive(Debug)]\n" -"struct Point {\n" -" x: T,\n" -" y: T,\n" -"}\n" -"\n" -"fn main() {\n" -" let integer = Point { x: 5, y: 10 };\n" -" let float = Point { x: 1.0, y: 4.0 };\n" -" println!(\"{integer:?} and {float:?}\");\n" -"}\n" -"```" +#: src/generics/data-types.md:15 +msgid "\"{integer:?} and {float:?}\"" msgstr "" #: src/generics/data-types.md:21 @@ -8088,25 +7732,16 @@ msgstr "" msgid "You can declare a generic type on your `impl` block:" msgstr "" -#: src/generics/methods.md:5 -msgid "" -"```rust,editable\n" -"#[derive(Debug)]\n" -"struct Point(T, T);\n" -"\n" -"impl Point {\n" -" fn x(&self) -> &T {\n" -" &self.0 // + 10\n" -" }\n" -"\n" -" // fn set_x(&mut self, x: T)\n" -"}\n" -"\n" -"fn main() {\n" -" let p = Point(5, 10);\n" -" println!(\"p.x = {}\", p.x());\n" -"}\n" -"```" +#: src/generics/methods.md:11 +msgid "// + 10" +msgstr "" + +#: src/generics/methods.md:14 +msgid "// fn set_x(&mut self, x: T)" +msgstr "" + +#: src/generics/methods.md:19 +msgid "\"p.x = {}\"" msgstr "" #: src/generics/methods.md:25 @@ -8154,37 +7789,24 @@ msgid "" "Rust lets you abstract over types with traits. They're similar to interfaces:" msgstr "" -#: src/traits.md:5 -msgid "" -"```rust,editable\n" -"struct Dog { name: String, age: i8 }\n" -"struct Cat { lives: i8 } // No name needed, cats won't respond anyway.\n" -"\n" -"trait Pet {\n" -" fn talk(&self) -> String;\n" -"}\n" -"\n" -"impl Pet for Dog {\n" -" fn talk(&self) -> String { format!(\"Woof, my name is {}!\", self." -"name) }\n" -"}\n" -"\n" -"impl Pet for Cat {\n" -" fn talk(&self) -> String { String::from(\"Miau!\") }\n" -"}\n" -"\n" -"fn greet(pet: &P) {\n" -" println!(\"Oh you're a cutie! What's your name? {}\", pet.talk());\n" -"}\n" -"\n" -"fn main() {\n" -" let captain_floof = Cat { lives: 9 };\n" -" let fido = Dog { name: String::from(\"Fido\"), age: 5 };\n" -"\n" -" greet(&captain_floof);\n" -" greet(&fido);\n" -"}\n" -"```" +#: src/traits.md:7 src/traits/trait-objects.md:7 +msgid "// No name needed, cats won't respond anyway." +msgstr "" + +#: src/traits.md:14 src/traits/trait-objects.md:14 +msgid "\"Woof, my name is {}!\"" +msgstr "" + +#: src/traits.md:18 src/traits/trait-objects.md:18 +msgid "\"Miau!\"" +msgstr "" + +#: src/traits.md:22 +msgid "\"Oh you're a cutie! What's your name? {}\"" +msgstr "" + +#: src/traits.md:27 src/traits/trait-objects.md:24 +msgid "\"Fido\"" msgstr "" #: src/traits/trait-objects.md:3 @@ -8193,35 +7815,8 @@ msgid "" "collection:" msgstr "" -#: src/traits/trait-objects.md:5 -msgid "" -"```rust,editable\n" -"struct Dog { name: String, age: i8 }\n" -"struct Cat { lives: i8 } // No name needed, cats won't respond anyway.\n" -"\n" -"trait Pet {\n" -" fn talk(&self) -> String;\n" -"}\n" -"\n" -"impl Pet for Dog {\n" -" fn talk(&self) -> String { format!(\"Woof, my name is {}!\", self." -"name) }\n" -"}\n" -"\n" -"impl Pet for Cat {\n" -" fn talk(&self) -> String { String::from(\"Miau!\") }\n" -"}\n" -"\n" -"fn main() {\n" -" let pets: Vec> = vec![\n" -" Box::new(Cat { lives: 9 }),\n" -" Box::new(Dog { name: String::from(\"Fido\"), age: 5 }),\n" -" ];\n" -" for pet in pets {\n" -" println!(\"Hello, who are you? {}\", pet.talk());\n" -" }\n" -"}\n" -"```" +#: src/traits/trait-objects.md:27 +msgid "\"Hello, who are you? {}\"" msgstr "" #: src/traits/trait-objects.md:32 @@ -8325,16 +7920,17 @@ msgstr "" msgid "Compare these outputs in the above example:" msgstr "" -#: src/traits/trait-objects.md:80 -msgid "" -"```rust,ignore\n" -" println!(\"{} {}\", std::mem::size_of::(), std::mem::size_of::" -"());\n" -" println!(\"{} {}\", std::mem::size_of::<&Dog>(), std::mem::size_of::" -"<&Cat>());\n" -" println!(\"{}\", std::mem::size_of::<&dyn Pet>());\n" -" println!(\"{}\", std::mem::size_of::>());\n" -"```" +#: src/traits/trait-objects.md:81 src/traits/trait-objects.md:82 +#: src/traits/closures.md:54 +msgid "\"{} {}\"" +msgstr "" + +#: src/traits/trait-objects.md:83 src/traits/trait-objects.md:84 +#: src/testing/test-modules.md:12 src/android/build-rules/library.md:43 +#: src/android/interoperability/cpp/rust-bridge.md:17 +#: src/async/pitfalls/cancellation.md:59 +#: src/exercises/day-3/solutions-morning.md:128 +msgid "\"{}\"" msgstr "" #: src/traits/deriving-traits.md:3 @@ -8347,55 +7943,30 @@ msgstr "" msgid "You can let the compiler derive a number of traits as follows:" msgstr "" -#: src/traits/deriving-traits.md:7 -msgid "" -"```rust,editable\n" -"#[derive(Debug, Clone, PartialEq, Eq, Default)]\n" -"struct Player {\n" -" name: String,\n" -" strength: u8,\n" -" hit_points: u8,\n" -"}\n" -"\n" -"fn main() {\n" -" let p1 = Player::default();\n" -" let p2 = p1.clone();\n" -" println!(\"Is {:?}\\nequal to {:?}?\\nThe answer is {}!\", &p1, &p2,\n" -" if p1 == p2 { \"yes\" } else { \"no\" });\n" -"}\n" -"```" +#: src/traits/deriving-traits.md:18 +msgid "\"Is {:?}\\nequal to {:?}?\\nThe answer is {}!\"" +msgstr "" + +#: src/traits/deriving-traits.md:19 +#: src/exercises/day-1/solutions-afternoon.md:43 +msgid "\"yes\"" +msgstr "" + +#: src/traits/deriving-traits.md:19 +#: src/exercises/day-1/solutions-afternoon.md:43 +msgid "\"no\"" msgstr "" #: src/traits/default-methods.md:3 msgid "Traits can implement behavior in terms of other trait methods:" msgstr "" -#: src/traits/default-methods.md:5 -msgid "" -"```rust,editable\n" -"trait Equals {\n" -" fn equals(&self, other: &Self) -> bool;\n" -" fn not_equals(&self, other: &Self) -> bool {\n" -" !self.equals(other)\n" -" }\n" -"}\n" -"\n" -"#[derive(Debug)]\n" -"struct Centimeter(i16);\n" -"\n" -"impl Equals for Centimeter {\n" -" fn equals(&self, other: &Centimeter) -> bool {\n" -" self.0 == other.0\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let a = Centimeter(10);\n" -" let b = Centimeter(20);\n" -" println!(\"{a:?} equals {b:?}: {}\", a.equals(&b));\n" -" println!(\"{a:?} not_equals {b:?}: {}\", a.not_equals(&b));\n" -"}\n" -"```" +#: src/traits/default-methods.md:25 +msgid "\"{a:?} equals {b:?}: {}\"" +msgstr "" + +#: src/traits/default-methods.md:26 +msgid "\"{a:?} not_equals {b:?}: {}\"" msgstr "" #: src/traits/default-methods.md:32 @@ -8433,32 +8004,28 @@ msgstr "" msgid "You can do this with `T: Trait` or `impl Trait`:" msgstr "" -#: src/traits/trait-bounds.md:8 -msgid "" -"```rust,editable\n" -"fn duplicate(a: T) -> (T, T) {\n" -" (a.clone(), a.clone())\n" -"}\n" -"\n" -"// Syntactic sugar for:\n" -"// fn add_42_millions>(x: T) -> i32 {\n" -"fn add_42_millions(x: impl Into) -> i32 {\n" -" x.into() + 42_000_000\n" -"}\n" -"\n" -"// struct NotClonable;\n" -"\n" -"fn main() {\n" -" let foo = String::from(\"foo\");\n" -" let pair = duplicate(foo);\n" -" println!(\"{pair:?}\");\n" -"\n" -" let many = add_42_millions(42_i8);\n" -" println!(\"{many}\");\n" -" let many_more = add_42_millions(10_000_000);\n" -" println!(\"{many_more}\");\n" -"}\n" -"```" +#: src/traits/trait-bounds.md:12 +msgid "// Syntactic sugar for:" +msgstr "" + +#: src/traits/trait-bounds.md:13 +msgid "// fn add_42_millions>(x: T) -> i32 {" +msgstr "" + +#: src/traits/trait-bounds.md:18 +msgid "// struct NotClonable;" +msgstr "" + +#: src/traits/trait-bounds.md:24 +msgid "\"{pair:?}\"" +msgstr "" + +#: src/traits/trait-bounds.md:27 +msgid "\"{many}\"" +msgstr "" + +#: src/traits/trait-bounds.md:29 +msgid "\"{many_more}\"" msgstr "" #: src/traits/trait-bounds.md:35 @@ -8489,22 +8056,6 @@ msgid "" "arguments and return values:" msgstr "" -#: src/traits/impl-trait.md:6 -msgid "" -"```rust,editable\n" -"use std::fmt::Display;\n" -"\n" -"fn get_x(name: impl Display) -> impl Display {\n" -" format!(\"Hello {name}\")\n" -"}\n" -"\n" -"fn main() {\n" -" let x = get_x(\"foo\");\n" -" println!(\"{x}\");\n" -"}\n" -"```" -msgstr "" - #: src/traits/impl-trait.md:19 msgid "`impl Trait` allows you to work with types which you cannot name." msgstr "" @@ -8603,32 +8154,8 @@ msgid "" "Iterator.html) trait on your own types:" msgstr "" -#: src/traits/iterator.md:5 -msgid "" -"```rust,editable\n" -"struct Fibonacci {\n" -" curr: u32,\n" -" next: u32,\n" -"}\n" -"\n" -"impl Iterator for Fibonacci {\n" -" type Item = u32;\n" -"\n" -" fn next(&mut self) -> Option {\n" -" let new_next = self.curr + self.next;\n" -" self.curr = self.next;\n" -" self.next = new_next;\n" -" Some(self.curr)\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let fib = Fibonacci { curr: 0, next: 1 };\n" -" for (i, n) in fib.enumerate().take(5) {\n" -" println!(\"fib({i}): {n}\");\n" -" }\n" -"}\n" -"```" +#: src/traits/iterator.md:25 +msgid "\"fib({i}): {n}\"" msgstr "" #: src/traits/iterator.md:32 @@ -8655,18 +8182,8 @@ msgid "" "std/iter/trait.Iterator.html)." msgstr "" -#: src/traits/from-iterator.md:5 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let primes = vec![2, 3, 5, 7];\n" -" let prime_squares = primes\n" -" .into_iter()\n" -" .map(|prime| prime * prime)\n" -" .collect::>();\n" -" println!(\"prime_squares: {prime_squares:?}\");\n" -"}\n" -"```" +#: src/traits/from-iterator.md:12 +msgid "\"prime_squares: {prime_squares:?}\"" msgstr "" #: src/traits/from-iterator.md:18 @@ -8692,17 +8209,8 @@ msgid "" "facilitate type conversions:" msgstr "" -#: src/traits/from-into.md:5 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let s = String::from(\"hello\");\n" -" let addr = std::net::Ipv4Addr::from([127, 0, 0, 1]);\n" -" let one = i16::from(true);\n" -" let bigger = i32::from(123i16);\n" -" println!(\"{s}, {addr}, {one}, {bigger}\");\n" -"}\n" -"```" +#: src/traits/from-into.md:11 src/traits/from-into.md:23 +msgid "\"{s}, {addr}, {one}, {bigger}\"" msgstr "" #: src/traits/from-into.md:15 @@ -8712,19 +8220,6 @@ msgid "" "convert/trait.From.html) is implemented:" msgstr "" -#: src/traits/from-into.md:17 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let s: String = \"hello\".into();\n" -" let addr: std::net::Ipv4Addr = [127, 0, 0, 1].into();\n" -" let one: i16 = true.into();\n" -" let bigger: i32 = 123i16.into();\n" -" println!(\"{s}, {addr}, {one}, {bigger}\");\n" -"}\n" -"```" -msgstr "" - #: src/traits/from-into.md:29 msgid "" "That's why it is common to only implement `From`, as your type will get " @@ -8750,25 +8245,16 @@ msgid "" "abstract over `u8` sources:" msgstr "" -#: src/traits/read-write.md:5 -msgid "" -"```rust,editable\n" -"use std::io::{BufRead, BufReader, Read, Result};\n" -"\n" -"fn count_lines(reader: R) -> usize {\n" -" let buf_reader = BufReader::new(reader);\n" -" buf_reader.lines().count()\n" -"}\n" -"\n" -"fn main() -> Result<()> {\n" -" let slice: &[u8] = b\"foo\\nbar\\nbaz\\n\";\n" -" println!(\"lines in slice: {}\", count_lines(slice));\n" -"\n" -" let file = std::fs::File::open(std::env::current_exe()?)?;\n" -" println!(\"lines in file: {}\", count_lines(file));\n" -" Ok(())\n" -"}\n" -"```" +#: src/traits/read-write.md:14 +msgid "b\"foo\\nbar\\nbaz\\n\"" +msgstr "" + +#: src/traits/read-write.md:15 +msgid "\"lines in slice: {}\"" +msgstr "" + +#: src/traits/read-write.md:18 +msgid "\"lines in file: {}\"" msgstr "" #: src/traits/read-write.md:23 @@ -8777,24 +8263,12 @@ msgid "" "you abstract over `u8` sinks:" msgstr "" -#: src/traits/read-write.md:25 -msgid "" -"```rust,editable\n" -"use std::io::{Result, Write};\n" -"\n" -"fn log(writer: &mut W, msg: &str) -> Result<()> {\n" -" writer.write_all(msg.as_bytes())?;\n" -" writer.write_all(\"\\n\".as_bytes())\n" -"}\n" -"\n" -"fn main() -> Result<()> {\n" -" let mut buffer = Vec::new();\n" -" log(&mut buffer, \"Hello\")?;\n" -" log(&mut buffer, \"World\")?;\n" -" println!(\"Logged: {:?}\", buffer);\n" -" Ok(())\n" -"}\n" -"```" +#: src/traits/read-write.md:30 +msgid "\"\\n\"" +msgstr "" + +#: src/traits/read-write.md:37 +msgid "\"Logged: {:?}\"" msgstr "" #: src/traits/drop.md:1 @@ -8807,37 +8281,41 @@ msgid "" "html) can specify code to run when they go out of scope:" msgstr "" -#: src/traits/drop.md:5 -msgid "" -"```rust,editable\n" -"struct Droppable {\n" -" name: &'static str,\n" -"}\n" -"\n" -"impl Drop for Droppable {\n" -" fn drop(&mut self) {\n" -" println!(\"Dropping {}\", self.name);\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let a = Droppable { name: \"a\" };\n" -" {\n" -" let b = Droppable { name: \"b\" };\n" -" {\n" -" let c = Droppable { name: \"c\" };\n" -" let d = Droppable { name: \"d\" };\n" -" println!(\"Exiting block B\");\n" -" }\n" -" println!(\"Exiting block A\");\n" -" }\n" -" drop(a);\n" -" println!(\"Exiting main\");\n" -"}\n" -"```" +#: src/traits/drop.md:12 +msgid "\"Dropping {}\"" msgstr "" -#: src/traits/drop.md:34 +#: src/traits/drop.md:17 src/exercises/concurrency/link-checker.md:92 +#: src/exercises/day-1/solutions-morning.md:86 +#: src/exercises/concurrency/solutions-morning.md:123 +msgid "\"a\"" +msgstr "" + +#: src/traits/drop.md:19 src/exercises/day-1/solutions-morning.md:86 +msgid "\"b\"" +msgstr "" + +#: src/traits/drop.md:21 src/exercises/day-1/solutions-morning.md:86 +msgid "\"c\"" +msgstr "" + +#: src/traits/drop.md:22 src/exercises/day-1/solutions-morning.md:86 +msgid "\"d\"" +msgstr "" + +#: src/traits/drop.md:23 +msgid "\"Exiting block B\"" +msgstr "" + +#: src/traits/drop.md:25 +msgid "\"Exiting block A\"" +msgstr "" + +#: src/traits/drop.md:28 +msgid "\"Exiting main\"" +msgstr "" + +#: src/traits/drop.md:34 msgid "Note that `std::mem::drop` is not the same as `std::ops::Drop::drop`." msgstr "" @@ -8898,40 +8376,24 @@ msgid "" "produces a default value for a type." msgstr "" -#: src/traits/default.md:5 -msgid "" -"```rust,editable\n" -"#[derive(Debug, Default)]\n" -"struct Derived {\n" -" x: u32,\n" -" y: String,\n" -" z: Implemented,\n" -"}\n" -"\n" -"#[derive(Debug)]\n" -"struct Implemented(String);\n" -"\n" -"impl Default for Implemented {\n" -" fn default() -> Self {\n" -" Self(\"John Smith\".into())\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let default_struct = Derived::default();\n" -" println!(\"{default_struct:#?}\");\n" -"\n" -" let almost_default_struct = Derived {\n" -" y: \"Y is set!\".into(),\n" -" ..Derived::default()\n" -" };\n" -" println!(\"{almost_default_struct:#?}\");\n" -"\n" -" let nothing: Option = None;\n" -" println!(\"{:#?}\", nothing.unwrap_or_default());\n" -"}\n" -"\n" -"```" +#: src/traits/default.md:18 +msgid "\"John Smith\"" +msgstr "" + +#: src/traits/default.md:24 +msgid "\"{default_struct:#?}\"" +msgstr "" + +#: src/traits/default.md:27 +msgid "\"Y is set!\"" +msgstr "" + +#: src/traits/default.md:30 +msgid "\"{almost_default_struct:#?}\"" +msgstr "" + +#: src/traits/default.md:33 +msgid "\"{:#?}\"" msgstr "" #: src/traits/default.md:40 @@ -8982,26 +8444,8 @@ msgid "" "rust-lang.org/std/ops/index.html):" msgstr "" -#: src/traits/operators.md:5 -msgid "" -"```rust,editable\n" -"#[derive(Debug, Copy, Clone)]\n" -"struct Point { x: i32, y: i32 }\n" -"\n" -"impl std::ops::Add for Point {\n" -" type Output = Self;\n" -"\n" -" fn add(self, other: Self) -> Self {\n" -" Self {x: self.x + other.x, y: self.y + other.y}\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let p1 = Point { x: 10, y: 20 };\n" -" let p2 = Point { x: 100, y: 200 };\n" -" println!(\"{:?} + {:?} = {:?}\", p1, p2, p1 + p2);\n" -"}\n" -"```" +#: src/traits/operators.md:20 +msgid "\"{:?} + {:?} = {:?}\"" msgstr "" #: src/traits/operators.md:28 @@ -9047,31 +8491,21 @@ msgid "" "[`FnOnce`](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) traits:" msgstr "" -#: src/traits/closures.md:8 -msgid "" -"```rust,editable\n" -"fn apply_with_log(func: impl FnOnce(i32) -> i32, input: i32) -> i32 {\n" -" println!(\"Calling function on {input}\");\n" -" func(input)\n" -"}\n" -"\n" -"fn main() {\n" -" let add_3 = |x| x + 3;\n" -" println!(\"add_3: {}\", apply_with_log(add_3, 10));\n" -" println!(\"add_3: {}\", apply_with_log(add_3, 20));\n" -"\n" -" let mut v = Vec::new();\n" -" let mut accumulate = |x: i32| {\n" -" v.push(x);\n" -" v.iter().sum::()\n" -" };\n" -" println!(\"accumulate: {}\", apply_with_log(&mut accumulate, 4));\n" -" println!(\"accumulate: {}\", apply_with_log(&mut accumulate, 5));\n" -"\n" -" let multiply_sum = |x| x * v.into_iter().sum::();\n" -" println!(\"multiply_sum: {}\", apply_with_log(multiply_sum, 3));\n" -"}\n" -"```" +#: src/traits/closures.md:10 +#, fuzzy +msgid "\"Calling function on {input}\"" +msgstr "فراخوانی متدهای ناامن" + +#: src/traits/closures.md:16 src/traits/closures.md:17 +msgid "\"add_3: {}\"" +msgstr "" + +#: src/traits/closures.md:24 src/traits/closures.md:25 +msgid "\"accumulate: {}\"" +msgstr "" + +#: src/traits/closures.md:28 +msgid "\"multiply_sum: {}\"" msgstr "" #: src/traits/closures.md:34 @@ -9112,18 +8546,12 @@ msgid "" "keyword makes them capture by value." msgstr "" -#: src/traits/closures.md:52 -msgid "" -"```rust,editable\n" -"fn make_greeter(prefix: String) -> impl Fn(&str) {\n" -" return move |name| println!(\"{} {}\", prefix, name)\n" -"}\n" -"\n" -"fn main() {\n" -" let hi = make_greeter(\"Hi\".to_string());\n" -" hi(\"there\");\n" -"}\n" -"```" +#: src/traits/closures.md:58 +msgid "\"Hi\"" +msgstr "" + +#: src/traits/closures.md:59 +msgid "\"there\"" msgstr "" #: src/exercises/day-3/morning.md:1 @@ -9182,117 +8610,39 @@ msgid "" "`draw_into` methods so that you implement the `Widget` trait:" msgstr "" -#: src/exercises/day-3/simple-gui.md:19 -msgid "" -"```rust,should_panic\n" -"// TODO: remove this when you're done with your implementation.\n" -"#![allow(unused_imports, unused_variables, dead_code)]\n" -"\n" -"pub trait Widget {\n" -" /// Natural width of `self`.\n" -" fn width(&self) -> usize;\n" -"\n" -" /// Draw the widget into a buffer.\n" -" fn draw_into(&self, buffer: &mut dyn std::fmt::Write);\n" -"\n" -" /// Draw the widget on standard output.\n" -" fn draw(&self) {\n" -" let mut buffer = String::new();\n" -" self.draw_into(&mut buffer);\n" -" println!(\"{buffer}\");\n" -" }\n" -"}\n" -"\n" -"pub struct Label {\n" -" label: String,\n" -"}\n" -"\n" -"impl Label {\n" -" fn new(label: &str) -> Label {\n" -" Label {\n" -" label: label.to_owned(),\n" -" }\n" -" }\n" -"}\n" -"\n" -"pub struct Button {\n" -" label: Label,\n" -"}\n" -"\n" -"impl Button {\n" -" fn new(label: &str) -> Button {\n" -" Button {\n" -" label: Label::new(label),\n" -" }\n" -" }\n" -"}\n" -"\n" -"pub struct Window {\n" -" title: String,\n" -" widgets: Vec>,\n" -"}\n" -"\n" -"impl Window {\n" -" fn new(title: &str) -> Window {\n" -" Window {\n" -" title: title.to_owned(),\n" -" widgets: Vec::new(),\n" -" }\n" -" }\n" -"\n" -" fn add_widget(&mut self, widget: Box) {\n" -" self.widgets.push(widget);\n" -" }\n" -"\n" -" fn inner_width(&self) -> usize {\n" -" std::cmp::max(\n" -" self.title.chars().count(),\n" -" self.widgets.iter().map(|w| w.width()).max().unwrap_or(0),\n" -" )\n" -" }\n" -"}\n" -"\n" -"\n" -"impl Widget for Label {\n" -" fn width(&self) -> usize {\n" -" unimplemented!()\n" -" }\n" -"\n" -" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n" -" unimplemented!()\n" -" }\n" -"}\n" -"\n" -"impl Widget for Button {\n" -" fn width(&self) -> usize {\n" -" unimplemented!()\n" -" }\n" -"\n" -" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n" -" unimplemented!()\n" -" }\n" -"}\n" -"\n" -"impl Widget for Window {\n" -" fn width(&self) -> usize {\n" -" unimplemented!()\n" -" }\n" -"\n" -" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n" -" unimplemented!()\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let mut window = Window::new(\"Rust GUI Demo 1.23\");\n" -" window.add_widget(Box::new(Label::new(\"This is a small text GUI demo." -"\")));\n" -" window.add_widget(Box::new(Button::new(\n" -" \"Click me!\"\n" -" )));\n" -" window.draw();\n" -"}\n" -"```" +#: src/exercises/day-3/simple-gui.md:24 +#: src/exercises/day-3/solutions-morning.md:9 +msgid "/// Natural width of `self`.\n" +msgstr "" + +#: src/exercises/day-3/simple-gui.md:27 +#: src/exercises/day-3/solutions-morning.md:12 +msgid "/// Draw the widget into a buffer.\n" +msgstr "" + +#: src/exercises/day-3/simple-gui.md:30 +#: src/exercises/day-3/solutions-morning.md:15 +msgid "/// Draw the widget on standard output.\n" +msgstr "" + +#: src/exercises/day-3/simple-gui.md:34 +#: src/exercises/day-3/solutions-morning.md:19 +msgid "\"{buffer}\"" +msgstr "" + +#: src/exercises/day-3/simple-gui.md:119 +#: src/exercises/day-3/solutions-morning.md:133 +msgid "\"Rust GUI Demo 1.23\"" +msgstr "" + +#: src/exercises/day-3/simple-gui.md:120 +#: src/exercises/day-3/solutions-morning.md:134 +msgid "\"This is a small text GUI demo.\"" +msgstr "" + +#: src/exercises/day-3/simple-gui.md:122 +#: src/exercises/day-3/solutions-morning.md:136 +msgid "\"Click me!\"" msgstr "" #: src/exercises/day-3/simple-gui.md:128 @@ -9307,16 +8657,16 @@ msgid "" "and how you can control alignment:" msgstr "" -#: src/exercises/day-3/simple-gui.md:145 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let width = 10;\n" -" println!(\"left aligned: |{:/width$}|\", \"foo\");\n" -"}\n" -"```" +#: src/exercises/day-3/simple-gui.md:148 +msgid "\"left aligned: |{:/width$}|\"" msgstr "" #: src/exercises/day-3/simple-gui.md:154 @@ -9335,117 +8685,19 @@ msgid "" "make the tests pass:" msgstr "" -#: src/exercises/day-3/points-polygons.md:7 -msgid "" -"```rust\n" -"// TODO: remove this when you're done with your implementation.\n" -"#![allow(unused_variables, dead_code)]\n" -"\n" -"pub struct Point {\n" -" // add fields\n" -"}\n" -"\n" -"impl Point {\n" -" // add methods\n" -"}\n" -"\n" -"pub struct Polygon {\n" -" // add fields\n" -"}\n" -"\n" -"impl Polygon {\n" -" // add methods\n" -"}\n" -"\n" -"pub struct Circle {\n" -" // add fields\n" -"}\n" -"\n" -"impl Circle {\n" -" // add methods\n" -"}\n" -"\n" -"pub enum Shape {\n" -" Polygon(Polygon),\n" -" Circle(Circle),\n" -"}\n" -"\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::*;\n" -"\n" -" fn round_two_digits(x: f64) -> f64 {\n" -" (x * 100.0).round() / 100.0\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_magnitude() {\n" -" let p1 = Point::new(12, 13);\n" -" assert_eq!(round_two_digits(p1.magnitude()), 17.69);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_dist() {\n" -" let p1 = Point::new(10, 10);\n" -" let p2 = Point::new(14, 13);\n" -" assert_eq!(round_two_digits(p1.dist(p2)), 5.00);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_add() {\n" -" let p1 = Point::new(16, 16);\n" -" let p2 = p1 + Point::new(-4, 3);\n" -" assert_eq!(p2, Point::new(12, 19));\n" -" }\n" -"\n" -" #[test]\n" -" fn test_polygon_left_most_point() {\n" -" let p1 = Point::new(12, 13);\n" -" let p2 = Point::new(16, 16);\n" -"\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(p1);\n" -" poly.add_point(p2);\n" -" assert_eq!(poly.left_most_point(), Some(p1));\n" -" }\n" -"\n" -" #[test]\n" -" fn test_polygon_iter() {\n" -" let p1 = Point::new(12, 13);\n" -" let p2 = Point::new(16, 16);\n" -"\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(p1);\n" -" poly.add_point(p2);\n" -"\n" -" let points = poly.iter().cloned().collect::>();\n" -" assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_shape_perimeters() {\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(Point::new(12, 13));\n" -" poly.add_point(Point::new(17, 11));\n" -" poly.add_point(Point::new(16, 16));\n" -" let shapes = vec![\n" -" Shape::from(poly),\n" -" Shape::from(Circle::new(Point::new(10, 20), 5)),\n" -" ];\n" -" let perimeters = shapes\n" -" .iter()\n" -" .map(Shape::perimeter)\n" -" .map(round_two_digits)\n" -" .collect::>();\n" -" assert_eq!(perimeters, vec![15.48, 31.42]);\n" -" }\n" -"}\n" -"\n" -"#[allow(dead_code)]\n" -"fn main() {}\n" -"```" +#: src/exercises/day-3/points-polygons.md:12 +#: src/exercises/day-3/points-polygons.md:20 +#: src/exercises/day-3/points-polygons.md:28 +msgid "// add fields" msgstr "" +#: src/exercises/day-3/points-polygons.md:16 +#: src/exercises/day-3/points-polygons.md:24 +#: src/exercises/day-3/points-polygons.md:32 +#, fuzzy +msgid "// add methods" +msgstr "رشته‌ها و تکرارکننده‌ها (Strings and Iterators)" + #: src/exercises/day-3/points-polygons.md:117 msgid "" "Since the method signatures are missing from the problem statements, the key " @@ -9485,14 +8737,8 @@ msgstr "" msgid "Rust will trigger a panic if a fatal error happens at runtime:" msgstr "" -#: src/error-handling/panics.md:5 -msgid "" -"```rust,editable,should_panic\n" -"fn main() {\n" -" let v = vec![10, 20, 30];\n" -" println!(\"v[100]: {}\", v[100]);\n" -"}\n" -"```" +#: src/error-handling/panics.md:8 +msgid "\"v[100]: {}\"" msgstr "" #: src/error-handling/panics.md:12 @@ -9518,23 +8764,16 @@ msgid "" "caught:" msgstr "" -#: src/error-handling/panic-unwind.md:5 -msgid "" -"```rust,editable\n" -"use std::panic;\n" -"\n" -"fn main() {\n" -" let result = panic::catch_unwind(|| {\n" -" \"No problem here!\"\n" -" });\n" -" println!(\"{result:?}\");\n" -"\n" -" let result = panic::catch_unwind(|| {\n" -" panic!(\"oh no!\");\n" -" });\n" -" println!(\"{result:?}\");\n" -"}\n" -"```" +#: src/error-handling/panic-unwind.md:10 +msgid "\"No problem here!\"" +msgstr "" + +#: src/error-handling/panic-unwind.md:12 src/error-handling/panic-unwind.md:17 +msgid "\"{result:?}\"" +msgstr "" + +#: src/error-handling/panic-unwind.md:15 +msgid "\"oh no!\"" msgstr "" #: src/error-handling/panic-unwind.md:21 @@ -9557,26 +8796,16 @@ msgid "" "are expected as part of normal operation:" msgstr "" -#: src/error-handling/result.md:6 -msgid "" -"```rust,editable\n" -"use std::fs;\n" -"use std::io::Read;\n" -"\n" -"fn main() {\n" -" let file = fs::File::open(\"diary.txt\");\n" -" match file {\n" -" Ok(mut file) => {\n" -" let mut contents = String::new();\n" -" file.read_to_string(&mut contents);\n" -" println!(\"Dear diary: {contents}\");\n" -" },\n" -" Err(err) => {\n" -" println!(\"The diary could not be opened: {err}\");\n" -" }\n" -" }\n" -"}\n" -"```" +#: src/error-handling/result.md:11 +msgid "\"diary.txt\"" +msgstr "" + +#: src/error-handling/result.md:16 +msgid "\"Dear diary: {contents}\"" +msgstr "" + +#: src/error-handling/result.md:19 +msgid "\"The diary could not be opened: {err}\"" msgstr "" #: src/error-handling/result.md:27 @@ -9612,32 +8841,21 @@ msgstr "" msgid "We can use this to simplify our error handling code:" msgstr "" -#: src/error-handling/try-operator.md:21 -msgid "" -"```rust,editable\n" -"use std::{fs, io};\n" -"use std::io::Read;\n" -"\n" -"fn read_username(path: &str) -> Result {\n" -" let username_file_result = fs::File::open(path);\n" -" let mut username_file = match username_file_result {\n" -" Ok(file) => file,\n" -" Err(err) => return Err(err),\n" -" };\n" -"\n" -" let mut username = String::new();\n" -" match username_file.read_to_string(&mut username) {\n" -" Ok(_) => Ok(username),\n" -" Err(err) => Err(err),\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" //fs::write(\"config.dat\", \"alice\").unwrap();\n" -" let username = read_username(\"config.dat\");\n" -" println!(\"username or error: {username:?}\");\n" -"}\n" -"```" +#: src/error-handling/try-operator.md:40 +msgid "//fs::write(\"config.dat\", \"alice\").unwrap();" +msgstr "" + +#: src/error-handling/try-operator.md:41 +#: src/error-handling/converting-error-types-example.md:43 +#: src/error-handling/deriving-error-enums.md:30 +#: src/error-handling/dynamic-errors.md:27 +#: src/error-handling/error-contexts.md:26 +msgid "\"config.dat\"" +msgstr "" + +#: src/error-handling/try-operator.md:42 +#: src/error-handling/converting-error-types-example.md:44 +msgid "\"username or error: {username:?}\"" msgstr "" #: src/error-handling/try-operator.md:50 @@ -9683,56 +8901,22 @@ msgstr "" #: src/error-handling/converting-error-types.md:18 msgid "" "The `From::from` call here means we attempt to convert the error type to the " -"type returned by the function:" +"type returned by the function." msgstr "" -#: src/error-handling/converting-error-types-example.md:3 -msgid "" -"```rust,editable\n" -"use std::error::Error;\n" -"use std::fmt::{self, Display, Formatter};\n" -"use std::fs::{self, File};\n" -"use std::io::{self, Read};\n" -"\n" -"#[derive(Debug)]\n" -"enum ReadUsernameError {\n" -" IoError(io::Error),\n" -" EmptyUsername(String),\n" -"}\n" -"\n" -"impl Error for ReadUsernameError {}\n" -"\n" -"impl Display for ReadUsernameError {\n" -" fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n" -" match self {\n" -" Self::IoError(e) => write!(f, \"IO error: {e}\"),\n" -" Self::EmptyUsername(filename) => write!(f, \"Found no username " -"in {filename}\"),\n" -" }\n" -" }\n" -"}\n" -"\n" -"impl From for ReadUsernameError {\n" -" fn from(err: io::Error) -> ReadUsernameError {\n" -" ReadUsernameError::IoError(err)\n" -" }\n" -"}\n" -"\n" -"fn read_username(path: &str) -> Result {\n" -" let mut username = String::with_capacity(100);\n" -" File::open(path)?.read_to_string(&mut username)?;\n" -" if username.is_empty() {\n" -" return Err(ReadUsernameError::EmptyUsername(String::from(path)));\n" -" }\n" -" Ok(username)\n" -"}\n" -"\n" -"fn main() {\n" -" //fs::write(\"config.dat\", \"\").unwrap();\n" -" let username = read_username(\"config.dat\");\n" -" println!(\"username or error: {username:?}\");\n" -"}\n" -"```" +#: src/error-handling/converting-error-types-example.md:20 +msgid "\"IO error: {e}\"" +msgstr "" + +#: src/error-handling/converting-error-types-example.md:21 +msgid "\"Found no username in {filename}\"" +msgstr "" + +#: src/error-handling/converting-error-types-example.md:42 +#: src/error-handling/deriving-error-enums.md:29 +#: src/error-handling/dynamic-errors.md:26 +#: src/error-handling/error-contexts.md:25 +msgid "//fs::write(\"config.dat\", \"\").unwrap();" msgstr "" #: src/error-handling/converting-error-types-example.md:55 @@ -9756,38 +8940,24 @@ msgid "" "an error enum like we did on the previous page:" msgstr "" -#: src/error-handling/deriving-error-enums.md:6 -msgid "" -"```rust,editable,compile_fail\n" -"use std::{fs, io};\n" -"use std::io::Read;\n" -"use thiserror::Error;\n" -"\n" -"#[derive(Debug, Error)]\n" -"enum ReadUsernameError {\n" -" #[error(\"Could not read: {0}\")]\n" -" IoError(#[from] io::Error),\n" -" #[error(\"Found no username in {0}\")]\n" -" EmptyUsername(String),\n" -"}\n" -"\n" -"fn read_username(path: &str) -> Result {\n" -" let mut username = String::new();\n" -" fs::File::open(path)?.read_to_string(&mut username)?;\n" -" if username.is_empty() {\n" -" return Err(ReadUsernameError::EmptyUsername(String::from(path)));\n" -" }\n" -" Ok(username)\n" -"}\n" -"\n" -"fn main() {\n" -" //fs::write(\"config.dat\", \"\").unwrap();\n" -" match read_username(\"config.dat\") {\n" -" Ok(username) => println!(\"Username: {username}\"),\n" -" Err(err) => println!(\"Error: {err}\"),\n" -" }\n" -"}\n" -"```" +#: src/error-handling/deriving-error-enums.md:13 +msgid "\"Could not read: {0}\"" +msgstr "" + +#: src/error-handling/deriving-error-enums.md:15 +#: src/error-handling/dynamic-errors.md:13 +msgid "\"Found no username in {0}\"" +msgstr "" + +#: src/error-handling/deriving-error-enums.md:31 +#: src/error-handling/dynamic-errors.md:28 +#: src/error-handling/error-contexts.md:27 +msgid "\"Username: {username}\"" +msgstr "" + +#: src/error-handling/deriving-error-enums.md:32 +#: src/error-handling/dynamic-errors.md:29 +msgid "\"Error: {err}\"" msgstr "" #: src/error-handling/deriving-error-enums.md:39 @@ -9808,37 +8978,6 @@ msgid "" "makes this easy." msgstr "" -#: src/error-handling/dynamic-errors.md:6 -msgid "" -"```rust,editable,compile_fail\n" -"use std::fs;\n" -"use std::io::Read;\n" -"use thiserror::Error;\n" -"use std::error::Error;\n" -"\n" -"#[derive(Clone, Debug, Eq, Error, PartialEq)]\n" -"#[error(\"Found no username in {0}\")]\n" -"struct EmptyUsernameError(String);\n" -"\n" -"fn read_username(path: &str) -> Result> {\n" -" let mut username = String::new();\n" -" fs::File::open(path)?.read_to_string(&mut username)?;\n" -" if username.is_empty() {\n" -" return Err(EmptyUsernameError(String::from(path)).into());\n" -" }\n" -" Ok(username)\n" -"}\n" -"\n" -"fn main() {\n" -" //fs::write(\"config.dat\", \"\").unwrap();\n" -" match read_username(\"config.dat\") {\n" -" Ok(username) => println!(\"Username: {username}\"),\n" -" Err(err) => println!(\"Error: {err}\"),\n" -" }\n" -"}\n" -"```" -msgstr "" - #: src/error-handling/dynamic-errors.md:36 msgid "" "This saves on code, but gives up the ability to cleanly handle different " @@ -9855,33 +8994,20 @@ msgid "" "error types:" msgstr "" -#: src/error-handling/error-contexts.md:7 -msgid "" -"```rust,editable,compile_fail\n" -"use std::{fs, io};\n" -"use std::io::Read;\n" -"use anyhow::{Context, Result, bail};\n" -"\n" -"fn read_username(path: &str) -> Result {\n" -" let mut username = String::with_capacity(100);\n" -" fs::File::open(path)\n" -" .with_context(|| format!(\"Failed to open {path}\"))?\n" -" .read_to_string(&mut username)\n" -" .context(\"Failed to read\")?;\n" -" if username.is_empty() {\n" -" bail!(\"Found no username in {path}\");\n" -" }\n" -" Ok(username)\n" -"}\n" -"\n" -"fn main() {\n" -" //fs::write(\"config.dat\", \"\").unwrap();\n" -" match read_username(\"config.dat\") {\n" -" Ok(username) => println!(\"Username: {username}\"),\n" -" Err(err) => println!(\"Error: {err:?}\"),\n" -" }\n" -"}\n" -"```" +#: src/error-handling/error-contexts.md:15 +msgid "\"Failed to open {path}\"" +msgstr "" + +#: src/error-handling/error-contexts.md:17 +msgid "\"Failed to read\"" +msgstr "" + +#: src/error-handling/error-contexts.md:19 +msgid "\"Found no username in {path}\"" +msgstr "" + +#: src/error-handling/error-contexts.md:28 +msgid "\"Error: {err:?}\"" msgstr "" #: src/error-handling/error-contexts.md:35 @@ -9923,32 +9049,10 @@ msgstr "" msgid "Mark unit tests with `#[test]`:" msgstr "" -#: src/testing/unit-tests.md:5 -msgid "" -"```rust,editable,ignore\n" -"fn first_word(text: &str) -> &str {\n" -" match text.find(' ') {\n" -" Some(idx) => &text[..idx],\n" -" None => &text,\n" -" }\n" -"}\n" -"\n" -"#[test]\n" -"fn test_empty() {\n" -" assert_eq!(first_word(\"\"), \"\");\n" -"}\n" -"\n" -"#[test]\n" -"fn test_single_word() {\n" -" assert_eq!(first_word(\"Hello\"), \"Hello\");\n" -"}\n" -"\n" -"#[test]\n" -"fn test_multiple_words() {\n" -" assert_eq!(first_word(\"Hello World\"), \"Hello\");\n" -"}\n" -"```" -msgstr "" +#: src/testing/unit-tests.md:25 +#, fuzzy +msgid "\"Hello World\"" +msgstr "سلام دنیا" #: src/testing/unit-tests.md:29 msgid "Use `cargo test` to find and run the unit tests." @@ -9960,27 +9064,12 @@ msgid "" "(https://play.rust-lang.org/)):" msgstr "" -#: src/testing/test-modules.md:6 -msgid "" -"```rust,editable\n" -"fn helper(a: &str, b: &str) -> String {\n" -" format!(\"{a} {b}\")\n" -"}\n" -"\n" -"pub fn main() {\n" -" println!(\"{}\", helper(\"Hello\", \"World\"));\n" -"}\n" -"\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::*;\n" -"\n" -" #[test]\n" -" fn test_helper() {\n" -" assert_eq!(helper(\"foo\", \"bar\"), \"foo bar\");\n" -" }\n" -"}\n" -"```" +#: src/testing/test-modules.md:8 +msgid "\"{a} {b}\"" +msgstr "" + +#: src/testing/test-modules.md:21 +msgid "\"foo bar\"" msgstr "" #: src/testing/test-modules.md:26 @@ -9995,27 +9084,27 @@ msgstr "" msgid "Rust has built-in support for documentation tests:" msgstr "" -#: src/testing/doc-tests.md:5 -msgid "" -"```rust\n" -"/// Shortens a string to the given length.\n" -"///\n" -"/// ```\n" -"/// # use playground::shorten_string;\n" -"/// assert_eq!(shorten_string(\"Hello World\", 5), \"Hello\");\n" -"/// assert_eq!(shorten_string(\"Hello World\", 20), \"Hello World\");\n" -"/// ```\n" -"pub fn shorten_string(s: &str, length: usize) -> &str {\n" -" &s[..std::cmp::min(length, s.len())]\n" -"}\n" -"```" +#: src/testing/doc-tests.md:6 +msgid "/// Shortens a string to the given length." msgstr "" -#: src/testing/doc-tests.md:18 -msgid "Code blocks in `///` comments are automatically seen as Rust code." +#: src/testing/doc-tests.md:8 +msgid "/// # use playground::shorten_string;" msgstr "" -#: src/testing/doc-tests.md:19 +#: src/testing/doc-tests.md:9 +msgid "/// assert_eq!(shorten_string(\"Hello World\", 5), \"Hello\");" +msgstr "" + +#: src/testing/doc-tests.md:10 +msgid "/// assert_eq!(shorten_string(\"Hello World\", 20), \"Hello World\");" +msgstr "" + +#: src/testing/doc-tests.md:18 +msgid "Code blocks in `///` comments are automatically seen as Rust code." +msgstr "" + +#: src/testing/doc-tests.md:19 msgid "The code will be compiled and executed as part of `cargo test`." msgstr "" @@ -10140,28 +9229,33 @@ msgstr "" msgid "Creating pointers is safe, but dereferencing them requires `unsafe`:" msgstr "" -#: src/unsafe/raw-pointers.md:5 +#: src/unsafe/raw-pointers.md:12 +msgid "// Safe because r1 and r2 were obtained from references and so are" +msgstr "" + +#: src/unsafe/raw-pointers.md:13 msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut num = 5;\n" -"\n" -" let r1 = &mut num as *mut i32;\n" -" let r2 = r1 as *const i32;\n" -"\n" -" // Safe because r1 and r2 were obtained from references and so are\n" -" // guaranteed to be non-null and properly aligned, the objects " -"underlying\n" -" // the references from which they were obtained are live throughout the\n" -" // whole unsafe block, and they are not accessed either through the\n" -" // references or concurrently through any other pointers.\n" -" unsafe {\n" -" println!(\"r1 is: {}\", *r1);\n" -" *r1 = 10;\n" -" println!(\"r2 is: {}\", *r2);\n" -" }\n" -"}\n" -"```" +"// guaranteed to be non-null and properly aligned, the objects underlying" +msgstr "" + +#: src/unsafe/raw-pointers.md:14 +msgid "// the references from which they were obtained are live throughout the" +msgstr "" + +#: src/unsafe/raw-pointers.md:15 +msgid "// whole unsafe block, and they are not accessed either through the" +msgstr "" + +#: src/unsafe/raw-pointers.md:16 +msgid "// references or concurrently through any other pointers." +msgstr "" + +#: src/unsafe/raw-pointers.md:18 +msgid "\"r1 is: {}\"" +msgstr "" + +#: src/unsafe/raw-pointers.md:20 +msgid "\"r2 is: {}\"" msgstr "" #: src/unsafe/raw-pointers.md:27 @@ -10209,15 +9303,13 @@ msgstr "" msgid "It is safe to read an immutable static variable:" msgstr "" -#: src/unsafe/mutable-static-variables.md:5 -msgid "" -"```rust,editable\n" -"static HELLO_WORLD: &str = \"Hello, world!\";\n" -"\n" -"fn main() {\n" -" println!(\"HELLO_WORLD: {HELLO_WORLD}\");\n" -"}\n" -"```" +#: src/unsafe/mutable-static-variables.md:6 +#, fuzzy +msgid "\"Hello, world!\"" +msgstr "سلام دنیا" + +#: src/unsafe/mutable-static-variables.md:9 +msgid "\"HELLO_WORLD: {HELLO_WORLD}\"" msgstr "" #: src/unsafe/mutable-static-variables.md:13 @@ -10226,21 +9318,13 @@ msgid "" "static variables:" msgstr "" -#: src/unsafe/mutable-static-variables.md:16 -msgid "" -"```rust,editable\n" -"static mut COUNTER: u32 = 0;\n" -"\n" -"fn add_to_counter(inc: u32) {\n" -" unsafe { COUNTER += inc; } // Potential data race!\n" -"}\n" -"\n" -"fn main() {\n" -" add_to_counter(42);\n" -"\n" -" unsafe { println!(\"COUNTER: {COUNTER}\"); } // Potential data race!\n" -"}\n" -"```" +#: src/unsafe/mutable-static-variables.md:20 +#: src/unsafe/mutable-static-variables.md:26 +msgid "// Potential data race!" +msgstr "" + +#: src/unsafe/mutable-static-variables.md:26 +msgid "\"COUNTER: {COUNTER}\"" msgstr "" #: src/unsafe/mutable-static-variables.md:32 @@ -10262,23 +9346,19 @@ msgstr "" msgid "Unions are like enums, but you need to track the active field yourself:" msgstr "" -#: src/unsafe/unions.md:5 -msgid "" -"```rust,editable\n" -"#[repr(C)]\n" -"union MyUnion {\n" -" i: u8,\n" -" b: bool,\n" -"}\n" -"\n" -"fn main() {\n" -" let u = MyUnion { i: 42 };\n" -" println!(\"int: {}\", unsafe { u.i });\n" -" println!(\"bool: {}\", unsafe { u.b }); // Undefined behavior!\n" -"}\n" -"```" +#: src/unsafe/unions.md:14 +msgid "\"int: {}\"" +msgstr "" + +#: src/unsafe/unions.md:15 +msgid "\"bool: {}\"" msgstr "" +#: src/unsafe/unions.md:15 +#, fuzzy +msgid "// Undefined behavior!" +msgstr "هیچ رفتار تعریف نشده‌ای در زمان اجرا:" + #: src/unsafe/unions.md:21 msgid "" "Unions are very rarely needed in Rust as you can usually use an enum. They " @@ -10299,34 +9379,41 @@ msgid "" "you must uphold to avoid undefined behaviour:" msgstr "" -#: src/unsafe/calling-unsafe-functions.md:6 +#: src/unsafe/calling-unsafe-functions.md:8 +msgid "\"🗻∈🌏\"" +msgstr "" + +#: src/unsafe/calling-unsafe-functions.md:10 msgid "" -"```rust,editable\n" -"fn main() {\n" -" let emojis = \"🗻∈🌏\";\n" -"\n" -" // Safe because the indices are in the correct order, within the bounds " -"of\n" -" // the string slice, and lie on UTF-8 sequence boundaries.\n" -" unsafe {\n" -" println!(\"emoji: {}\", emojis.get_unchecked(0..4));\n" -" println!(\"emoji: {}\", emojis.get_unchecked(4..7));\n" -" println!(\"emoji: {}\", emojis.get_unchecked(7..11));\n" -" }\n" -"\n" -" println!(\"char count: {}\", count_chars(unsafe { emojis." -"get_unchecked(0..7) }));\n" -"\n" -" // Not upholding the UTF-8 encoding requirement breaks memory safety!\n" -" // println!(\"emoji: {}\", unsafe { emojis.get_unchecked(0..3) });\n" -" // println!(\"char count: {}\", count_chars(unsafe { emojis." -"get_unchecked(0..3) }));\n" -"}\n" -"\n" -"fn count_chars(s: &str) -> usize {\n" -" s.chars().count()\n" -"}\n" -"```" +"// Safe because the indices are in the correct order, within the bounds of" +msgstr "" + +#: src/unsafe/calling-unsafe-functions.md:11 +msgid "// the string slice, and lie on UTF-8 sequence boundaries." +msgstr "" + +#: src/unsafe/calling-unsafe-functions.md:13 +#: src/unsafe/calling-unsafe-functions.md:14 +#: src/unsafe/calling-unsafe-functions.md:15 +msgid "\"emoji: {}\"" +msgstr "" + +#: src/unsafe/calling-unsafe-functions.md:18 +msgid "\"char count: {}\"" +msgstr "" + +#: src/unsafe/calling-unsafe-functions.md:20 +msgid "// Not upholding the UTF-8 encoding requirement breaks memory safety!" +msgstr "" + +#: src/unsafe/calling-unsafe-functions.md:21 +msgid "// println!(\"emoji: {}\", unsafe { emojis.get_unchecked(0..3) });" +msgstr "" + +#: src/unsafe/calling-unsafe-functions.md:22 +msgid "" +"// println!(\"char count: {}\", count_chars(unsafe { emojis." +"get_unchecked(0..3) }));" msgstr "" #: src/unsafe/writing-unsafe-functions.md:3 @@ -10335,32 +9422,24 @@ msgid "" "conditions to avoid undefined behaviour." msgstr "" -#: src/unsafe/writing-unsafe-functions.md:6 -msgid "" -"```rust,editable\n" -"/// Swaps the values pointed to by the given pointers.\n" -"///\n" -"/// # Safety\n" -"///\n" -"/// The pointers must be valid and properly aligned.\n" -"unsafe fn swap(a: *mut u8, b: *mut u8) {\n" -" let temp = *a;\n" -" *a = *b;\n" -" *b = temp;\n" -"}\n" -"\n" -"fn main() {\n" -" let mut a = 42;\n" -" let mut b = 66;\n" -"\n" -" // Safe because ...\n" -" unsafe {\n" -" swap(&mut a, &mut b);\n" -" }\n" -"\n" -" println!(\"a = {}, b = {}\", a, b);\n" -"}\n" -"```" +#: src/unsafe/writing-unsafe-functions.md:7 +msgid "/// Swaps the values pointed to by the given pointers." +msgstr "" + +#: src/unsafe/writing-unsafe-functions.md:8 src/unsafe/unsafe-traits.md:13 +msgid "/// # Safety" +msgstr "" + +#: src/unsafe/writing-unsafe-functions.md:10 +msgid "/// The pointers must be valid and properly aligned." +msgstr "" + +#: src/unsafe/writing-unsafe-functions.md:22 +msgid "// Safe because ..." +msgstr "" + +#: src/unsafe/writing-unsafe-functions.md:27 +msgid "\"a = {}, b = {}\"" msgstr "" #: src/unsafe/writing-unsafe-functions.md:33 @@ -10386,20 +9465,31 @@ msgid "" "them is thus unsafe:" msgstr "" -#: src/unsafe/extern-functions.md:6 -msgid "" -"```rust,editable\n" -"extern \"C\" {\n" -" fn abs(input: i32) -> i32;\n" -"}\n" -"\n" -"fn main() {\n" -" unsafe {\n" -" // Undefined behavior if abs misbehaves.\n" -" println!(\"Absolute value of -3 according to C: {}\", abs(-3));\n" -" }\n" -"}\n" -"```" +#: src/unsafe/extern-functions.md:7 src/exercises/day-3/safe-ffi-wrapper.md:89 +#: src/android/interoperability/with-c.md:9 +#: src/android/interoperability/with-c/rust.md:15 +#: src/android/interoperability/with-c/rust.md:30 +#: src/android/interoperability/cpp/cpp-bridge.md:29 +#: src/android/interoperability/cpp/cpp-bridge.md:38 +#: src/bare-metal/aps/inline-assembly.md:18 +#: src/bare-metal/aps/better-uart/using.md:24 +#: src/bare-metal/aps/logging/using.md:23 src/exercises/bare-metal/rtc.md:46 +#: src/exercises/bare-metal/rtc.md:100 src/exercises/bare-metal/rtc.md:106 +#: src/exercises/bare-metal/rtc.md:113 src/exercises/bare-metal/rtc.md:119 +#: src/exercises/bare-metal/rtc.md:125 src/exercises/bare-metal/rtc.md:131 +#: src/exercises/bare-metal/rtc.md:137 src/exercises/bare-metal/rtc.md:143 +#: src/exercises/day-3/solutions-afternoon.md:45 +#: src/exercises/bare-metal/solutions-afternoon.md:43 +msgid "\"C\"" +msgstr "" + +#: src/unsafe/extern-functions.md:13 +#, fuzzy +msgid "// Undefined behavior if abs misbehaves." +msgstr "هیچ رفتار تعریف نشده‌ای در زمان اجرا:" + +#: src/unsafe/extern-functions.md:14 +msgid "\"Absolute value of -3 according to C: {}\"" msgstr "" #: src/unsafe/extern-functions.md:21 @@ -10427,27 +9517,16 @@ msgid "" "like this](https://docs.rs/zerocopy/latest/zerocopy/trait.AsBytes.html):" msgstr "" -#: src/unsafe/unsafe-traits.md:9 -msgid "" -"```rust,editable\n" -"use std::mem::size_of_val;\n" -"use std::slice;\n" -"\n" -"/// ...\n" -"/// # Safety\n" -"/// The type must have a defined representation and no padding.\n" -"pub unsafe trait AsBytes {\n" -" fn as_bytes(&self) -> &[u8] {\n" -" unsafe {\n" -" slice::from_raw_parts(self as *const Self as *const u8, " -"size_of_val(self))\n" -" }\n" -" }\n" -"}\n" -"\n" -"// Safe because u32 has a defined representation and no padding.\n" -"unsafe impl AsBytes for u32 {}\n" -"```" +#: src/unsafe/unsafe-traits.md:12 +msgid "/// ..." +msgstr "" + +#: src/unsafe/unsafe-traits.md:14 +msgid "/// The type must have a defined representation and no padding." +msgstr "" + +#: src/unsafe/unsafe-traits.md:23 +msgid "// Safe because u32 has a defined representation and no padding." msgstr "" #: src/unsafe/unsafe-traits.md:30 @@ -10622,111 +9701,86 @@ msgid "" "functions and methods:" msgstr "" -#: src/exercises/day-3/safe-ffi-wrapper.md:48 +#: src/exercises/day-3/safe-ffi-wrapper.md:54 +#: src/exercises/day-3/safe-ffi-wrapper.md:67 +#: src/exercises/day-3/safe-ffi-wrapper.md:78 +#: src/exercises/day-3/safe-ffi-wrapper.md:92 +#: src/exercises/day-3/safe-ffi-wrapper.md:100 +#: src/exercises/day-3/solutions-afternoon.md:10 +#: src/exercises/day-3/solutions-afternoon.md:23 +#: src/exercises/day-3/solutions-afternoon.md:34 +#: src/exercises/day-3/solutions-afternoon.md:48 +#: src/exercises/day-3/solutions-afternoon.md:56 +msgid "\"macos\"" +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:57 +#: src/exercises/day-3/solutions-afternoon.md:13 +msgid "// Opaque type. See https://doc.rust-lang.org/nomicon/ffi.html.\n" +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:64 +#: src/exercises/day-3/solutions-afternoon.md:20 msgid "" -"```rust,should_panic\n" -"// TODO: remove this when you're done with your implementation.\n" -"#![allow(unused_imports, unused_variables, dead_code)]\n" -"\n" -"mod ffi {\n" -" use std::os::raw::{c_char, c_int};\n" -" #[cfg(not(target_os = \"macos\"))]\n" -" use std::os::raw::{c_long, c_ulong, c_ushort, c_uchar};\n" -"\n" -" // Opaque type. See https://doc.rust-lang.org/nomicon/ffi.html.\n" -" #[repr(C)]\n" -" pub struct DIR {\n" -" _data: [u8; 0],\n" -" _marker: core::marker::PhantomData<(*mut u8, core::marker::" -"PhantomPinned)>,\n" -" }\n" -"\n" -" // Layout according to the Linux man page for readdir(3), where ino_t " -"and\n" +"// Layout according to the Linux man page for readdir(3), where ino_t and\n" " // off_t are resolved according to the definitions in\n" " // /usr/include/x86_64-linux-gnu/{sys/types.h, bits/typesizes.h}.\n" -" #[cfg(not(target_os = \"macos\"))]\n" -" #[repr(C)]\n" -" pub struct dirent {\n" -" pub d_ino: c_ulong,\n" -" pub d_off: c_long,\n" -" pub d_reclen: c_ushort,\n" -" pub d_type: c_uchar,\n" -" pub d_name: [c_char; 256],\n" -" }\n" -"\n" -" // Layout according to the macOS man page for dir(5).\n" -" #[cfg(all(target_os = \"macos\"))]\n" -" #[repr(C)]\n" -" pub struct dirent {\n" -" pub d_fileno: u64,\n" -" pub d_seekoff: u64,\n" -" pub d_reclen: u16,\n" -" pub d_namlen: u16,\n" -" pub d_type: u8,\n" -" pub d_name: [c_char; 1024],\n" -" }\n" -"\n" -" extern \"C\" {\n" -" pub fn opendir(s: *const c_char) -> *mut DIR;\n" -"\n" -" #[cfg(not(all(target_os = \"macos\", target_arch = \"x86_64\")))]\n" -" pub fn readdir(s: *mut DIR) -> *const dirent;\n" -"\n" -" // See https://github.com/rust-lang/libc/issues/414 and the section " -"on\n" +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:77 +#: src/exercises/day-3/solutions-afternoon.md:33 +msgid "// Layout according to the macOS man page for dir(5).\n" +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:92 +#: src/exercises/day-3/safe-ffi-wrapper.md:100 +#: src/exercises/day-3/solutions-afternoon.md:48 +#: src/exercises/day-3/solutions-afternoon.md:56 +msgid "\"x86_64\"" +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:95 +#: src/exercises/day-3/solutions-afternoon.md:51 +msgid "" +"// See https://github.com/rust-lang/libc/issues/414 and the section on\n" " // _DARWIN_FEATURE_64_BIT_INODE in the macOS man page for stat(2).\n" " //\n" " // \"Platforms that existed before these updates were available\" " "refers\n" " // to macOS (as opposed to iOS / wearOS / etc.) on Intel and " "PowerPC.\n" -" #[cfg(all(target_os = \"macos\", target_arch = \"x86_64\"))]\n" -" #[link_name = \"readdir$INODE64\"]\n" -" pub fn readdir(s: *mut DIR) -> *const dirent;\n" -"\n" -" pub fn closedir(s: *mut DIR) -> c_int;\n" -" }\n" -"}\n" -"\n" -"use std::ffi::{CStr, CString, OsStr, OsString};\n" -"use std::os::unix::ffi::OsStrExt;\n" -"\n" -"#[derive(Debug)]\n" -"struct DirectoryIterator {\n" -" path: CString,\n" -" dir: *mut ffi::DIR,\n" -"}\n" -"\n" -"impl DirectoryIterator {\n" -" fn new(path: &str) -> Result {\n" -" // Call opendir and return a Ok value if that worked,\n" -" // otherwise return Err with a message.\n" -" unimplemented!()\n" -" }\n" -"}\n" -"\n" -"impl Iterator for DirectoryIterator {\n" -" type Item = OsString;\n" -" fn next(&mut self) -> Option {\n" -" // Keep calling readdir until we get a NULL pointer back.\n" -" unimplemented!()\n" -" }\n" -"}\n" -"\n" -"impl Drop for DirectoryIterator {\n" -" fn drop(&mut self) {\n" -" // Call closedir as needed.\n" -" unimplemented!()\n" -" }\n" -"}\n" -"\n" -"fn main() -> Result<(), String> {\n" -" let iter = DirectoryIterator::new(\".\")?;\n" -" println!(\"files: {:#?}\", iter.collect::>());\n" -" Ok(())\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:101 +#: src/exercises/day-3/solutions-afternoon.md:57 +msgid "\"readdir$INODE64\"" +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:119 +msgid "" +"// Call opendir and return a Ok value if that worked,\n" +" // otherwise return Err with a message." +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:128 +msgid "// Keep calling readdir until we get a NULL pointer back." +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:135 +msgid "// Call closedir as needed." +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:141 +#: src/android/interoperability/with-c/rust.md:44 +#: src/exercises/day-3/solutions-afternoon.md:119 +#: src/exercises/day-3/solutions-afternoon.md:143 +#: src/exercises/day-3/solutions-afternoon.md:158 +msgid "\".\"" +msgstr "" + +#: src/exercises/day-3/safe-ffi-wrapper.md:142 +#: src/exercises/day-3/solutions-afternoon.md:120 +msgid "\"files: {:#?}\"" msgstr "" #: src/android.md:1 @@ -10862,31 +9916,29 @@ msgstr "" msgid "_hello_rust/Android.bp_:" msgstr "" -#: src/android/build-rules/binary.md:8 -msgid "" -"```javascript\n" -"rust_binary {\n" -" name: \"hello_rust\",\n" -" crate_name: \"hello_rust\",\n" -" srcs: [\"src/main.rs\"],\n" -"}\n" -"```" +#: src/android/build-rules/binary.md:10 src/android/build-rules/binary.md:11 +msgid "\"hello_rust\"" +msgstr "" + +#: src/android/build-rules/binary.md:12 src/android/build-rules/library.md:19 +#: src/android/logging.md:12 +msgid "\"src/main.rs\"" msgstr "" -#: src/android/build-rules/binary.md:16 src/android/build-rules/library.md:34 +#: src/android/build-rules/binary.md:16 src/android/build-rules/library.md:33 msgid "_hello_rust/src/main.rs_:" msgstr "" -#: src/android/build-rules/binary.md:18 -msgid "" -"```rust\n" -"//! Rust demo.\n" -"\n" -"/// Prints a greeting to standard output.\n" -"fn main() {\n" -" println!(\"Hello from Rust!\");\n" -"}\n" -"```" +#: src/android/build-rules/binary.md:19 src/android/build-rules/library.md:36 +msgid "//! Rust demo.\n" +msgstr "" + +#: src/android/build-rules/binary.md:20 src/android/build-rules/library.md:40 +msgid "/// Prints a greeting to standard output.\n" +msgstr "" + +#: src/android/build-rules/binary.md:23 +msgid "\"Hello from Rust!\"" msgstr "" #: src/android/build-rules/binary.md:27 @@ -10925,64 +9977,48 @@ msgid "" "crates/)." msgstr "" -#: src/android/build-rules/library.md:15 -msgid "" -"```javascript\n" -"rust_binary {\n" -" name: \"hello_rust_with_dep\",\n" -" crate_name: \"hello_rust_with_dep\",\n" -" srcs: [\"src/main.rs\"],\n" -" rustlibs: [\n" -" \"libgreetings\",\n" -" \"libtextwrap\",\n" -" ],\n" -" prefer_rlib: true,\n" -"}\n" -"\n" -"rust_library {\n" -" name: \"libgreetings\",\n" -" crate_name: \"greetings\",\n" -" srcs: [\"src/lib.rs\"],\n" -"}\n" -"```" +#: src/android/build-rules/library.md:17 src/android/build-rules/library.md:18 +msgid "\"hello_rust_with_dep\"" msgstr "" -#: src/android/build-rules/library.md:36 -msgid "" -"```rust,ignore\n" -"//! Rust demo.\n" -"\n" -"use greetings::greeting;\n" -"use textwrap::fill;\n" -"\n" -"/// Prints a greeting to standard output.\n" -"fn main() {\n" -" println!(\"{}\", fill(&greeting(\"Bob\"), 24));\n" -"}\n" -"```" +#: src/android/build-rules/library.md:21 src/android/build-rules/library.md:27 +msgid "\"libgreetings\"" +msgstr "" + +#: src/android/build-rules/library.md:22 +msgid "\"libtextwrap\"" +msgstr "" + +#: src/android/build-rules/library.md:28 +msgid "\"greetings\"" +msgstr "" + +#: src/android/build-rules/library.md:29 src/android/aidl/implementation.md:31 +#: src/android/interoperability/java.md:38 +msgid "\"src/lib.rs\"" msgstr "" -#: src/android/build-rules/library.md:48 +#: src/android/build-rules/library.md:47 msgid "_hello_rust/src/lib.rs_:" msgstr "" #: src/android/build-rules/library.md:50 -msgid "" -"```rust,ignore\n" -"//! Greeting library.\n" -"\n" -"/// Greet `name`.\n" -"pub fn greeting(name: &str) -> String {\n" -" format!(\"Hello {name}, it is very nice to meet you!\")\n" -"}\n" -"```" +msgid "//! Greeting library.\n" +msgstr "" + +#: src/android/build-rules/library.md:51 +msgid "/// Greet `name`.\n" +msgstr "" + +#: src/android/build-rules/library.md:54 +msgid "\"Hello {name}, it is very nice to meet you!\"" msgstr "" -#: src/android/build-rules/library.md:59 +#: src/android/build-rules/library.md:58 msgid "You build, push, and run the binary like before:" msgstr "" -#: src/android/build-rules/library.md:61 +#: src/android/build-rules/library.md:60 msgid "" "```shell\n" "m hello_rust_with_dep\n" @@ -11019,24 +10055,28 @@ msgid "" "_birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl_:" msgstr "" +#: src/android/aidl/interface.md:9 src/android/aidl/changing.md:8 +msgid "/** Birthday service interface. */" +msgstr "" + +#: src/android/aidl/interface.md:12 src/android/aidl/changing.md:11 +msgid "/** Generate a Happy Birthday message. */" +msgstr "" + #: src/android/aidl/interface.md:17 msgid "_birthday_service/aidl/Android.bp_:" msgstr "" -#: src/android/aidl/interface.md:19 -msgid "" -"```javascript\n" -"aidl_interface {\n" -" name: \"com.example.birthdayservice\",\n" -" srcs: [\"com/example/birthdayservice/*.aidl\"],\n" -" unstable: true,\n" -" backend: {\n" -" rust: { // Rust is not enabled by default\n" -" enabled: true,\n" -" },\n" -" },\n" -"}\n" -"```" +#: src/android/aidl/interface.md:21 +msgid "\"com.example.birthdayservice\"" +msgstr "" + +#: src/android/aidl/interface.md:22 +msgid "\"com/example/birthdayservice/*.aidl\"" +msgstr "" + +#: src/android/aidl/interface.md:25 +msgid "// Rust is not enabled by default\n" msgstr "" #: src/android/aidl/interface.md:32 @@ -11057,29 +10097,16 @@ msgstr "" msgid "_birthday_service/src/lib.rs_:" msgstr "" -#: src/android/aidl/implementation.md:7 -msgid "" -"```rust,ignore\n" -"//! Implementation of the `IBirthdayService` AIDL interface.\n" -"use com_example_birthdayservice::aidl::com::example::birthdayservice::" -"IBirthdayService::IBirthdayService;\n" -"use com_example_birthdayservice::binder;\n" -"\n" -"/// The `IBirthdayService` implementation.\n" -"pub struct BirthdayService;\n" -"\n" -"impl binder::Interface for BirthdayService {}\n" -"\n" -"impl IBirthdayService for BirthdayService {\n" -" fn wishHappyBirthday(&self, name: &str, years: i32) -> binder::" -"Result {\n" -" Ok(format!(\n" -" \"Happy Birthday {name}, congratulations with the {years} years!" -"\"\n" -" ))\n" -" }\n" -"}\n" -"```" +#: src/android/aidl/implementation.md:8 +msgid "//! Implementation of the `IBirthdayService` AIDL interface.\n" +msgstr "" + +#: src/android/aidl/implementation.md:11 +msgid "/// The `IBirthdayService` implementation.\n" +msgstr "" + +#: src/android/aidl/implementation.md:20 +msgid "\"Happy Birthday {name}, congratulations with the {years} years!\"" msgstr "" #: src/android/aidl/implementation.md:26 src/android/aidl/server.md:28 @@ -11087,19 +10114,23 @@ msgstr "" msgid "_birthday_service/Android.bp_:" msgstr "" -#: src/android/aidl/implementation.md:28 -msgid "" -"```javascript\n" -"rust_library {\n" -" name: \"libbirthdayservice\",\n" -" srcs: [\"src/lib.rs\"],\n" -" crate_name: \"birthdayservice\",\n" -" rustlibs: [\n" -" \"com.example.birthdayservice-rust\",\n" -" \"libbinder_rs\",\n" -" ],\n" -"}\n" -"```" +#: src/android/aidl/implementation.md:30 src/android/aidl/server.md:38 +msgid "\"libbirthdayservice\"" +msgstr "" + +#: src/android/aidl/implementation.md:32 src/android/aidl/server.md:13 +#: src/android/aidl/client.md:12 +msgid "\"birthdayservice\"" +msgstr "" + +#: src/android/aidl/implementation.md:34 src/android/aidl/server.md:36 +#: src/android/aidl/client.md:45 +msgid "\"com.example.birthdayservice-rust\"" +msgstr "" + +#: src/android/aidl/implementation.md:35 src/android/aidl/server.md:37 +#: src/android/aidl/client.md:46 +msgid "\"libbinder_rs\"" msgstr "" #: src/android/aidl/server.md:1 @@ -11114,49 +10145,27 @@ msgstr "" msgid "_birthday_service/src/server.rs_:" msgstr "" -#: src/android/aidl/server.md:7 -msgid "" -"```rust,ignore\n" -"//! Birthday service.\n" -"use birthdayservice::BirthdayService;\n" -"use com_example_birthdayservice::aidl::com::example::birthdayservice::" -"IBirthdayService::BnBirthdayService;\n" -"use com_example_birthdayservice::binder;\n" -"\n" -"const SERVICE_IDENTIFIER: &str = \"birthdayservice\";\n" -"\n" -"/// Entry point for birthday service.\n" -"fn main() {\n" -" let birthday_service = BirthdayService;\n" -" let birthday_service_binder = BnBirthdayService::new_binder(\n" -" birthday_service,\n" -" binder::BinderFeatures::default(),\n" -" );\n" -" binder::add_service(SERVICE_IDENTIFIER, birthday_service_binder." -"as_binder())\n" -" .expect(\"Failed to register service\");\n" -" binder::ProcessState::join_thread_pool()\n" -"}\n" -"```" +#: src/android/aidl/server.md:8 src/android/aidl/client.md:8 +msgid "//! Birthday service.\n" msgstr "" -#: src/android/aidl/server.md:30 -msgid "" -"```javascript\n" -"rust_binary {\n" -" name: \"birthday_server\",\n" -" crate_name: \"birthday_server\",\n" -" srcs: [\"src/server.rs\"],\n" -" rustlibs: [\n" -" \"com.example.birthdayservice-rust\",\n" -" \"libbinder_rs\",\n" -" \"libbirthdayservice\",\n" -" ],\n" -" prefer_rlib: true,\n" -"}\n" -"```" +#: src/android/aidl/server.md:14 +msgid "/// Entry point for birthday service.\n" +msgstr "" + +#: src/android/aidl/server.md:23 +msgid "\"Failed to register service\"" +msgstr "" + +#: src/android/aidl/server.md:32 src/android/aidl/server.md:33 +msgid "\"birthday_server\"" msgstr "" +#: src/android/aidl/server.md:34 +#, fuzzy +msgid "\"src/server.rs\"" +msgstr "سرورها" + #: src/android/aidl/deploy.md:3 msgid "We can now build, push, and start the service:" msgstr "" @@ -11191,67 +10200,39 @@ msgstr "" msgid "_birthday_service/src/client.rs_:" msgstr "" -#: src/android/aidl/client.md:7 -msgid "" -"```rust,ignore\n" -"//! Birthday service.\n" -"use com_example_birthdayservice::aidl::com::example::birthdayservice::" -"IBirthdayService::IBirthdayService;\n" -"use com_example_birthdayservice::binder;\n" -"\n" -"const SERVICE_IDENTIFIER: &str = \"birthdayservice\";\n" -"\n" -"/// Connect to the BirthdayService.\n" -"pub fn connect() -> Result, binder::" -"StatusCode> {\n" -" binder::get_interface(SERVICE_IDENTIFIER)\n" -"}\n" -"\n" -"/// Call the birthday service.\n" -"fn main() -> Result<(), binder::Status> {\n" -" let name = std::env::args()\n" -" .nth(1)\n" -" .unwrap_or_else(|| String::from(\"Bob\"));\n" -" let years = std::env::args()\n" -" .nth(2)\n" -" .and_then(|arg| arg.parse::().ok())\n" -" .unwrap_or(42);\n" -"\n" -" binder::ProcessState::start_thread_pool();\n" -" let service = connect().expect(\"Failed to connect to " -"BirthdayService\");\n" -" let msg = service.wishHappyBirthday(&name, years)?;\n" -" println!(\"{msg}\");\n" -" Ok(())\n" -"}\n" -"```" +#: src/android/aidl/client.md:13 +msgid "/// Connect to the BirthdayService.\n" msgstr "" -#: src/android/aidl/client.md:39 -msgid "" -"```javascript\n" -"rust_binary {\n" -" name: \"birthday_client\",\n" -" crate_name: \"birthday_client\",\n" -" srcs: [\"src/client.rs\"],\n" -" rustlibs: [\n" -" \"com.example.birthdayservice-rust\",\n" -" \"libbinder_rs\",\n" -" ],\n" -" prefer_rlib: true,\n" -"}\n" -"```" +#: src/android/aidl/client.md:18 +msgid "/// Call the birthday service.\n" +msgstr "" + +#: src/android/aidl/client.md:30 +msgid "\"Failed to connect to BirthdayService\"" +msgstr "" + +#: src/android/aidl/client.md:32 +msgid "\"{msg}\"" +msgstr "" + +#: src/android/aidl/client.md:41 src/android/aidl/client.md:42 +msgid "\"birthday_client\"" +msgstr "" + +#: src/android/aidl/client.md:43 +msgid "\"src/client.rs\"" msgstr "" -#: src/android/aidl/client.md:52 +#: src/android/aidl/client.md:51 msgid "Notice that the client does not depend on `libbirthdayservice`." msgstr "" -#: src/android/aidl/client.md:54 +#: src/android/aidl/client.md:53 msgid "Build, push, and run the client on your device:" msgstr "" -#: src/android/aidl/client.md:56 +#: src/android/aidl/client.md:55 msgid "" "```shell\n" "m birthday_client\n" @@ -11277,54 +10258,52 @@ msgstr "" msgid "_hello_rust_logs/Android.bp_:" msgstr "" -#: src/android/logging.md:8 -msgid "" -"```javascript\n" -"rust_binary {\n" -" name: \"hello_rust_logs\",\n" -" crate_name: \"hello_rust_logs\",\n" -" srcs: [\"src/main.rs\"],\n" -" rustlibs: [\n" -" \"liblog_rust\",\n" -" \"liblogger\",\n" -" ],\n" -" prefer_rlib: true,\n" -" host_supported: true,\n" -"}\n" -"```" +#: src/android/logging.md:10 src/android/logging.md:11 +msgid "\"hello_rust_logs\"" msgstr "" -#: src/android/logging.md:22 +#: src/android/logging.md:14 +msgid "\"liblog_rust\"" +msgstr "" + +#: src/android/logging.md:15 +msgid "\"liblogger\"" +msgstr "" + +#: src/android/logging.md:21 msgid "_hello_rust_logs/src/main.rs_:" msgstr "" #: src/android/logging.md:24 -msgid "" -"```rust,ignore\n" -"//! Rust logging demo.\n" -"\n" -"use log::{debug, error, info};\n" -"\n" -"/// Logs a greeting.\n" -"fn main() {\n" -" logger::init(\n" -" logger::Config::default()\n" -" .with_tag_on_device(\"rust\")\n" -" .with_min_level(log::Level::Trace),\n" -" );\n" -" debug!(\"Starting program.\");\n" -" info!(\"Things are going fine.\");\n" -" error!(\"Something went wrong!\");\n" -"}\n" -"```" +msgid "//! Rust logging demo.\n" +msgstr "" + +#: src/android/logging.md:27 +msgid "/// Logs a greeting.\n" +msgstr "" + +#: src/android/logging.md:32 +msgid "\"rust\"" +msgstr "" + +#: src/android/logging.md:35 +msgid "\"Starting program.\"" +msgstr "" + +#: src/android/logging.md:36 +msgid "\"Things are going fine.\"" +msgstr "" + +#: src/android/logging.md:37 +msgid "\"Something went wrong!\"" msgstr "" -#: src/android/logging.md:42 src/android/interoperability/with-c/bindgen.md:98 +#: src/android/logging.md:41 src/android/interoperability/with-c/bindgen.md:98 #: src/android/interoperability/with-c/rust.md:73 msgid "Build, push, and run the binary on your device:" msgstr "" -#: src/android/logging.md:44 +#: src/android/logging.md:43 msgid "" "```shell\n" "m hello_rust_logs\n" @@ -11334,7 +10313,7 @@ msgid "" "```" msgstr "" -#: src/android/logging.md:50 +#: src/android/logging.md:49 msgid "The logs show up in `adb logcat`:" msgstr "" @@ -11372,19 +10351,8 @@ msgstr "" msgid "You can do it by hand if you want:" msgstr "" -#: src/android/interoperability/with-c.md:8 -msgid "" -"```rust\n" -"extern \"C\" {\n" -" fn abs(x: i32) -> i32;\n" -"}\n" -"\n" -"fn main() {\n" -" let x = -42;\n" -" let abs_x = unsafe { abs(x) };\n" -" println!(\"{x}, {abs_x}\");\n" -"}\n" -"```" +#: src/android/interoperability/with-c.md:16 +msgid "\"{x}, {abs_x}\"" msgstr "" #: src/android/interoperability/with-c.md:20 @@ -11425,19 +10393,22 @@ msgstr "" msgid "_interoperability/bindgen/libbirthday.c_:" msgstr "" -#: src/android/interoperability/with-c/bindgen.md:21 -msgid "" -"```c\n" -"#include \n" -"#include \"libbirthday.h\"\n" -"\n" -"void print_card(const card* card) {\n" -" printf(\"+--------------\\n\");\n" -" printf(\"| Happy Birthday %s!\\n\", card->name);\n" -" printf(\"| Congratulations with the %i years!\\n\", card->years);\n" -" printf(\"+--------------\\n\");\n" -"}\n" -"```" +#: src/android/interoperability/with-c/bindgen.md:23 +#: src/android/interoperability/with-c/bindgen.md:50 +msgid "\"libbirthday.h\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:26 +#: src/android/interoperability/with-c/bindgen.md:29 +msgid "\"+--------------\\n\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:27 +msgid "\"| Happy Birthday %s!\\n\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:28 +msgid "\"| Congratulations with the %i years!\\n\"" msgstr "" #: src/android/interoperability/with-c/bindgen.md:33 @@ -11451,14 +10422,13 @@ msgstr "" msgid "_interoperability/bindgen/Android.bp_:" msgstr "" -#: src/android/interoperability/with-c/bindgen.md:37 -msgid "" -"```javascript\n" -"cc_library {\n" -" name: \"libbirthday\",\n" -" srcs: [\"libbirthday.c\"],\n" -"}\n" -"```" +#: src/android/interoperability/with-c/bindgen.md:39 +#: src/android/interoperability/with-c/bindgen.md:63 +msgid "\"libbirthday\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:40 +msgid "\"libbirthday.c\"" msgstr "" #: src/android/interoperability/with-c/bindgen.md:44 @@ -11471,67 +10441,45 @@ msgstr "" msgid "_interoperability/bindgen/libbirthday_wrapper.h_:" msgstr "" -#: src/android/interoperability/with-c/bindgen.md:49 -msgid "" -"```c\n" -"#include \"libbirthday.h\"\n" -"```" -msgstr "" - #: src/android/interoperability/with-c/bindgen.md:53 msgid "You can now auto-generate the bindings:" msgstr "" -#: src/android/interoperability/with-c/bindgen.md:57 -msgid "" -"```javascript\n" -"rust_bindgen {\n" -" name: \"libbirthday_bindgen\",\n" -" crate_name: \"birthday_bindgen\",\n" -" wrapper_src: \"libbirthday_wrapper.h\",\n" -" source_stem: \"bindings\",\n" -" static_libs: [\"libbirthday\"],\n" -"}\n" -"```" +#: src/android/interoperability/with-c/bindgen.md:59 +#: src/android/interoperability/with-c/bindgen.md:75 +msgid "\"libbirthday_bindgen\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:60 +msgid "\"birthday_bindgen\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:61 +msgid "\"libbirthday_wrapper.h\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:62 +msgid "\"bindings\"" msgstr "" #: src/android/interoperability/with-c/bindgen.md:67 msgid "Finally, we can use the bindings in our Rust program:" msgstr "" -#: src/android/interoperability/with-c/bindgen.md:71 -msgid "" -"```javascript\n" -"rust_binary {\n" -" name: \"print_birthday_card\",\n" -" srcs: [\"main.rs\"],\n" -" rustlibs: [\"libbirthday_bindgen\"],\n" -"}\n" -"```" +#: src/android/interoperability/with-c/bindgen.md:73 +msgid "\"print_birthday_card\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:74 +msgid "\"main.rs\"" msgstr "" #: src/android/interoperability/with-c/bindgen.md:79 msgid "_interoperability/bindgen/main.rs_:" msgstr "" -#: src/android/interoperability/with-c/bindgen.md:81 -msgid "" -"```rust,compile_fail\n" -"//! Bindgen demo.\n" -"\n" -"use birthday_bindgen::{card, print_card};\n" -"\n" -"fn main() {\n" -" let name = std::ffi::CString::new(\"Peter\").unwrap();\n" -" let card = card {\n" -" name: name.as_ptr(),\n" -" years: 42,\n" -" };\n" -" unsafe {\n" -" print_card(&card as *const card);\n" -" }\n" -"}\n" -"```" +#: src/android/interoperability/with-c/bindgen.md:82 +msgid "//! Bindgen demo.\n" msgstr "" #: src/android/interoperability/with-c/bindgen.md:100 @@ -11548,19 +10496,26 @@ msgstr "" msgid "Finally, we can run auto-generated tests to ensure the bindings work:" msgstr "" -#: src/android/interoperability/with-c/bindgen.md:110 -msgid "" -"```javascript\n" -"rust_test {\n" -" name: \"libbirthday_bindgen_test\",\n" -" srcs: [\":libbirthday_bindgen\"],\n" -" crate_name: \"libbirthday_bindgen_test\",\n" -" test_suites: [\"general-tests\"],\n" -" auto_gen_config: true,\n" -" clippy_lints: \"none\", // Generated file, skip linting\n" -" lints: \"none\",\n" -"}\n" -"```" +#: src/android/interoperability/with-c/bindgen.md:112 +#: src/android/interoperability/with-c/bindgen.md:114 +msgid "\"libbirthday_bindgen_test\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:113 +msgid "\":libbirthday_bindgen\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:115 +msgid "\"general-tests\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:117 +#: src/android/interoperability/with-c/bindgen.md:118 +msgid "\"none\"" +msgstr "" + +#: src/android/interoperability/with-c/bindgen.md:117 +msgid "// Generated file, skip linting\n" msgstr "" #: src/android/interoperability/with-c/rust.md:1 @@ -11575,58 +10530,41 @@ msgstr "" msgid "_interoperability/rust/libanalyze/analyze.rs_" msgstr "" -#: src/android/interoperability/with-c/rust.md:7 -msgid "" -"```rust,editable\n" -"//! Rust FFI demo.\n" -"#![deny(improper_ctypes_definitions)]\n" -"\n" -"use std::os::raw::c_int;\n" -"\n" -"/// Analyze the numbers.\n" -"#[no_mangle]\n" -"pub extern \"C\" fn analyze_numbers(x: c_int, y: c_int) {\n" -" if x < y {\n" -" println!(\"x ({x}) is smallest!\");\n" -" } else {\n" -" println!(\"y ({y}) is probably larger than x ({x})\");\n" -" }\n" -"}\n" -"```" +#: src/android/interoperability/with-c/rust.md:8 +msgid "//! Rust FFI demo.\n" msgstr "" -#: src/android/interoperability/with-c/rust.md:24 -msgid "_interoperability/rust/libanalyze/analyze.h_" +#: src/android/interoperability/with-c/rust.md:12 +msgid "/// Analyze the numbers.\n" msgstr "" -#: src/android/interoperability/with-c/rust.md:26 -msgid "" -"```c\n" -"#ifndef ANALYSE_H\n" -"#define ANALYSE_H\n" -"\n" -"extern \"C\" {\n" -"void analyze_numbers(int x, int y);\n" -"}\n" -"\n" -"#endif\n" -"```" +#: src/android/interoperability/with-c/rust.md:17 +msgid "\"x ({x}) is smallest!\"" +msgstr "" + +#: src/android/interoperability/with-c/rust.md:19 +msgid "\"y ({y}) is probably larger than x ({x})\"" +msgstr "" + +#: src/android/interoperability/with-c/rust.md:24 +msgid "_interoperability/rust/libanalyze/analyze.h_" msgstr "" #: src/android/interoperability/with-c/rust.md:37 msgid "_interoperability/rust/libanalyze/Android.bp_" msgstr "" -#: src/android/interoperability/with-c/rust.md:39 -msgid "" -"```javascript\n" -"rust_ffi {\n" -" name: \"libanalyze_ffi\",\n" -" crate_name: \"analyze_ffi\",\n" -" srcs: [\"analyze.rs\"],\n" -" include_dirs: [\".\"],\n" -"}\n" -"```" +#: src/android/interoperability/with-c/rust.md:41 +#: src/android/interoperability/with-c/rust.md:68 +msgid "\"libanalyze_ffi\"" +msgstr "" + +#: src/android/interoperability/with-c/rust.md:42 +msgid "\"analyze_ffi\"" +msgstr "" + +#: src/android/interoperability/with-c/rust.md:43 +msgid "\"analyze.rs\"" msgstr "" #: src/android/interoperability/with-c/rust.md:48 @@ -11637,32 +10575,20 @@ msgstr "" msgid "_interoperability/rust/analyze/main.c_" msgstr "" -#: src/android/interoperability/with-c/rust.md:52 -msgid "" -"```c\n" -"#include \"analyze.h\"\n" -"\n" -"int main() {\n" -" analyze_numbers(10, 20);\n" -" analyze_numbers(123, 123);\n" -" return 0;\n" -"}\n" -"```" +#: src/android/interoperability/with-c/rust.md:53 +msgid "\"analyze.h\"" msgstr "" #: src/android/interoperability/with-c/rust.md:62 msgid "_interoperability/rust/analyze/Android.bp_" msgstr "" -#: src/android/interoperability/with-c/rust.md:64 -msgid "" -"```javascript\n" -"cc_binary {\n" -" name: \"analyze_numbers\",\n" -" srcs: [\"main.c\"],\n" -" static_libs: [\"libanalyze_ffi\"],\n" -"}\n" -"```" +#: src/android/interoperability/with-c/rust.md:66 +msgid "\"analyze_numbers\"" +msgstr "" + +#: src/android/interoperability/with-c/rust.md:67 +msgid "\"main.c\"" msgstr "" #: src/android/interoperability/with-c/rust.md:75 @@ -11682,6 +10608,10 @@ msgid "" "\"some_name\"]` to specify whatever name you want." msgstr "" +#: src/android/interoperability/cpp.md:1 +msgid "With C++" +msgstr "با C++" + #: src/android/interoperability/cpp.md:3 msgid "" "The [CXX crate](https://cxx.rs/) makes it possible to do safe " @@ -11692,995 +10622,1232 @@ msgstr "" msgid "The overall approach looks like this:" msgstr "" -#: src/android/interoperability/cpp.md:10 +#: src/android/interoperability/cpp/bridge.md:3 msgid "" -"See the [CXX tutorial](https://cxx.rs/tutorial.html) for an full example of " -"using this." +"CXX relies on a description of the function signatures that will be exposed " +"from each language to the other. You provide this description using extern " +"blocks in a Rust module annotated with the `#[cxx::bridge]` attribute macro." msgstr "" -#: src/android/interoperability/cpp.md:14 -msgid "" -"At this point, the instructor should switch to the [CXX tutorial](https://" -"cxx.rs/tutorial.html)." +#: src/android/interoperability/cpp/bridge.md:9 +msgid "\"org::blobstore\"" msgstr "" -#: src/android/interoperability/cpp.md:16 -msgid "Walk the students through the tutorial step by step." +#: src/android/interoperability/cpp/bridge.md:11 +msgid "// Shared structs with fields visible to both languages.\n" msgstr "" -#: src/android/interoperability/cpp.md:18 -msgid "" -"Highlight how CXX presents a clean interface without unsafe code in _both " -"languages_." +#: src/android/interoperability/cpp/bridge.md:17 +#: src/android/interoperability/cpp/generated-cpp.md:6 +msgid "// Rust types and signatures exposed to C++.\n" msgstr "" -#: src/android/interoperability/cpp.md:20 -msgid "" -"Show the correspondence between [Rust and C++ types](https://cxx.rs/bindings." -"html):" +#: src/android/interoperability/cpp/bridge.md:18 +#: src/android/interoperability/cpp/rust-bridge.md:6 +#: src/android/interoperability/cpp/generated-cpp.md:7 +#: src/android/interoperability/cpp/rust-result.md:6 +#, fuzzy +msgid "\"Rust\"" +msgstr "Rustdoc" + +#: src/android/interoperability/cpp/bridge.md:24 +#: src/android/interoperability/cpp/cpp-bridge.md:6 +msgid "// C++ types and signatures exposed to Rust.\n" msgstr "" -#: src/android/interoperability/cpp.md:22 -msgid "" -"Explain how a Rust `String` cannot map to a C++ `std::string` (the latter " -"does not uphold the UTF-8 invariant). Show that despite being different " -"types, `rust::String` in C++ can be easily constructed from a C++ `std::" -"string`, making it very ergonomic to use." +#: src/android/interoperability/cpp/bridge.md:25 +#: src/android/interoperability/cpp/cpp-bridge.md:7 +#: src/android/interoperability/cpp/cpp-exception.md:6 +msgid "\"C++\"" msgstr "" -#: src/android/interoperability/cpp.md:28 -msgid "" -"Explain that a Rust function returning `Result` becomes a function " -"which throws a `E` exception in C++ (and vice versa)." +#: src/android/interoperability/cpp/bridge.md:26 +#: src/android/interoperability/cpp/cpp-bridge.md:8 +msgid "\"include/blobstore.h\"" msgstr "" -#: src/android/interoperability/java.md:1 -msgid "Interoperability with Java" +#: src/android/interoperability/cpp/bridge.md:40 +msgid "The bridge is generally declared in an `ffi` module within your crate." msgstr "" -#: src/android/interoperability/java.md:3 +#: src/android/interoperability/cpp/bridge.md:41 msgid "" -"Java can load shared objects via [Java Native Interface (JNI)](https://en." -"wikipedia.org/wiki/Java_Native_Interface). The [`jni` crate](https://docs.rs/" -"jni/) allows you to create a compatible library." +"From the declarations made in the bridge module, CXX will generate matching " +"Rust and C++ type/function definitions in order to expose those items to " +"both languages." msgstr "" -#: src/android/interoperability/java.md:7 -msgid "First, we create a Rust function to export to Java:" +#: src/android/interoperability/cpp/bridge.md:44 +msgid "" +"To view the generated Rust code, use [cargo-expand](https://github.com/" +"dtolnay/cargo-expand) to view the expanded proc macro. For most of the " +"examples you would use `cargo expand ::ffi` to expand just the `ffi` module " +"(though this doesn't apply for Android projects)." msgstr "" -#: src/android/interoperability/java.md:9 -msgid "_interoperability/java/src/lib.rs_:" +#: src/android/interoperability/cpp/bridge.md:47 +msgid "To view the generated C++ code, look in `target/cxxbridge`." msgstr "" -#: src/android/interoperability/java.md:11 -msgid "" -"```rust,compile_fail\n" -"//! Rust <-> Java FFI demo.\n" -"\n" -"use jni::objects::{JClass, JString};\n" -"use jni::sys::jstring;\n" -"use jni::JNIEnv;\n" -"\n" -"/// HelloWorld::hello method implementation.\n" -"#[no_mangle]\n" -"pub extern \"system\" fn Java_HelloWorld_hello(\n" -" env: JNIEnv,\n" -" _class: JClass,\n" -" name: JString,\n" -") -> jstring {\n" -" let input: String = env.get_string(name).unwrap().into();\n" -" let greeting = format!(\"Hello, {input}!\");\n" -" let output = env.new_string(greeting).unwrap();\n" -" output.into_inner()\n" -"}\n" -"```" +#: src/android/interoperability/cpp/rust-bridge.md:1 +msgid "Rust Bridge Declarations" msgstr "" -#: src/android/interoperability/java.md:32 -#: src/android/interoperability/java.md:62 -msgid "_interoperability/java/Android.bp_:" +#: src/android/interoperability/cpp/rust-bridge.md:7 +msgid "// Opaque type\n" msgstr "" -#: src/android/interoperability/java.md:34 -msgid "" -"```javascript\n" -"rust_ffi_shared {\n" -" name: \"libhello_jni\",\n" -" crate_name: \"hello_jni\",\n" -" srcs: [\"src/lib.rs\"],\n" -" rustlibs: [\"libjni\"],\n" -"}\n" -"```" +#: src/android/interoperability/cpp/rust-bridge.md:8 +msgid "// Method on `MyType`\n" msgstr "" -#: src/android/interoperability/java.md:43 -msgid "Finally, we can call this function from Java:" -msgstr "" +#: src/android/interoperability/cpp/rust-bridge.md:9 +#, fuzzy +msgid "// Free function\n" +msgstr "توابع" -#: src/android/interoperability/java.md:45 -msgid "_interoperability/java/HelloWorld.java_:" +#: src/android/interoperability/cpp/rust-bridge.md:28 +msgid "" +"Items declared in the `extern \"Rust\"` reference items that are in scope in " +"the parent module." msgstr "" -#: src/android/interoperability/java.md:47 +#: src/android/interoperability/cpp/rust-bridge.md:30 msgid "" -"```java\n" -"class HelloWorld {\n" -" private static native String hello(String name);\n" -"\n" -" static {\n" -" System.loadLibrary(\"hello_jni\");\n" -" }\n" -"\n" -" public static void main(String[] args) {\n" -" String output = HelloWorld.hello(\"Alice\");\n" -" System.out.println(output);\n" -" }\n" -"}\n" -"```" +"The CXX code generator uses your `extern \"Rust\"` section(s) to produce a C+" +"+ header file containing the corresponding C++ declarations. The generated " +"header has the same path as the Rust source file containing the bridge, " +"except with a .rs.h file extension." msgstr "" -#: src/android/interoperability/java.md:64 -msgid "" -"```javascript\n" -"java_binary {\n" -" name: \"helloworld_jni\",\n" -" srcs: [\"HelloWorld.java\"],\n" -" main_class: \"HelloWorld\",\n" -" required: [\"libhello_jni\"],\n" -"}\n" -"```" +#: src/android/interoperability/cpp/generated-cpp.md:15 +msgid "Results in (roughly) the following C++:" msgstr "" -#: src/android/interoperability/java.md:73 -msgid "Finally, you can build, sync, and run the binary:" +#: src/android/interoperability/cpp/cpp-bridge.md:1 +msgid "C++ Bridge Declarations" msgstr "" -#: src/exercises/android/morning.md:3 -msgid "" -"This is a group exercise: We will look at one of the projects you work with " -"and try to integrate some Rust into it. Some suggestions:" +#: src/android/interoperability/cpp/cpp-bridge.md:20 +msgid "Results in (roughly) the following Rust:" msgstr "" -#: src/exercises/android/morning.md:6 -msgid "Call your AIDL service with a client written in Rust." +#: src/android/interoperability/cpp/cpp-bridge.md:30 +msgid "\"org$blobstore$cxxbridge1$new_blobstore_client\"" msgstr "" -#: src/exercises/android/morning.md:8 -msgid "Move a function from your project to Rust and call it." +#: src/android/interoperability/cpp/cpp-bridge.md:39 +msgid "\"org$blobstore$cxxbridge1$BlobstoreClient$put\"" msgstr "" -#: src/exercises/android/morning.md:12 +#: src/android/interoperability/cpp/cpp-bridge.md:56 msgid "" -"No solution is provided here since this is open-ended: it relies on someone " -"in the class having a piece of code which you can turn in to Rust on the fly." +"The programmer does not need to promise that the signatures they have typed " +"in are accurate. CXX performs static assertions that the signatures exactly " +"correspond with what is declared in C++." msgstr "" -#: src/bare-metal.md:1 -msgid "Welcome to Bare Metal Rust" +#: src/android/interoperability/cpp/cpp-bridge.md:59 +msgid "" +"`unsafe extern` blocks allow you to declare C++ functions that are safe to " +"call from Rust." msgstr "" -#: src/bare-metal.md:3 -msgid "" -"This is a standalone one-day course about bare-metal Rust, aimed at people " -"who are familiar with the basics of Rust (perhaps from completing the " -"Comprehensive Rust course), and ideally also have some experience with bare-" -"metal programming in some other language such as C." +#: src/android/interoperability/cpp/shared-types.md:9 +msgid "// A=1, J=11, Q=12, K=13\n" msgstr "" -#: src/bare-metal.md:7 +#: src/android/interoperability/cpp/shared-types.md:23 +msgid "Only C-like (unit) enums are supported." +msgstr "" + +#: src/android/interoperability/cpp/shared-types.md:24 msgid "" -"Today we will talk about 'bare-metal' Rust: running Rust code without an OS " -"underneath us. This will be divided into several parts:" +"A limited number of traits are supported for `#[derive()]` on shared types. " +"Corresponding functionality is also generated for the C++ code, e.g. if you " +"derive `Hash` also generates an implementation of `std::hash` for the " +"corresponding C++ type." msgstr "" -#: src/bare-metal.md:10 -msgid "What is `no_std` Rust?" +#: src/android/interoperability/cpp/shared-enums.md:15 +#, fuzzy +msgid "Generated Rust:" +msgstr "Rust ناایمن" + +#: src/android/interoperability/cpp/shared-enums.md:33 +msgid "Generated C++:" msgstr "" -#: src/bare-metal.md:11 -msgid "Writing firmware for microcontrollers." +#: src/android/interoperability/cpp/shared-enums.md:46 +msgid "" +"On the Rust side, the code generated for shared enums is actually a struct " +"wrapping a numeric value. This is because it is not UB in C++ for an enum " +"class to hold a value different from all of the listed variants, and our " +"Rust representation needs to have the same behavior." msgstr "" -#: src/bare-metal.md:12 -msgid "Writing bootloader / kernel code for application processors." +#: src/android/interoperability/cpp/rust-result.md:13 +msgid "\"fallible1 requires depth > 0\"" msgstr "" -#: src/bare-metal.md:13 -msgid "Some useful crates for bare-metal Rust development." +#: src/android/interoperability/cpp/rust-result.md:16 +msgid "\"Success!\"" msgstr "" -#: src/bare-metal.md:15 +#: src/android/interoperability/cpp/rust-result.md:22 msgid "" -"For the microcontroller part of the course we will use the [BBC micro:bit]" -"(https://microbit.org/) v2 as an example. It's a [development board](https://" -"tech.microbit.org/hardware/) based on the Nordic nRF51822 microcontroller " -"with some LEDs and buttons, an I2C-connected accelerometer and compass, and " -"an on-board SWD debugger." +"Rust functions that return `Result` are translated to exceptions on the C++ " +"side." msgstr "" -#: src/bare-metal.md:20 +#: src/android/interoperability/cpp/rust-result.md:24 msgid "" -"To get started, install some tools we'll need later. On gLinux or Debian:" +"The exception thrown will always be of type `rust::Error`, which primarily " +"exposes a way to get the error message string. The error message will come " +"from the error type's `Display` impl." msgstr "" -#: src/bare-metal.md:30 +#: src/android/interoperability/cpp/rust-result.md:27 msgid "" -"And give users in the `plugdev` group access to the micro:bit programmer:" +"A panic unwinding from Rust to C++ will always cause the process to " +"immediately terminate." msgstr "" -#: src/bare-metal.md:38 src/bare-metal/microcontrollers/debugging.md:27 -msgid "On MacOS:" +#: src/android/interoperability/cpp/cpp-exception.md:7 +msgid "\"example/include/example.h\"" msgstr "" -#: src/bare-metal/no_std.md:1 -msgid "`no_std`" +#: src/android/interoperability/cpp/cpp-exception.md:14 +msgid "\"Error: {}\"" msgstr "" -#: src/bare-metal/no_std.md:7 -msgid "`core`" +#: src/android/interoperability/cpp/cpp-exception.md:22 +msgid "" +"C++ functions declared to return a `Result` will catch any thrown exception " +"on the C++ side and return it as an `Err` value to the calling Rust function." msgstr "" -#: src/bare-metal/no_std.md:12 src/bare-metal/alloc.md:1 -msgid "`alloc`" +#: src/android/interoperability/cpp/cpp-exception.md:24 +msgid "" +"If an exception is thrown from an extern \"C++\" function that is not " +"declared by the CXX bridge to return `Result`, the program calls C++'s `std::" +"terminate`. The behavior is equivalent to the same exception being thrown " +"through a `noexcept` C++ function." msgstr "" -#: src/bare-metal/no_std.md:17 -msgid "`std`" -msgstr "" +#: src/android/interoperability/cpp/type-mapping.md:3 +#, fuzzy +msgid "Rust Type" +msgstr "انواع داده‌های بازگشتی" -#: src/bare-metal/no_std.md:24 -msgid "Slices, `&str`, `CStr`" +#: src/android/interoperability/cpp/type-mapping.md:3 +#, fuzzy +msgid "C++ Type" +msgstr "انواع" + +#: src/android/interoperability/cpp/type-mapping.md:5 +#, fuzzy +msgid "`String`" +msgstr "String" + +#: src/android/interoperability/cpp/type-mapping.md:5 +#, fuzzy +msgid "`rust::String`" +msgstr "String" + +#: src/android/interoperability/cpp/type-mapping.md:6 +msgid "`rust::Str`" msgstr "" -#: src/bare-metal/no_std.md:25 -msgid "`NonZeroU8`..." +#: src/android/interoperability/cpp/type-mapping.md:7 +#, fuzzy +msgid "`CxxString`" +msgstr "String" + +#: src/android/interoperability/cpp/type-mapping.md:7 +#, fuzzy +msgid "`std::string`" +msgstr "String" + +#: src/android/interoperability/cpp/type-mapping.md:8 +msgid "`&[T]`/`&mut [T]`" msgstr "" -#: src/bare-metal/no_std.md:26 -msgid "`Option`, `Result`" +#: src/android/interoperability/cpp/type-mapping.md:8 +msgid "`rust::Slice`" msgstr "" -#: src/bare-metal/no_std.md:27 -msgid "`Display`, `Debug`, `write!`..." +#: src/android/interoperability/cpp/type-mapping.md:9 +msgid "`Box`" msgstr "" -#: src/bare-metal/no_std.md:29 -msgid "`panic!`, `assert_eq!`..." +#: src/android/interoperability/cpp/type-mapping.md:9 +msgid "`rust::Box`" msgstr "" -#: src/bare-metal/no_std.md:30 -msgid "`NonNull` and all the usual pointer-related functions" +#: src/android/interoperability/cpp/type-mapping.md:10 +msgid "`UniquePtr`" msgstr "" -#: src/bare-metal/no_std.md:31 -msgid "`Future` and `async`/`await`" +#: src/android/interoperability/cpp/type-mapping.md:10 +msgid "`std::unique_ptr`" msgstr "" -#: src/bare-metal/no_std.md:32 -msgid "`fence`, `AtomicBool`, `AtomicPtr`, `AtomicU32`..." +#: src/android/interoperability/cpp/type-mapping.md:11 +msgid "`Vec`" msgstr "" -#: src/bare-metal/no_std.md:33 -msgid "`Duration`" +#: src/android/interoperability/cpp/type-mapping.md:11 +msgid "`rust::Vec`" msgstr "" -#: src/bare-metal/no_std.md:38 -msgid "`Box`, `Cow`, `Arc`, `Rc`" +#: src/android/interoperability/cpp/type-mapping.md:12 +msgid "`CxxVector`" msgstr "" -#: src/bare-metal/no_std.md:39 -msgid "`Vec`, `BinaryHeap`, `BtreeMap`, `LinkedList`, `VecDeque`" +#: src/android/interoperability/cpp/type-mapping.md:12 +msgid "`std::vector`" msgstr "" -#: src/bare-metal/no_std.md:40 -msgid "`String`, `CString`, `format!`" +#: src/android/interoperability/cpp/type-mapping.md:16 +msgid "" +"These types can be used in the fields of shared structs and the arguments " +"and returns of extern functions." msgstr "" -#: src/bare-metal/no_std.md:45 -msgid "`Error`" +#: src/android/interoperability/cpp/type-mapping.md:18 +msgid "" +"Note that Rust's `String` does not map directly to `std::string`. There are " +"a few reasons for this:" msgstr "" -#: src/bare-metal/no_std.md:47 -msgid "`Mutex`, `Condvar`, `Barrier`, `Once`, `RwLock`, `mpsc`" +#: src/android/interoperability/cpp/type-mapping.md:20 +msgid "" +"`std::string` does not uphold the UTF-8 invariant that `String` requires." msgstr "" -#: src/bare-metal/no_std.md:48 -msgid "`File` and the rest of `fs`" +#: src/android/interoperability/cpp/type-mapping.md:21 +msgid "" +"The two types have different layouts in memory and so can't be passed " +"directly between languages." msgstr "" -#: src/bare-metal/no_std.md:49 -msgid "`println!`, `Read`, `Write`, `Stdin`, `Stdout` and the rest of `io`" +#: src/android/interoperability/cpp/type-mapping.md:23 +msgid "" +"`std::string` requires move constructors that don't match Rust's move " +"semantics, so a `std::string` can't be passed by value to Rust." msgstr "" -#: src/bare-metal/no_std.md:50 -msgid "`Path`, `OsString`" -msgstr "" +#: src/android/interoperability/cpp/android-build-cpp.md:1 +#: src/android/interoperability/cpp/android-cpp-genrules.md:1 +#: src/android/interoperability/cpp/android-build-rust.md:1 +#, fuzzy +msgid "Building in Android" +msgstr "Rust در اندروید" -#: src/bare-metal/no_std.md:51 -msgid "`net`" +#: src/android/interoperability/cpp/android-build-cpp.md:3 +msgid "" +"Create a `cc_library_static` to build the C++ library, including the CXX " +"generated header and source file." msgstr "" -#: src/bare-metal/no_std.md:52 -msgid "`Command`, `Child`, `ExitCode`" +#: src/android/interoperability/cpp/android-build-cpp.md:8 +#: src/android/interoperability/cpp/android-build-rust.md:10 +msgid "\"libcxx_test_cpp\"" msgstr "" -#: src/bare-metal/no_std.md:53 -msgid "`spawn`, `sleep` and the rest of `thread`" +#: src/android/interoperability/cpp/android-build-cpp.md:9 +msgid "\"cxx_test.cpp\"" msgstr "" -#: src/bare-metal/no_std.md:54 -msgid "`SystemTime`, `Instant`" +#: src/android/interoperability/cpp/android-build-cpp.md:11 +msgid "\"cxx-bridge-header\"" msgstr "" -#: src/bare-metal/no_std.md:62 -msgid "`HashMap` depends on RNG." +#: src/android/interoperability/cpp/android-build-cpp.md:12 +#: src/android/interoperability/cpp/android-cpp-genrules.md:10 +msgid "\"libcxx_test_bridge_header\"" msgstr "" -#: src/bare-metal/no_std.md:63 -msgid "`std` re-exports the contents of both `core` and `alloc`." +#: src/android/interoperability/cpp/android-build-cpp.md:14 +#: src/android/interoperability/cpp/android-cpp-genrules.md:19 +msgid "\"libcxx_test_bridge_code\"" msgstr "" -#: src/bare-metal/minimal.md:1 -msgid "A minimal `no_std` program" +#: src/android/interoperability/cpp/android-build-cpp.md:20 +msgid "" +"Point out that `libcxx_test_bridge_header` and `libcxx_test_bridge_code` are " +"the dependencies for the CXX-generated C++ bindings. We'll show how these " +"are setup on the next slide." msgstr "" -#: src/bare-metal/minimal.md:17 -msgid "This will compile to an empty binary." +#: src/android/interoperability/cpp/android-build-cpp.md:23 +msgid "" +"Note that you also need to depend on the `cxx-bridge-header` library in " +"order to pull in common CXX definitions." msgstr "" -#: src/bare-metal/minimal.md:18 -msgid "`std` provides a panic handler; without it we must provide our own." +#: src/android/interoperability/cpp/android-build-cpp.md:25 +msgid "" +"Full docs for using CXX in Android can be found in [the Android docs]" +"(https://source.android.com/docs/setup/build/rust/building-rust-modules/" +"android-rust-patterns#rust-cpp-interop-using-cxx). You may want to share " +"that link with the class so that students know where they can find these " +"instructions again in the future." msgstr "" -#: src/bare-metal/minimal.md:19 -msgid "It can also be provided by another crate, such as `panic-halt`." +#: src/android/interoperability/cpp/android-cpp-genrules.md:3 +msgid "" +"Create two genrules: One to generate the CXX header, and one to generate the " +"CXX source file. These are then used as inputs to the `cc_library_static`." msgstr "" -#: src/bare-metal/minimal.md:20 -msgid "" -"Depending on the target, you may need to compile with `panic = \"abort\"` to " -"avoid an error about `eh_personality`." +#: src/android/interoperability/cpp/android-cpp-genrules.md:7 +msgid "// Generate a C++ header containing the C++ bindings" msgstr "" -#: src/bare-metal/minimal.md:22 -msgid "" -"Note that there is no `main` or any other entry point; it's up to you to " -"define your own entry point. This will typically involve a linker script and " -"some assembly code to set things up ready for Rust code to run." +#: src/android/interoperability/cpp/android-cpp-genrules.md:7 +msgid "// to the Rust exported functions in lib.rs." msgstr "" -#: src/bare-metal/alloc.md:3 -msgid "" -"To use `alloc` you must implement a [global (heap) allocator](https://doc." -"rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html)." +#: src/android/interoperability/cpp/android-cpp-genrules.md:11 +#: src/android/interoperability/cpp/android-cpp-genrules.md:20 +msgid "\"cxxbridge\"" msgstr "" -#: src/bare-metal/alloc.md:6 -msgid "" -"```rust,editable,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"extern crate alloc;\n" -"extern crate panic_halt as _;\n" -"\n" -"use alloc::string::ToString;\n" -"use alloc::vec::Vec;\n" -"use buddy_system_allocator::LockedHeap;\n" -"\n" -"#[global_allocator]\n" -"static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::new();\n" -"\n" -"static mut HEAP: [u8; 65536] = [0; 65536];\n" -"\n" -"pub fn entry() {\n" -" // Safe because `HEAP` is only used here and `entry` is only called " -"once.\n" -" unsafe {\n" -" // Give the allocator some memory to allocate.\n" -" HEAP_ALLOCATOR\n" -" .lock()\n" -" .init(HEAP.as_mut_ptr() as usize, HEAP.len());\n" -" }\n" -"\n" -" // Now we can do things that require heap allocation.\n" -" let mut v = Vec::new();\n" -" v.push(\"A string\".to_string());\n" -"}\n" -"```" +#: src/android/interoperability/cpp/android-cpp-genrules.md:12 +msgid "\"$(location cxxbridge) $(in) --header > $(out)\"" msgstr "" -#: src/bare-metal/alloc.md:39 -msgid "" -"`buddy_system_allocator` is a third-party crate implementing a basic buddy " -"system allocator. Other crates are available, or you can write your own or " -"hook into your existing allocator." +#: src/android/interoperability/cpp/android-cpp-genrules.md:13 +#: src/android/interoperability/cpp/android-cpp-genrules.md:22 +#: src/android/interoperability/cpp/android-build-rust.md:8 +msgid "\"lib.rs\"" msgstr "" -#: src/bare-metal/alloc.md:41 -msgid "" -"The const parameter of `LockedHeap` is the max order of the allocator; i.e. " -"in this case it can allocate regions of up to 2\\*\\*32 bytes." +#: src/android/interoperability/cpp/android-cpp-genrules.md:14 +msgid "\"lib.rs.h\"" msgstr "" -#: src/bare-metal/alloc.md:43 -msgid "" -"If any crate in your dependency tree depends on `alloc` then you must have " -"exactly one global allocator defined in your binary. Usually this is done in " -"the top-level binary crate." +#: src/android/interoperability/cpp/android-cpp-genrules.md:16 +msgid "// Generate the C++ code that Rust calls into." msgstr "" -#: src/bare-metal/alloc.md:45 -msgid "" -"`extern crate panic_halt as _` is necessary to ensure that the `panic_halt` " -"crate is linked in so we get its panic handler." +#: src/android/interoperability/cpp/android-cpp-genrules.md:21 +msgid "\"$(location cxxbridge) $(in) > $(out)\"" msgstr "" -#: src/bare-metal/alloc.md:47 -msgid "This example will build but not run, as it doesn't have an entry point." +#: src/android/interoperability/cpp/android-cpp-genrules.md:23 +msgid "\"lib.rs.cc\"" msgstr "" -#: src/bare-metal/microcontrollers.md:3 +#: src/android/interoperability/cpp/android-cpp-genrules.md:29 msgid "" -"The `cortex_m_rt` crate provides (among other things) a reset handler for " -"Cortex M microcontrollers." +"The `cxxbridge` tool is a standalone tool that generates the C++ side of the " +"bridge module. It is included in Android and available as a Soong tool." msgstr "" -#: src/bare-metal/microcontrollers.md:21 +#: src/android/interoperability/cpp/android-cpp-genrules.md:31 msgid "" -"Next we'll look at how to access peripherals, with increasing levels of " -"abstraction." +"By convention, if your Rust source file is `lib.rs` your header file will be " +"named `lib.rs.h` and your source file will be named `lib.rs.cc`. This naming " +"convention isn't enforced, though." msgstr "" -#: src/bare-metal/microcontrollers.md:25 +#: src/android/interoperability/cpp/android-build-rust.md:3 msgid "" -"The `cortex_m_rt::entry` macro requires that the function have type `fn() -" -"> !`, because returning to the reset handler doesn't make sense." +"Create a `rust_binary` that depends on `libcxx` and your `cc_library_static`." msgstr "" -#: src/bare-metal/microcontrollers.md:27 -msgid "Run the example with `cargo embed --bin minimal`" +#: src/android/interoperability/cpp/android-build-rust.md:7 +msgid "\"cxx_test\"" msgstr "" -#: src/bare-metal/microcontrollers/mmio.md:3 -msgid "" -"Most microcontrollers access peripherals via memory-mapped IO. Let's try " -"turning on an LED on our micro:bit:" +#: src/android/interoperability/cpp/android-build-rust.md:9 +msgid "\"libcxx\"" msgstr "" -#: src/bare-metal/microcontrollers/mmio.md:6 -msgid "" -"```rust,editable,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"extern crate panic_halt as _;\n" -"\n" -"mod interrupts;\n" -"\n" -"use core::mem::size_of;\n" -"use cortex_m_rt::entry;\n" -"\n" -"/// GPIO port 0 peripheral address\n" -"const GPIO_P0: usize = 0x5000_0000;\n" -"\n" -"// GPIO peripheral offsets\n" -"const PIN_CNF: usize = 0x700;\n" -"const OUTSET: usize = 0x508;\n" -"const OUTCLR: usize = 0x50c;\n" -"\n" -"// PIN_CNF fields\n" -"const DIR_OUTPUT: u32 = 0x1;\n" -"const INPUT_DISCONNECT: u32 = 0x1 << 1;\n" -"const PULL_DISABLED: u32 = 0x0 << 2;\n" -"const DRIVE_S0S1: u32 = 0x0 << 8;\n" -"const SENSE_DISABLED: u32 = 0x0 << 16;\n" -"\n" -"#[entry]\n" -"fn main() -> ! {\n" -" // Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n" -" let pin_cnf_21 = (GPIO_P0 + PIN_CNF + 21 * size_of::()) as *mut " -"u32;\n" -" let pin_cnf_28 = (GPIO_P0 + PIN_CNF + 28 * size_of::()) as *mut " -"u32;\n" -" // Safe because the pointers are to valid peripheral control registers, " -"and\n" -" // no aliases exist.\n" -" unsafe {\n" -" pin_cnf_21.write_volatile(\n" -" DIR_OUTPUT | INPUT_DISCONNECT | PULL_DISABLED | DRIVE_S0S1 | " -"SENSE_DISABLED,\n" -" );\n" -" pin_cnf_28.write_volatile(\n" -" DIR_OUTPUT | INPUT_DISCONNECT | PULL_DISABLED | DRIVE_S0S1 | " -"SENSE_DISABLED,\n" -" );\n" -" }\n" -"\n" -" // Set pin 28 low and pin 21 high to turn the LED on.\n" -" let gpio0_outset = (GPIO_P0 + OUTSET) as *mut u32;\n" -" let gpio0_outclr = (GPIO_P0 + OUTCLR) as *mut u32;\n" -" // Safe because the pointers are to valid peripheral control registers, " -"and\n" -" // no aliases exist.\n" -" unsafe {\n" -" gpio0_outclr.write_volatile(1 << 28);\n" -" gpio0_outset.write_volatile(1 << 21);\n" -" }\n" -"\n" -" loop {}\n" -"}\n" -"```" +#: src/android/interoperability/java.md:1 +msgid "Interoperability with Java" msgstr "" -#: src/bare-metal/microcontrollers/mmio.md:64 +#: src/android/interoperability/java.md:3 msgid "" -"GPIO 0 pin 21 is connected to the first column of the LED matrix, and pin 28 " -"to the first row." +"Java can load shared objects via [Java Native Interface (JNI)](https://en." +"wikipedia.org/wiki/Java_Native_Interface). The [`jni` crate](https://docs.rs/" +"jni/) allows you to create a compatible library." msgstr "" -#: src/bare-metal/microcontrollers/mmio.md:66 -#: src/bare-metal/microcontrollers/pacs.md:59 -#: src/bare-metal/microcontrollers/hals.md:43 -#: src/bare-metal/microcontrollers/board-support.md:34 -msgid "Run the example with:" +#: src/android/interoperability/java.md:7 +msgid "First, we create a Rust function to export to Java:" msgstr "" -#: src/bare-metal/microcontrollers/pacs.md:1 -msgid "Peripheral Access Crates" +#: src/android/interoperability/java.md:9 +msgid "_interoperability/java/src/lib.rs_:" msgstr "" -#: src/bare-metal/microcontrollers/pacs.md:3 -msgid "" -"[`svd2rust`](https://crates.io/crates/svd2rust) generates mostly-safe Rust " -"wrappers for memory-mapped peripherals from [CMSIS-SVD](https://www.keil.com/" -"pack/doc/CMSIS/SVD/html/index.html) files." +#: src/android/interoperability/java.md:12 +msgid "//! Rust <-> Java FFI demo.\n" msgstr "" -#: src/bare-metal/microcontrollers/pacs.md:7 -msgid "" -"```rust,editable,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"extern crate panic_halt as _;\n" -"\n" -"use cortex_m_rt::entry;\n" -"use nrf52833_pac::Peripherals;\n" -"\n" -"#[entry]\n" -"fn main() -> ! {\n" -" let p = Peripherals::take().unwrap();\n" -" let gpio0 = p.P0;\n" -"\n" -" // Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n" -" gpio0.pin_cnf[21].write(|w| {\n" -" w.dir().output();\n" -" w.input().disconnect();\n" -" w.pull().disabled();\n" -" w.drive().s0s1();\n" -" w.sense().disabled();\n" -" w\n" -" });\n" -" gpio0.pin_cnf[28].write(|w| {\n" -" w.dir().output();\n" -" w.input().disconnect();\n" -" w.pull().disabled();\n" -" w.drive().s0s1();\n" -" w.sense().disabled();\n" -" w\n" -" });\n" -"\n" -" // Set pin 28 low and pin 21 high to turn the LED on.\n" -" gpio0.outclr.write(|w| w.pin28().clear());\n" -" gpio0.outset.write(|w| w.pin21().set());\n" -"\n" -" loop {}\n" -"}\n" -"```" +#: src/android/interoperability/java.md:17 +msgid "/// HelloWorld::hello method implementation.\n" msgstr "" -#: src/bare-metal/microcontrollers/pacs.md:49 -msgid "" -"SVD (System View Description) files are XML files typically provided by " -"silicon vendors which describe the memory map of the device." +#: src/android/interoperability/java.md:20 +msgid "\"system\"" msgstr "" -#: src/bare-metal/microcontrollers/pacs.md:51 -msgid "" -"They are organised by peripheral, register, field and value, with names, " -"descriptions, addresses and so on." +#: src/android/interoperability/java.md:26 +msgid "\"Hello, {input}!\"" msgstr "" -#: src/bare-metal/microcontrollers/pacs.md:53 -msgid "" -"SVD files are often buggy and incomplete, so there are various projects " -"which patch the mistakes, add missing details, and publish the generated " -"crates." +#: src/android/interoperability/java.md:32 +#: src/android/interoperability/java.md:62 +msgid "_interoperability/java/Android.bp_:" msgstr "" -#: src/bare-metal/microcontrollers/pacs.md:55 -msgid "`cortex-m-rt` provides the vector table, among other things." +#: src/android/interoperability/java.md:36 +#: src/android/interoperability/java.md:69 +msgid "\"libhello_jni\"" msgstr "" -#: src/bare-metal/microcontrollers/pacs.md:56 -msgid "" -"If you `cargo install cargo-binutils` then you can run `cargo objdump --bin " -"pac -- -d --no-show-raw-insn` to see the resulting binary." +#: src/android/interoperability/java.md:37 +#: src/android/interoperability/java.md:52 +msgid "\"hello_jni\"" msgstr "" -#: src/bare-metal/microcontrollers/hals.md:1 -msgid "HAL crates" +#: src/android/interoperability/java.md:39 +msgid "\"libjni\"" msgstr "" -#: src/bare-metal/microcontrollers/hals.md:3 -msgid "" -"[HAL crates](https://github.com/rust-embedded/awesome-embedded-rust#hal-" -"implementation-crates) for many microcontrollers provide wrappers around " -"various peripherals. These generally implement traits from [`embedded-hal`]" -"(https://crates.io/crates/embedded-hal)." +#: src/android/interoperability/java.md:43 +msgid "Finally, we can call this function from Java:" msgstr "" -#: src/bare-metal/microcontrollers/hals.md:7 -msgid "" -"```rust,editable,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"extern crate panic_halt as _;\n" -"\n" -"use cortex_m_rt::entry;\n" -"use nrf52833_hal::gpio::{p0, Level};\n" -"use nrf52833_hal::pac::Peripherals;\n" -"use nrf52833_hal::prelude::*;\n" -"\n" -"#[entry]\n" -"fn main() -> ! {\n" -" let p = Peripherals::take().unwrap();\n" -"\n" -" // Create HAL wrapper for GPIO port 0.\n" -" let gpio0 = p0::Parts::new(p.P0);\n" -"\n" -" // Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n" -" let mut col1 = gpio0.p0_28.into_push_pull_output(Level::High);\n" -" let mut row1 = gpio0.p0_21.into_push_pull_output(Level::Low);\n" -"\n" -" // Set pin 28 low and pin 21 high to turn the LED on.\n" -" col1.set_low().unwrap();\n" -" row1.set_high().unwrap();\n" -"\n" -" loop {}\n" -"}\n" -"```" +#: src/android/interoperability/java.md:45 +msgid "_interoperability/java/HelloWorld.java_:" msgstr "" -#: src/bare-metal/microcontrollers/hals.md:39 -msgid "" -"`set_low` and `set_high` are methods on the `embedded_hal` `OutputPin` trait." +#: src/android/interoperability/java.md:66 +msgid "\"helloworld_jni\"" msgstr "" -#: src/bare-metal/microcontrollers/hals.md:40 -msgid "" -"HAL crates exist for many Cortex-M and RISC-V devices, including various " -"STM32, GD32, nRF, NXP, MSP430, AVR and PIC microcontrollers." -msgstr "" +#: src/android/interoperability/java.md:67 +#, fuzzy +msgid "\"HelloWorld.java\"" +msgstr "سلام دنیا" -#: src/bare-metal/microcontrollers/board-support.md:1 -msgid "Board support crates" +#: src/android/interoperability/java.md:68 +#, fuzzy +msgid "\"HelloWorld\"" +msgstr "سلام دنیا" + +#: src/android/interoperability/java.md:73 +msgid "Finally, you can build, sync, and run the binary:" msgstr "" -#: src/bare-metal/microcontrollers/board-support.md:3 +#: src/exercises/android/morning.md:3 msgid "" -"Board support crates provide a further level of wrapping for a specific " -"board for convenience." +"This is a group exercise: We will look at one of the projects you work with " +"and try to integrate some Rust into it. Some suggestions:" msgstr "" -#: src/bare-metal/microcontrollers/board-support.md:28 -msgid "" -"In this case the board support crate is just providing more useful names, " -"and a bit of initialisation." +#: src/exercises/android/morning.md:6 +msgid "Call your AIDL service with a client written in Rust." msgstr "" -#: src/bare-metal/microcontrollers/board-support.md:30 -msgid "" -"The crate may also include drivers for some on-board devices outside of the " -"microcontroller itself." +#: src/exercises/android/morning.md:8 +msgid "Move a function from your project to Rust and call it." msgstr "" -#: src/bare-metal/microcontrollers/board-support.md:32 -msgid "`microbit-v2` includes a simple driver for the LED matrix." +#: src/exercises/android/morning.md:12 +msgid "" +"No solution is provided here since this is open-ended: it relies on someone " +"in the class having a piece of code which you can turn in to Rust on the fly." msgstr "" -#: src/bare-metal/microcontrollers/type-state.md:1 -msgid "The type state pattern" +#: src/bare-metal.md:1 +msgid "Welcome to Bare Metal Rust" msgstr "" -#: src/bare-metal/microcontrollers/type-state.md:3 +#: src/bare-metal.md:3 msgid "" -"```rust,editable,compile_fail\n" -"#[entry]\n" -"fn main() -> ! {\n" -" let p = Peripherals::take().unwrap();\n" -" let gpio0 = p0::Parts::new(p.P0);\n" -"\n" -" let pin: P0_01 = gpio0.p0_01;\n" -"\n" -" // let gpio0_01_again = gpio0.p0_01; // Error, moved.\n" -" let pin_input: P0_01> = pin.into_floating_input();\n" -" if pin_input.is_high().unwrap() {\n" -" // ...\n" -" }\n" -" let mut pin_output: P0_01> = pin_input\n" -" .into_open_drain_output(OpenDrainConfig::Disconnect0Standard1, " -"Level::Low);\n" -" pin_output.set_high().unwrap();\n" -" // pin_input.is_high(); // Error, moved.\n" -"\n" -" let _pin2: P0_02> = gpio0\n" -" .p0_02\n" -" .into_open_drain_output(OpenDrainConfig::Disconnect0Standard1, " -"Level::Low);\n" -" let _pin3: P0_03> = gpio0.p0_03." -"into_push_pull_output(Level::Low);\n" -"\n" -" loop {}\n" -"}\n" -"```" +"This is a standalone one-day course about bare-metal Rust, aimed at people " +"who are familiar with the basics of Rust (perhaps from completing the " +"Comprehensive Rust course), and ideally also have some experience with bare-" +"metal programming in some other language such as C." msgstr "" -#: src/bare-metal/microcontrollers/type-state.md:32 +#: src/bare-metal.md:7 msgid "" -"Pins don't implement `Copy` or `Clone`, so only one instance of each can " -"exist. Once a pin is moved out of the port struct nobody else can take it." +"Today we will talk about 'bare-metal' Rust: running Rust code without an OS " +"underneath us. This will be divided into several parts:" msgstr "" -#: src/bare-metal/microcontrollers/type-state.md:34 -msgid "" -"Changing the configuration of a pin consumes the old pin instance, so you " -"can’t keep use the old instance afterwards." +#: src/bare-metal.md:10 +msgid "What is `no_std` Rust?" msgstr "" -#: src/bare-metal/microcontrollers/type-state.md:36 -msgid "" -"The type of a value indicates the state that it is in: e.g. in this case, " -"the configuration state of a GPIO pin. This encodes the state machine into " -"the type system, and ensures that you don't try to use a pin in a certain " -"way without properly configuring it first. Illegal state transitions are " -"caught at compile time." +#: src/bare-metal.md:11 +msgid "Writing firmware for microcontrollers." msgstr "" -#: src/bare-metal/microcontrollers/type-state.md:40 -msgid "" -"You can call `is_high` on an input pin and `set_high` on an output pin, but " -"not vice-versa." +#: src/bare-metal.md:12 +msgid "Writing bootloader / kernel code for application processors." msgstr "" -#: src/bare-metal/microcontrollers/type-state.md:41 -msgid "Many HAL crates follow this pattern." +#: src/bare-metal.md:13 +msgid "Some useful crates for bare-metal Rust development." msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:1 -msgid "`embedded-hal`" +#: src/bare-metal.md:15 +msgid "" +"For the microcontroller part of the course we will use the [BBC micro:bit]" +"(https://microbit.org/) v2 as an example. It's a [development board](https://" +"tech.microbit.org/hardware/) based on the Nordic nRF51822 microcontroller " +"with some LEDs and buttons, an I2C-connected accelerometer and compass, and " +"an on-board SWD debugger." msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:3 +#: src/bare-metal.md:20 msgid "" -"The [`embedded-hal`](https://crates.io/crates/embedded-hal) crate provides a " -"number of traits covering common microcontroller peripherals." +"To get started, install some tools we'll need later. On gLinux or Debian:" msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:6 -msgid "GPIO" +#: src/bare-metal.md:30 +msgid "" +"And give users in the `plugdev` group access to the micro:bit programmer:" msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:7 -msgid "ADC" +#: src/bare-metal.md:38 src/bare-metal/microcontrollers/debugging.md:27 +msgid "On MacOS:" msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:8 -msgid "I2C, SPI, UART, CAN" +#: src/bare-metal/no_std.md:1 +msgid "`no_std`" msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:9 -msgid "RNG" +#: src/bare-metal/no_std.md:7 +msgid "`core`" msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:10 -msgid "Timers" +#: src/bare-metal/no_std.md:12 src/bare-metal/alloc.md:1 +msgid "`alloc`" msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:11 -msgid "Watchdogs" +#: src/bare-metal/no_std.md:17 +msgid "`std`" msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:13 -msgid "" -"Other crates then implement [drivers](https://github.com/rust-embedded/" -"awesome-embedded-rust#driver-crates) in terms of these traits, e.g. an " -"accelerometer driver might need an I2C or SPI bus implementation." +#: src/bare-metal/no_std.md:24 +msgid "Slices, `&str`, `CStr`" msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:19 -msgid "" -"There are implementations for many microcontrollers, as well as other " -"platforms such as Linux on Raspberry Pi." +#: src/bare-metal/no_std.md:25 +msgid "`NonZeroU8`..." msgstr "" -#: src/bare-metal/microcontrollers/embedded-hal.md:21 -msgid "" -"There is work in progress on an `async` version of `embedded-hal`, but it " -"isn't stable yet." +#: src/bare-metal/no_std.md:26 +msgid "`Option`, `Result`" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:1 -msgid "`probe-rs`, `cargo-embed`" +#: src/bare-metal/no_std.md:27 +msgid "`Display`, `Debug`, `write!`..." msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:3 -msgid "" -"[probe-rs](https://probe.rs/) is a handy toolset for embedded debugging, " -"like OpenOCD but better integrated." +#: src/bare-metal/no_std.md:29 +msgid "`panic!`, `assert_eq!`..." msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:6 -msgid "" -"SWD (Serial Wire Debug) and JTAG via CMSIS-DAP, ST-Link and J-Link probes" +#: src/bare-metal/no_std.md:30 +msgid "`NonNull` and all the usual pointer-related functions" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:7 -msgid "GDB stub and Microsoft DAP (Debug Adapter Protocol) server" +#: src/bare-metal/no_std.md:31 +msgid "`Future` and `async`/`await`" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:8 -msgid "Cargo integration" +#: src/bare-metal/no_std.md:32 +msgid "`fence`, `AtomicBool`, `AtomicPtr`, `AtomicU32`..." msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:10 -msgid "" -"`cargo-embed` is a cargo subcommand to build and flash binaries, log RTT " -"(Real Time Transfers) output and connect GDB. It's configured by an `Embed." -"toml` file in your project directory." +#: src/bare-metal/no_std.md:33 +msgid "`Duration`" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:16 -msgid "" -"[CMSIS-DAP](https://arm-software.github.io/CMSIS_5/DAP/html/index.html) is " -"an Arm standard protocol over USB for an in-circuit debugger to access the " -"CoreSight Debug Access Port of various Arm Cortex processors. It's what the " -"on-board debugger on the BBC micro:bit uses." +#: src/bare-metal/no_std.md:38 +msgid "`Box`, `Cow`, `Arc`, `Rc`" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:19 -msgid "" -"ST-Link is a range of in-circuit debuggers from ST Microelectronics, J-Link " -"is a range from SEGGER." +#: src/bare-metal/no_std.md:39 +msgid "`Vec`, `BinaryHeap`, `BtreeMap`, `LinkedList`, `VecDeque`" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:21 -msgid "" -"The Debug Access Port is usually either a 5-pin JTAG interface or 2-pin " -"Serial Wire Debug." +#: src/bare-metal/no_std.md:40 +msgid "`String`, `CString`, `format!`" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:22 -msgid "" -"probe-rs is a library which you can integrate into your own tools if you " -"want to." +#: src/bare-metal/no_std.md:45 +msgid "`Error`" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:23 -msgid "" -"The [Microsoft Debug Adapter Protocol](https://microsoft.github.io/debug-" -"adapter-protocol/) lets VSCode and other IDEs debug code running on any " -"supported microcontroller." +#: src/bare-metal/no_std.md:47 +msgid "`Mutex`, `Condvar`, `Barrier`, `Once`, `RwLock`, `mpsc`" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:25 -msgid "cargo-embed is a binary built using the probe-rs library." +#: src/bare-metal/no_std.md:48 +msgid "`File` and the rest of `fs`" msgstr "" -#: src/bare-metal/microcontrollers/probe-rs.md:26 -msgid "" -"RTT (Real Time Transfers) is a mechanism to transfer data between the debug " -"host and the target through a number of ringbuffers." +#: src/bare-metal/no_std.md:49 +msgid "`println!`, `Read`, `Write`, `Stdin`, `Stdout` and the rest of `io`" msgstr "" -#: src/bare-metal/microcontrollers/debugging.md:3 -msgid "_Embed.toml_:" +#: src/bare-metal/no_std.md:50 +msgid "`Path`, `OsString`" msgstr "" -#: src/bare-metal/microcontrollers/debugging.md:13 -msgid "In one terminal under `src/bare-metal/microcontrollers/examples/`:" +#: src/bare-metal/no_std.md:51 +msgid "`net`" msgstr "" -#: src/bare-metal/microcontrollers/debugging.md:19 -msgid "In another terminal in the same directory:" +#: src/bare-metal/no_std.md:52 +msgid "`Command`, `Child`, `ExitCode`" msgstr "" -#: src/bare-metal/microcontrollers/debugging.md:21 -msgid "On gLinux or Debian:" +#: src/bare-metal/no_std.md:53 +msgid "`spawn`, `sleep` and the rest of `thread`" msgstr "" -#: src/bare-metal/microcontrollers/debugging.md:34 -msgid "In GDB, try running:" +#: src/bare-metal/no_std.md:54 +msgid "`SystemTime`, `Instant`" msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:1 -#: src/bare-metal/aps/other-projects.md:1 -msgid "Other projects" +#: src/bare-metal/no_std.md:62 +msgid "`HashMap` depends on RNG." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:3 -msgid "[RTIC](https://rtic.rs/)" +#: src/bare-metal/no_std.md:63 +msgid "`std` re-exports the contents of both `core` and `alloc`." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:4 -msgid "\"Real-Time Interrupt-driven Concurrency\"" +#: src/bare-metal/minimal.md:1 +msgid "A minimal `no_std` program" msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:5 -msgid "" -"Shared resource management, message passing, task scheduling, timer queue" +#: src/bare-metal/minimal.md:17 +msgid "This will compile to an empty binary." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:6 -msgid "[Embassy](https://embassy.dev/)" +#: src/bare-metal/minimal.md:18 +msgid "`std` provides a panic handler; without it we must provide our own." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:7 -msgid "`async` executors with priorities, timers, networking, USB" +#: src/bare-metal/minimal.md:19 +msgid "It can also be provided by another crate, such as `panic-halt`." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:8 -msgid "[TockOS](https://www.tockos.org/documentation/getting-started)" +#: src/bare-metal/minimal.md:20 +msgid "" +"Depending on the target, you may need to compile with `panic = \"abort\"` to " +"avoid an error about `eh_personality`." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:9 +#: src/bare-metal/minimal.md:22 msgid "" -"Security-focused RTOS with preemptive scheduling and Memory Protection Unit " -"support" +"Note that there is no `main` or any other entry point; it's up to you to " +"define your own entry point. This will typically involve a linker script and " +"some assembly code to set things up ready for Rust code to run." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:10 -msgid "[Hubris](https://hubris.oxide.computer/)" +#: src/bare-metal/alloc.md:3 +msgid "" +"To use `alloc` you must implement a [global (heap) allocator](https://doc." +"rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html)." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:11 +#: src/bare-metal/alloc.md:23 msgid "" -"Microkernel RTOS from Oxide Computer Company with memory protection, " -"unprivileged drivers, IPC" +"// Safe because `HEAP` is only used here and `entry` is only called once.\n" msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:12 -msgid "[Bindings for FreeRTOS](https://github.com/lobaro/FreeRTOS-rust)" +#: src/bare-metal/alloc.md:25 +msgid "// Give the allocator some memory to allocate.\n" msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:13 -msgid "" -"Some platforms have `std` implementations, e.g. [esp-idf](https://esp-rs." -"github.io/book/overview/using-the-standard-library.html)." +#: src/bare-metal/alloc.md:31 +msgid "// Now we can do things that require heap allocation.\n" msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:18 -msgid "RTIC can be considered either an RTOS or a concurrency framework." -msgstr "" +#: src/bare-metal/alloc.md:33 +#, fuzzy +msgid "\"A string\"" +msgstr "String" -#: src/bare-metal/microcontrollers/other-projects.md:19 -msgid "It doesn't include any HALs." +#: src/bare-metal/alloc.md:39 +msgid "" +"`buddy_system_allocator` is a third-party crate implementing a basic buddy " +"system allocator. Other crates are available, or you can write your own or " +"hook into your existing allocator." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:20 +#: src/bare-metal/alloc.md:41 msgid "" -"It uses the Cortex-M NVIC (Nested Virtual Interrupt Controller) for " -"scheduling rather than a proper kernel." +"The const parameter of `LockedHeap` is the max order of the allocator; i.e. " +"in this case it can allocate regions of up to 2\\*\\*32 bytes." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:22 -msgid "Cortex-M only." +#: src/bare-metal/alloc.md:43 +msgid "" +"If any crate in your dependency tree depends on `alloc` then you must have " +"exactly one global allocator defined in your binary. Usually this is done in " +"the top-level binary crate." msgstr "" -#: src/bare-metal/microcontrollers/other-projects.md:23 +#: src/bare-metal/alloc.md:45 +msgid "" +"`extern crate panic_halt as _` is necessary to ensure that the `panic_halt` " +"crate is linked in so we get its panic handler." +msgstr "" + +#: src/bare-metal/alloc.md:47 +msgid "This example will build but not run, as it doesn't have an entry point." +msgstr "" + +#: src/bare-metal/microcontrollers.md:3 +msgid "" +"The `cortex_m_rt` crate provides (among other things) a reset handler for " +"Cortex M microcontrollers." +msgstr "" + +#: src/bare-metal/microcontrollers.md:21 +msgid "" +"Next we'll look at how to access peripherals, with increasing levels of " +"abstraction." +msgstr "" + +#: src/bare-metal/microcontrollers.md:25 +msgid "" +"The `cortex_m_rt::entry` macro requires that the function have type `fn() -" +"> !`, because returning to the reset handler doesn't make sense." +msgstr "" + +#: src/bare-metal/microcontrollers.md:27 +msgid "Run the example with `cargo embed --bin minimal`" +msgstr "" + +#: src/bare-metal/microcontrollers/mmio.md:3 +msgid "" +"Most microcontrollers access peripherals via memory-mapped IO. Let's try " +"turning on an LED on our micro:bit:" +msgstr "" + +#: src/bare-metal/microcontrollers/mmio.md:16 +msgid "/// GPIO port 0 peripheral address\n" +msgstr "" + +#: src/bare-metal/microcontrollers/mmio.md:19 +msgid "// GPIO peripheral offsets\n" +msgstr "" + +#: src/bare-metal/microcontrollers/mmio.md:24 +msgid "// PIN_CNF fields\n" +msgstr "" + +#: src/bare-metal/microcontrollers/mmio.md:34 +#: src/bare-metal/microcontrollers/pacs.md:21 +#: src/bare-metal/microcontrollers/hals.md:25 +msgid "// Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n" +msgstr "" + +#: src/bare-metal/microcontrollers/mmio.md:37 +#: src/bare-metal/microcontrollers/mmio.md:51 +msgid "" +"// Safe because the pointers are to valid peripheral control registers, and\n" +" // no aliases exist.\n" +msgstr "" + +#: src/bare-metal/microcontrollers/mmio.md:48 +#: src/bare-metal/microcontrollers/pacs.md:39 +#: src/bare-metal/microcontrollers/hals.md:29 +msgid "// Set pin 28 low and pin 21 high to turn the LED on.\n" +msgstr "" + +#: src/bare-metal/microcontrollers/mmio.md:64 +msgid "" +"GPIO 0 pin 21 is connected to the first column of the LED matrix, and pin 28 " +"to the first row." +msgstr "" + +#: src/bare-metal/microcontrollers/mmio.md:66 +#: src/bare-metal/microcontrollers/pacs.md:59 +#: src/bare-metal/microcontrollers/hals.md:43 +#: src/bare-metal/microcontrollers/board-support.md:34 +msgid "Run the example with:" +msgstr "" + +#: src/bare-metal/microcontrollers/pacs.md:1 +msgid "Peripheral Access Crates" +msgstr "" + +#: src/bare-metal/microcontrollers/pacs.md:3 +msgid "" +"[`svd2rust`](https://crates.io/crates/svd2rust) generates mostly-safe Rust " +"wrappers for memory-mapped peripherals from [CMSIS-SVD](https://www.keil.com/" +"pack/doc/CMSIS/SVD/html/index.html) files." +msgstr "" + +#: src/bare-metal/microcontrollers/pacs.md:49 +msgid "" +"SVD (System View Description) files are XML files typically provided by " +"silicon vendors which describe the memory map of the device." +msgstr "" + +#: src/bare-metal/microcontrollers/pacs.md:51 +msgid "" +"They are organised by peripheral, register, field and value, with names, " +"descriptions, addresses and so on." +msgstr "" + +#: src/bare-metal/microcontrollers/pacs.md:53 +msgid "" +"SVD files are often buggy and incomplete, so there are various projects " +"which patch the mistakes, add missing details, and publish the generated " +"crates." +msgstr "" + +#: src/bare-metal/microcontrollers/pacs.md:55 +msgid "`cortex-m-rt` provides the vector table, among other things." +msgstr "" + +#: src/bare-metal/microcontrollers/pacs.md:56 +msgid "" +"If you `cargo install cargo-binutils` then you can run `cargo objdump --bin " +"pac -- -d --no-show-raw-insn` to see the resulting binary." +msgstr "" + +#: src/bare-metal/microcontrollers/hals.md:1 +msgid "HAL crates" +msgstr "" + +#: src/bare-metal/microcontrollers/hals.md:3 +msgid "" +"[HAL crates](https://github.com/rust-embedded/awesome-embedded-rust#hal-" +"implementation-crates) for many microcontrollers provide wrappers around " +"various peripherals. These generally implement traits from [`embedded-hal`]" +"(https://crates.io/crates/embedded-hal)." +msgstr "" + +#: src/bare-metal/microcontrollers/hals.md:22 +msgid "// Create HAL wrapper for GPIO port 0.\n" +msgstr "" + +#: src/bare-metal/microcontrollers/hals.md:39 +msgid "" +"`set_low` and `set_high` are methods on the `embedded_hal` `OutputPin` trait." +msgstr "" + +#: src/bare-metal/microcontrollers/hals.md:40 +msgid "" +"HAL crates exist for many Cortex-M and RISC-V devices, including various " +"STM32, GD32, nRF, NXP, MSP430, AVR and PIC microcontrollers." +msgstr "" + +#: src/bare-metal/microcontrollers/board-support.md:1 +msgid "Board support crates" +msgstr "" + +#: src/bare-metal/microcontrollers/board-support.md:3 +msgid "" +"Board support crates provide a further level of wrapping for a specific " +"board for convenience." +msgstr "" + +#: src/bare-metal/microcontrollers/board-support.md:28 +msgid "" +"In this case the board support crate is just providing more useful names, " +"and a bit of initialisation." +msgstr "" + +#: src/bare-metal/microcontrollers/board-support.md:30 +msgid "" +"The crate may also include drivers for some on-board devices outside of the " +"microcontroller itself." +msgstr "" + +#: src/bare-metal/microcontrollers/board-support.md:32 +msgid "`microbit-v2` includes a simple driver for the LED matrix." +msgstr "" + +#: src/bare-metal/microcontrollers/type-state.md:1 +msgid "The type state pattern" +msgstr "" + +#: src/bare-metal/microcontrollers/type-state.md:11 +msgid "// let gpio0_01_again = gpio0.p0_01; // Error, moved.\n" +msgstr "" + +#: src/bare-metal/microcontrollers/type-state.md:14 +msgid "// ...\n" +msgstr "" + +#: src/bare-metal/microcontrollers/type-state.md:19 +msgid "// pin_input.is_high(); // Error, moved.\n" +msgstr "" + +#: src/bare-metal/microcontrollers/type-state.md:32 +msgid "" +"Pins don't implement `Copy` or `Clone`, so only one instance of each can " +"exist. Once a pin is moved out of the port struct nobody else can take it." +msgstr "" + +#: src/bare-metal/microcontrollers/type-state.md:34 +msgid "" +"Changing the configuration of a pin consumes the old pin instance, so you " +"can’t keep use the old instance afterwards." +msgstr "" + +#: src/bare-metal/microcontrollers/type-state.md:36 +msgid "" +"The type of a value indicates the state that it is in: e.g. in this case, " +"the configuration state of a GPIO pin. This encodes the state machine into " +"the type system, and ensures that you don't try to use a pin in a certain " +"way without properly configuring it first. Illegal state transitions are " +"caught at compile time." +msgstr "" + +#: src/bare-metal/microcontrollers/type-state.md:40 +msgid "" +"You can call `is_high` on an input pin and `set_high` on an output pin, but " +"not vice-versa." +msgstr "" + +#: src/bare-metal/microcontrollers/type-state.md:41 +msgid "Many HAL crates follow this pattern." +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:1 +msgid "`embedded-hal`" +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:3 +msgid "" +"The [`embedded-hal`](https://crates.io/crates/embedded-hal) crate provides a " +"number of traits covering common microcontroller peripherals." +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:6 +msgid "GPIO" +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:7 +msgid "ADC" +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:8 +msgid "I2C, SPI, UART, CAN" +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:9 +msgid "RNG" +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:10 +msgid "Timers" +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:11 +msgid "Watchdogs" +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:13 +msgid "" +"Other crates then implement [drivers](https://github.com/rust-embedded/" +"awesome-embedded-rust#driver-crates) in terms of these traits, e.g. an " +"accelerometer driver might need an I2C or SPI bus implementation." +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:19 +msgid "" +"There are implementations for many microcontrollers, as well as other " +"platforms such as Linux on Raspberry Pi." +msgstr "" + +#: src/bare-metal/microcontrollers/embedded-hal.md:21 +msgid "" +"There is work in progress on an `async` version of `embedded-hal`, but it " +"isn't stable yet." +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:1 +msgid "`probe-rs`, `cargo-embed`" +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:3 +msgid "" +"[probe-rs](https://probe.rs/) is a handy toolset for embedded debugging, " +"like OpenOCD but better integrated." +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:6 +msgid "" +"SWD (Serial Wire Debug) and JTAG via CMSIS-DAP, ST-Link and J-Link probes" +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:7 +msgid "GDB stub and Microsoft DAP (Debug Adapter Protocol) server" +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:8 +msgid "Cargo integration" +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:10 +msgid "" +"`cargo-embed` is a cargo subcommand to build and flash binaries, log RTT " +"(Real Time Transfers) output and connect GDB. It's configured by an `Embed." +"toml` file in your project directory." +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:16 +msgid "" +"[CMSIS-DAP](https://arm-software.github.io/CMSIS_5/DAP/html/index.html) is " +"an Arm standard protocol over USB for an in-circuit debugger to access the " +"CoreSight Debug Access Port of various Arm Cortex processors. It's what the " +"on-board debugger on the BBC micro:bit uses." +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:19 +msgid "" +"ST-Link is a range of in-circuit debuggers from ST Microelectronics, J-Link " +"is a range from SEGGER." +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:21 +msgid "" +"The Debug Access Port is usually either a 5-pin JTAG interface or 2-pin " +"Serial Wire Debug." +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:22 +msgid "" +"probe-rs is a library which you can integrate into your own tools if you " +"want to." +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:23 +msgid "" +"The [Microsoft Debug Adapter Protocol](https://microsoft.github.io/debug-" +"adapter-protocol/) lets VSCode and other IDEs debug code running on any " +"supported microcontroller." +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:25 +msgid "cargo-embed is a binary built using the probe-rs library." +msgstr "" + +#: src/bare-metal/microcontrollers/probe-rs.md:26 +msgid "" +"RTT (Real Time Transfers) is a mechanism to transfer data between the debug " +"host and the target through a number of ringbuffers." +msgstr "" + +#: src/bare-metal/microcontrollers/debugging.md:3 +msgid "_Embed.toml_:" +msgstr "" + +#: src/bare-metal/microcontrollers/debugging.md:13 +msgid "In one terminal under `src/bare-metal/microcontrollers/examples/`:" +msgstr "" + +#: src/bare-metal/microcontrollers/debugging.md:19 +msgid "In another terminal in the same directory:" +msgstr "" + +#: src/bare-metal/microcontrollers/debugging.md:21 +msgid "On gLinux or Debian:" +msgstr "" + +#: src/bare-metal/microcontrollers/debugging.md:34 +msgid "In GDB, try running:" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:1 +#: src/bare-metal/aps/other-projects.md:1 +msgid "Other projects" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:3 +msgid "[RTIC](https://rtic.rs/)" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:4 +msgid "\"Real-Time Interrupt-driven Concurrency\"" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:5 +msgid "" +"Shared resource management, message passing, task scheduling, timer queue" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:6 +msgid "[Embassy](https://embassy.dev/)" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:7 +msgid "`async` executors with priorities, timers, networking, USB" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:8 +msgid "[TockOS](https://www.tockos.org/documentation/getting-started)" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:9 +msgid "" +"Security-focused RTOS with preemptive scheduling and Memory Protection Unit " +"support" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:10 +msgid "[Hubris](https://hubris.oxide.computer/)" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:11 +msgid "" +"Microkernel RTOS from Oxide Computer Company with memory protection, " +"unprivileged drivers, IPC" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:12 +msgid "[Bindings for FreeRTOS](https://github.com/lobaro/FreeRTOS-rust)" +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:13 +msgid "" +"Some platforms have `std` implementations, e.g. [esp-idf](https://esp-rs." +"github.io/book/overview/using-the-standard-library.html)." +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:18 +msgid "RTIC can be considered either an RTOS or a concurrency framework." +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:19 +msgid "It doesn't include any HALs." +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:20 +msgid "" +"It uses the Cortex-M NVIC (Nested Virtual Interrupt Controller) for " +"scheduling rather than a proper kernel." +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:22 +msgid "Cortex-M only." +msgstr "" + +#: src/bare-metal/microcontrollers/other-projects.md:23 msgid "" "Google uses TockOS on the Haven microcontroller for Titan security keys." msgstr "" @@ -12756,41 +11923,27 @@ msgstr "" msgid "_src/main.rs_:" msgstr "" -#: src/exercises/bare-metal/compass.md:30 -msgid "" -"```rust,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"extern crate panic_halt as _;\n" -"\n" -"use core::fmt::Write;\n" -"use cortex_m_rt::entry;\n" -"use microbit::{hal::uarte::{Baudrate, Parity, Uarte}, Board};\n" -"\n" -"#[entry]\n" -"fn main() -> ! {\n" -" let board = Board::take().unwrap();\n" -"\n" -" // Configure serial port.\n" -" let mut serial = Uarte::new(\n" -" board.UARTE0,\n" -" board.uart.into(),\n" -" Parity::EXCLUDED,\n" -" Baudrate::BAUD115200,\n" -" );\n" -"\n" -" // Set up the I2C controller and Inertial Measurement Unit.\n" -" // TODO\n" -"\n" -" writeln!(serial, \"Ready.\").unwrap();\n" -"\n" -" loop {\n" -" // Read compass data and log it to the serial port.\n" -" // TODO\n" -" }\n" -"}\n" -"```" +#: src/exercises/bare-metal/compass.md:44 +#: src/exercises/bare-metal/solutions-morning.md:32 +msgid "// Configure serial port.\n" +msgstr "" + +#: src/exercises/bare-metal/compass.md:52 +msgid "// Set up the I2C controller and Inertial Measurement Unit." +msgstr "" + +#: src/exercises/bare-metal/compass.md:53 +#: src/exercises/bare-metal/compass.md:59 +msgid "// TODO" +msgstr "" + +#: src/exercises/bare-metal/compass.md:55 +#: src/exercises/bare-metal/solutions-morning.md:56 +msgid "\"Ready.\"" +msgstr "" + +#: src/exercises/bare-metal/compass.md:58 +msgid "// Read compass data and log it to the serial port." msgstr "" #: src/exercises/bare-metal/compass.md:64 src/exercises/bare-metal/rtc.md:385 @@ -13003,40 +12156,46 @@ msgid "" "firmware to power off the system:" msgstr "" -#: src/bare-metal/aps/inline-assembly.md:6 +#: src/bare-metal/aps/inline-assembly.md:19 msgid "" -"```rust,editable,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"use core::arch::asm;\n" -"use core::panic::PanicInfo;\n" -"\n" -"mod exceptions;\n" -"\n" -"const PSCI_SYSTEM_OFF: u32 = 0x84000008;\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn main(_x0: u64, _x1: u64, _x2: u64, _x3: u64) {\n" -" // Safe because this only uses the declared registers and doesn't do\n" +"// Safe because this only uses the declared registers and doesn't do\n" " // anything with memory.\n" -" unsafe {\n" -" asm!(\"hvc #0\",\n" -" inout(\"w0\") PSCI_SYSTEM_OFF => _,\n" -" inout(\"w1\") 0 => _,\n" -" inout(\"w2\") 0 => _,\n" -" inout(\"w3\") 0 => _,\n" -" inout(\"w4\") 0 => _,\n" -" inout(\"w5\") 0 => _,\n" -" inout(\"w6\") 0 => _,\n" -" inout(\"w7\") 0 => _,\n" -" options(nomem, nostack)\n" -" );\n" -" }\n" -"\n" -" loop {}\n" -"}\n" -"```" +msgstr "" + +#: src/bare-metal/aps/inline-assembly.md:22 +msgid "\"hvc #0\"" +msgstr "" + +#: src/bare-metal/aps/inline-assembly.md:23 +msgid "\"w0\"" +msgstr "" + +#: src/bare-metal/aps/inline-assembly.md:24 +msgid "\"w1\"" +msgstr "" + +#: src/bare-metal/aps/inline-assembly.md:25 +msgid "\"w2\"" +msgstr "" + +#: src/bare-metal/aps/inline-assembly.md:26 +msgid "\"w3\"" +msgstr "" + +#: src/bare-metal/aps/inline-assembly.md:27 +msgid "\"w4\"" +msgstr "" + +#: src/bare-metal/aps/inline-assembly.md:28 +msgid "\"w5\"" +msgstr "" + +#: src/bare-metal/aps/inline-assembly.md:29 +msgid "\"w6\"" +msgstr "" + +#: src/bare-metal/aps/inline-assembly.md:30 +msgid "\"w7\"" msgstr "" #: src/bare-metal/aps/inline-assembly.md:39 @@ -13136,22 +12295,13 @@ msgid "" "documentation/ddi0183/g) UART, so let's write a driver for that." msgstr "" -#: src/bare-metal/aps/uart.md:5 +#: src/bare-metal/aps/uart.md:9 +msgid "/// Minimal driver for a PL011 UART.\n" +msgstr "" + +#: src/bare-metal/aps/uart.md:17 src/bare-metal/aps/better-uart/driver.md:13 msgid "" -"```rust,editable\n" -"const FLAG_REGISTER_OFFSET: usize = 0x18;\n" -"const FR_BUSY: u8 = 1 << 3;\n" -"const FR_TXFF: u8 = 1 << 5;\n" -"\n" -"/// Minimal driver for a PL011 UART.\n" -"#[derive(Debug)]\n" -"pub struct Uart {\n" -" base_address: *mut u8,\n" -"}\n" -"\n" -"impl Uart {\n" -" /// Constructs a new instance of the UART driver for a PL011 device at " -"the\n" +"/// Constructs a new instance of the UART driver for a PL011 device at the\n" " /// given base address.\n" " ///\n" " /// # Safety\n" @@ -13161,34 +12311,32 @@ msgid "" " /// PL011 device, which must be mapped into the address space of the " "process\n" " /// as device memory and not have any other aliases.\n" -" pub unsafe fn new(base_address: *mut u8) -> Self {\n" -" Self { base_address }\n" -" }\n" -"\n" -" /// Writes a single byte to the UART.\n" -" pub fn write_byte(&self, byte: u8) {\n" -" // Wait until there is room in the TX buffer.\n" -" while self.read_flag_register() & FR_TXFF != 0 {}\n" -"\n" -" // Safe because we know that the base address points to the control\n" -" // registers of a PL011 device which is appropriately mapped.\n" -" unsafe {\n" -" // Write to the TX buffer.\n" -" self.base_address.write_volatile(byte);\n" -" }\n" -"\n" -" // Wait until the UART is no longer busy.\n" -" while self.read_flag_register() & FR_BUSY != 0 {}\n" -" }\n" -"\n" -" fn read_flag_register(&self) -> u8 {\n" -" // Safe because we know that the base address points to the control\n" +msgstr "" + +#: src/bare-metal/aps/uart.md:29 src/bare-metal/aps/better-uart/driver.md:27 +#: src/exercises/bare-metal/rtc.md:336 +msgid "/// Writes a single byte to the UART.\n" +msgstr "" + +#: src/bare-metal/aps/uart.md:31 src/bare-metal/aps/better-uart/driver.md:29 +#: src/exercises/bare-metal/rtc.md:338 +msgid "// Wait until there is room in the TX buffer.\n" +msgstr "" + +#: src/bare-metal/aps/uart.md:34 src/bare-metal/aps/uart.md:46 +msgid "" +"// Safe because we know that the base address points to the control\n" " // registers of a PL011 device which is appropriately mapped.\n" -" unsafe { self.base_address.add(FLAG_REGISTER_OFFSET)." -"read_volatile() }\n" -" }\n" -"}\n" -"```" +msgstr "" + +#: src/bare-metal/aps/uart.md:37 src/bare-metal/aps/better-uart/driver.md:35 +#: src/exercises/bare-metal/rtc.md:344 +msgid "// Write to the TX buffer.\n" +msgstr "" + +#: src/bare-metal/aps/uart.md:41 src/bare-metal/aps/better-uart/driver.md:39 +#: src/exercises/bare-metal/rtc.md:348 +msgid "// Wait until the UART is no longer busy.\n" msgstr "" #: src/bare-metal/aps/uart.md:55 @@ -13225,24 +12373,11 @@ msgid "" "traits too." msgstr "" -#: src/bare-metal/aps/uart/traits.md:5 +#: src/bare-metal/aps/uart/traits.md:16 src/exercises/bare-metal/rtc.md:379 +#: src/exercises/bare-metal/solutions-afternoon.md:231 msgid "" -"```rust,editable,compile_fail\n" -"use core::fmt::{self, Write};\n" -"\n" -"impl Write for Uart {\n" -" fn write_str(&mut self, s: &str) -> fmt::Result {\n" -" for c in s.as_bytes() {\n" -" self.write_byte(*c);\n" -" }\n" -" Ok(())\n" -" }\n" -"}\n" -"\n" "// Safe because it just contains a pointer to device memory, which can be\n" "// accessed from any context.\n" -"unsafe impl Send for Uart {}\n" -"```" msgstr "" #: src/bare-metal/aps/uart/traits.md:24 @@ -13437,37 +12572,54 @@ msgid "" "working with bitflags." msgstr "" -#: src/bare-metal/aps/better-uart/bitflags.md:5 -msgid "" -"```rust,editable,compile_fail\n" -"use bitflags::bitflags;\n" -"\n" -"bitflags! {\n" -" /// Flags from the UART flag register.\n" -" #[repr(transparent)]\n" -" #[derive(Copy, Clone, Debug, Eq, PartialEq)]\n" -" struct Flags: u16 {\n" -" /// Clear to send.\n" -" const CTS = 1 << 0;\n" -" /// Data set ready.\n" -" const DSR = 1 << 1;\n" -" /// Data carrier detect.\n" -" const DCD = 1 << 2;\n" -" /// UART busy transmitting data.\n" -" const BUSY = 1 << 3;\n" -" /// Receive FIFO is empty.\n" -" const RXFE = 1 << 4;\n" -" /// Transmit FIFO is full.\n" -" const TXFF = 1 << 5;\n" -" /// Receive FIFO is full.\n" -" const RXFF = 1 << 6;\n" -" /// Transmit FIFO is empty.\n" -" const TXFE = 1 << 7;\n" -" /// Ring indicator.\n" -" const RI = 1 << 8;\n" -" }\n" -"}\n" -"```" +#: src/bare-metal/aps/better-uart/bitflags.md:9 +#: src/exercises/bare-metal/rtc.md:238 +msgid "/// Flags from the UART flag register.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/bitflags.md:13 +#: src/exercises/bare-metal/rtc.md:242 +msgid "/// Clear to send.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/bitflags.md:15 +#: src/exercises/bare-metal/rtc.md:244 +msgid "/// Data set ready.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/bitflags.md:17 +#: src/exercises/bare-metal/rtc.md:246 +msgid "/// Data carrier detect.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/bitflags.md:19 +#: src/exercises/bare-metal/rtc.md:248 +msgid "/// UART busy transmitting data.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/bitflags.md:21 +#: src/exercises/bare-metal/rtc.md:250 +msgid "/// Receive FIFO is empty.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/bitflags.md:23 +#: src/exercises/bare-metal/rtc.md:252 +msgid "/// Transmit FIFO is full.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/bitflags.md:25 +#: src/exercises/bare-metal/rtc.md:254 +msgid "/// Receive FIFO is full.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/bitflags.md:27 +#: src/exercises/bare-metal/rtc.md:256 +msgid "/// Transmit FIFO is empty.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/bitflags.md:29 +#: src/exercises/bare-metal/rtc.md:258 +msgid "/// Ring indicator.\n" msgstr "" #: src/bare-metal/aps/better-uart/bitflags.md:37 @@ -13497,70 +12649,29 @@ msgstr "" #: src/bare-metal/aps/better-uart/driver.md:3 msgid "Now let's use the new `Registers` struct in our driver." msgstr "" - -#: src/bare-metal/aps/better-uart/driver.md:5 -msgid "" -"```rust,editable,compile_fail\n" -"/// Driver for a PL011 UART.\n" -"#[derive(Debug)]\n" -"pub struct Uart {\n" -" registers: *mut Registers,\n" -"}\n" -"\n" -"impl Uart {\n" -" /// Constructs a new instance of the UART driver for a PL011 device at " -"the\n" -" /// given base address.\n" -" ///\n" -" /// # Safety\n" -" ///\n" -" /// The given base address must point to the 8 MMIO control registers of " -"a\n" -" /// PL011 device, which must be mapped into the address space of the " -"process\n" -" /// as device memory and not have any other aliases.\n" -" pub unsafe fn new(base_address: *mut u32) -> Self {\n" -" Self {\n" -" registers: base_address as *mut Registers,\n" -" }\n" -" }\n" -"\n" -" /// Writes a single byte to the UART.\n" -" pub fn write_byte(&self, byte: u8) {\n" -" // Wait until there is room in the TX buffer.\n" -" while self.read_flag_register().contains(Flags::TXFF) {}\n" -"\n" -" // Safe because we know that self.registers points to the control\n" + +#: src/bare-metal/aps/better-uart/driver.md:6 +msgid "/// Driver for a PL011 UART.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/driver.md:32 +#: src/bare-metal/aps/better-uart/driver.md:55 +#: src/exercises/bare-metal/rtc.md:341 src/exercises/bare-metal/rtc.md:364 +msgid "" +"// Safe because we know that self.registers points to the control\n" " // registers of a PL011 device which is appropriately mapped.\n" -" unsafe {\n" -" // Write to the TX buffer.\n" -" addr_of_mut!((*self.registers).dr).write_volatile(byte.into());\n" -" }\n" -"\n" -" // Wait until the UART is no longer busy.\n" -" while self.read_flag_register().contains(Flags::BUSY) {}\n" -" }\n" -"\n" -" /// Reads and returns a pending byte, or `None` if nothing has been " +msgstr "" + +#: src/bare-metal/aps/better-uart/driver.md:43 +#: src/exercises/bare-metal/rtc.md:352 +msgid "" +"/// Reads and returns a pending byte, or `None` if nothing has been " "received.\n" -" pub fn read_byte(&self) -> Option {\n" -" if self.read_flag_register().contains(Flags::RXFE) {\n" -" None\n" -" } else {\n" -" let data = unsafe { addr_of!((*self.registers).dr)." -"read_volatile() };\n" -" // TODO: Check for error conditions in bits 8-11.\n" -" Some(data as u8)\n" -" }\n" -" }\n" -"\n" -" fn read_flag_register(&self) -> Flags {\n" -" // Safe because we know that self.registers points to the control\n" -" // registers of a PL011 device which is appropriately mapped.\n" -" unsafe { addr_of!((*self.registers).fr).read_volatile() }\n" -" }\n" -"}\n" -"```" +msgstr "" + +#: src/bare-metal/aps/better-uart/driver.md:49 +#: src/exercises/bare-metal/rtc.md:358 +msgid "// TODO: Check for error conditions in bits 8-11.\n" msgstr "" #: src/bare-metal/aps/better-uart/driver.md:64 @@ -13580,51 +12691,40 @@ msgid "" "and echo incoming bytes." msgstr "" -#: src/bare-metal/aps/better-uart/using.md:6 +#: src/bare-metal/aps/better-uart/using.md:19 +#: src/bare-metal/aps/logging/using.md:18 src/exercises/bare-metal/rtc.md:41 +#: src/exercises/bare-metal/solutions-afternoon.md:33 +msgid "/// Base address of the primary PL011 UART.\n" +msgstr "" + +#: src/bare-metal/aps/better-uart/using.md:25 +#: src/bare-metal/aps/logging/using.md:24 src/exercises/bare-metal/rtc.md:47 +#: src/exercises/bare-metal/solutions-afternoon.md:44 msgid "" -"```rust,editable,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"mod exceptions;\n" -"mod pl011;\n" -"\n" -"use crate::pl011::Uart;\n" -"use core::fmt::Write;\n" -"use core::panic::PanicInfo;\n" -"use log::error;\n" -"use smccc::psci::system_off;\n" -"use smccc::Hvc;\n" -"\n" -"/// Base address of the primary PL011 UART.\n" -"const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {\n" -" // Safe because `PL011_BASE_ADDRESS` is the base address of a PL011 " -"device,\n" +"// Safe because `PL011_BASE_ADDRESS` is the base address of a PL011 device,\n" " // and nothing else accesses that address range.\n" -" let mut uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };\n" -"\n" -" writeln!(uart, \"main({x0:#x}, {x1:#x}, {x2:#x}, {x3:#x})\").unwrap();\n" -"\n" -" loop {\n" -" if let Some(byte) = uart.read_byte() {\n" -" uart.write_byte(byte);\n" -" match byte {\n" -" b'\\r' => {\n" -" uart.write_byte(b'\\n');\n" -" }\n" -" b'q' => break,\n" -" _ => {}\n" -" }\n" -" }\n" -" }\n" -"\n" -" writeln!(uart, \"Bye!\").unwrap();\n" -" system_off::().unwrap();\n" -"}\n" -"```" +msgstr "" + +#: src/bare-metal/aps/better-uart/using.md:29 +#: src/bare-metal/aps/logging/using.md:29 +msgid "\"main({x0:#x}, {x1:#x}, {x2:#x}, {x3:#x})\"" +msgstr "" + +#: src/bare-metal/aps/better-uart/using.md:35 +msgid "b'\\r'" +msgstr "" + +#: src/bare-metal/aps/better-uart/using.md:36 +#: src/async/pitfalls/cancellation.md:27 +msgid "b'\\n'" +msgstr "" + +#: src/bare-metal/aps/better-uart/using.md:38 +msgid "b'q'" +msgstr "" + +#: src/bare-metal/aps/better-uart/using.md:44 +msgid "\"Bye!\"" msgstr "" #: src/bare-metal/aps/better-uart/using.md:51 @@ -13646,50 +12746,12 @@ msgid "" "`Log` trait." msgstr "" -#: src/bare-metal/aps/logging.md:6 -msgid "" -"```rust,editable,compile_fail\n" -"use crate::pl011::Uart;\n" -"use core::fmt::Write;\n" -"use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};\n" -"use spin::mutex::SpinMutex;\n" -"\n" -"static LOGGER: Logger = Logger {\n" -" uart: SpinMutex::new(None),\n" -"};\n" -"\n" -"struct Logger {\n" -" uart: SpinMutex>,\n" -"}\n" -"\n" -"impl Log for Logger {\n" -" fn enabled(&self, _metadata: &Metadata) -> bool {\n" -" true\n" -" }\n" -"\n" -" fn log(&self, record: &Record) {\n" -" writeln!(\n" -" self.uart.lock().as_mut().unwrap(),\n" -" \"[{}] {}\",\n" -" record.level(),\n" -" record.args()\n" -" )\n" -" .unwrap();\n" -" }\n" -"\n" -" fn flush(&self) {}\n" -"}\n" -"\n" -"/// Initialises UART logger.\n" -"pub fn init(uart: Uart, max_level: LevelFilter) -> Result<(), " -"SetLoggerError> {\n" -" LOGGER.uart.lock().replace(uart);\n" -"\n" -" log::set_logger(&LOGGER)?;\n" -" log::set_max_level(max_level);\n" -" Ok(())\n" -"}\n" -"```" +#: src/bare-metal/aps/logging.md:28 src/exercises/bare-metal/rtc.md:190 +msgid "\"[{}] {}\"" +msgstr "" + +#: src/bare-metal/aps/logging.md:37 src/exercises/bare-metal/rtc.md:199 +msgid "/// Initialises UART logger.\n" msgstr "" #: src/bare-metal/aps/logging.md:50 @@ -13702,47 +12764,9 @@ msgstr "" msgid "We need to initialise the logger before we use it." msgstr "" -#: src/bare-metal/aps/logging/using.md:5 -msgid "" -"```rust,editable,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"mod exceptions;\n" -"mod logger;\n" -"mod pl011;\n" -"\n" -"use crate::pl011::Uart;\n" -"use core::panic::PanicInfo;\n" -"use log::{error, info, LevelFilter};\n" -"use smccc::psci::system_off;\n" -"use smccc::Hvc;\n" -"\n" -"/// Base address of the primary PL011 UART.\n" -"const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {\n" -" // Safe because `PL011_BASE_ADDRESS` is the base address of a PL011 " -"device,\n" -" // and nothing else accesses that address range.\n" -" let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };\n" -" logger::init(uart, LevelFilter::Trace).unwrap();\n" -"\n" -" info!(\"main({x0:#x}, {x1:#x}, {x2:#x}, {x3:#x})\");\n" -"\n" -" assert_eq!(x1, 42);\n" -"\n" -" system_off::().unwrap();\n" -"}\n" -"\n" -"#[panic_handler]\n" -"fn panic(info: &PanicInfo) -> ! {\n" -" error!(\"{info}\");\n" -" system_off::().unwrap();\n" -" loop {}\n" -"}\n" -"```" +#: src/bare-metal/aps/logging/using.md:38 src/exercises/bare-metal/rtc.md:69 +#: src/exercises/bare-metal/solutions-afternoon.md:121 +msgid "\"{info}\"" msgstr "" #: src/bare-metal/aps/logging/using.md:46 @@ -13917,27 +12941,16 @@ msgid "" "Architecture." msgstr "" -#: src/bare-metal/useful-crates/aarch64-paging.md:6 -msgid "" -"```rust,editable,compile_fail\n" -"use aarch64_paging::{\n" -" idmap::IdMap,\n" -" paging::{Attributes, MemoryRegion},\n" -"};\n" -"\n" -"const ASID: usize = 1;\n" -"const ROOT_LEVEL: usize = 1;\n" -"\n" -"// Create a new page table with identity mapping.\n" -"let mut idmap = IdMap::new(ASID, ROOT_LEVEL);\n" -"// Map a 2 MiB region of memory as read-only.\n" -"idmap.map_range(\n" -" &MemoryRegion::new(0x80200000, 0x80400000),\n" -" Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::READ_ONLY,\n" -").unwrap();\n" -"// Set `TTBR0_EL1` to activate the page table.\n" -"idmap.activate();\n" -"```" +#: src/bare-metal/useful-crates/aarch64-paging.md:14 +msgid "// Create a new page table with identity mapping." +msgstr "" + +#: src/bare-metal/useful-crates/aarch64-paging.md:16 +msgid "// Map a 2 MiB region of memory as read-only." +msgstr "" + +#: src/bare-metal/useful-crates/aarch64-paging.md:21 +msgid "// Set `TTBR0_EL1` to activate the page table." msgstr "" #: src/bare-metal/useful-crates/aarch64-paging.md:28 @@ -14129,62 +13142,30 @@ msgid "" "look in the `rtc` directory for the following files." msgstr "" -#: src/exercises/bare-metal/rtc.md:23 +#: src/exercises/bare-metal/rtc.md:37 +#: src/exercises/bare-metal/solutions-afternoon.md:29 +msgid "/// Base addresses of the GICv3.\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:52 +#: src/exercises/bare-metal/solutions-afternoon.md:49 +msgid "\"main({:#x}, {:#x}, {:#x}, {:#x})\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:54 +#: src/exercises/bare-metal/solutions-afternoon.md:51 msgid "" -"```rust,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"mod exceptions;\n" -"mod logger;\n" -"mod pl011;\n" -"\n" -"use crate::pl011::Uart;\n" -"use arm_gic::gicv3::GicV3;\n" -"use core::panic::PanicInfo;\n" -"use log::{error, info, trace, LevelFilter};\n" -"use smccc::psci::system_off;\n" -"use smccc::Hvc;\n" -"\n" -"/// Base addresses of the GICv3.\n" -"const GICD_BASE_ADDRESS: *mut u64 = 0x800_0000 as _;\n" -"const GICR_BASE_ADDRESS: *mut u64 = 0x80A_0000 as _;\n" -"\n" -"/// Base address of the primary PL011 UART.\n" -"const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {\n" -" // Safe because `PL011_BASE_ADDRESS` is the base address of a PL011 " -"device,\n" -" // and nothing else accesses that address range.\n" -" let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };\n" -" logger::init(uart, LevelFilter::Trace).unwrap();\n" -"\n" -" info!(\"main({:#x}, {:#x}, {:#x}, {:#x})\", x0, x1, x2, x3);\n" -"\n" -" // Safe because `GICD_BASE_ADDRESS` and `GICR_BASE_ADDRESS` are the " -"base\n" +"// Safe because `GICD_BASE_ADDRESS` and `GICR_BASE_ADDRESS` are the base\n" " // addresses of a GICv3 distributor and redistributor respectively, and\n" " // nothing else accesses those address ranges.\n" -" let mut gic = unsafe { GicV3::new(GICD_BASE_ADDRESS, " -"GICR_BASE_ADDRESS) };\n" -" gic.setup();\n" -"\n" -" // TODO: Create instance of RTC driver and print current time.\n" -"\n" -" // TODO: Wait for 3 seconds.\n" -"\n" -" system_off::().unwrap();\n" -"}\n" -"\n" -"#[panic_handler]\n" -"fn panic(info: &PanicInfo) -> ! {\n" -" error!(\"{info}\");\n" -" system_off::().unwrap();\n" -" loop {}\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:60 +msgid "// TODO: Create instance of RTC driver and print current time." +msgstr "" + +#: src/exercises/bare-metal/rtc.md:62 +msgid "// TODO: Wait for 3 seconds." msgstr "" #: src/exercises/bare-metal/rtc.md:75 @@ -14193,9 +13174,9 @@ msgid "" "the exercise):" msgstr "" -#: src/exercises/bare-metal/rtc.md:79 +#: src/exercises/bare-metal/rtc.md:80 src/exercises/bare-metal/rtc.md:154 +#: src/exercises/bare-metal/rtc.md:215 src/exercises/bare-metal/rtc.md:415 msgid "" -"```rust,compile_fail\n" "// Copyright 2023 Google LLC\n" "//\n" "// Licensed under the Apache License, Version 2.0 (the \"License\");\n" @@ -14209,245 +13190,106 @@ msgid "" "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" "// See the License for the specific language governing permissions and\n" "// limitations under the License.\n" -"\n" -"use arm_gic::gicv3::GicV3;\n" -"use log::{error, info, trace};\n" -"use smccc::psci::system_off;\n" -"use smccc::Hvc;\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn sync_exception_current(_elr: u64, _spsr: u64) {\n" -" error!(\"sync_exception_current\");\n" -" system_off::().unwrap();\n" -"}\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn irq_current(_elr: u64, _spsr: u64) {\n" -" trace!(\"irq_current\");\n" -" let intid = GicV3::get_and_acknowledge_interrupt().expect(\"No pending " -"interrupt\");\n" -" info!(\"IRQ {intid:?}\");\n" -"}\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn fiq_current(_elr: u64, _spsr: u64) {\n" -" error!(\"fiq_current\");\n" -" system_off::().unwrap();\n" -"}\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn serr_current(_elr: u64, _spsr: u64) {\n" -" error!(\"serr_current\");\n" -" system_off::().unwrap();\n" -"}\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn sync_lower(_elr: u64, _spsr: u64) {\n" -" error!(\"sync_lower\");\n" -" system_off::().unwrap();\n" -"}\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn irq_lower(_elr: u64, _spsr: u64) {\n" -" error!(\"irq_lower\");\n" -" system_off::().unwrap();\n" -"}\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn fiq_lower(_elr: u64, _spsr: u64) {\n" -" error!(\"fiq_lower\");\n" -" system_off::().unwrap();\n" -"}\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn serr_lower(_elr: u64, _spsr: u64) {\n" -" error!(\"serr_lower\");\n" -" system_off::().unwrap();\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:101 +msgid "\"sync_exception_current\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:107 +msgid "\"irq_current\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:108 +msgid "\"No pending interrupt\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:109 +msgid "\"IRQ {intid:?}\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:114 +msgid "\"fiq_current\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:120 +msgid "\"serr_current\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:126 +msgid "\"sync_lower\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:132 +msgid "\"irq_lower\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:138 +msgid "\"fiq_lower\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:144 +msgid "\"serr_lower\"" msgstr "" #: src/exercises/bare-metal/rtc.md:149 msgid "_src/logger.rs_ (you shouldn't need to change this):" msgstr "" -#: src/exercises/bare-metal/rtc.md:153 -msgid "" -"```rust,compile_fail\n" -"// Copyright 2023 Google LLC\n" -"//\n" -"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" -"// you may not use this file except in compliance with the License.\n" -"// You may obtain a copy of the License at\n" -"//\n" -"// http://www.apache.org/licenses/LICENSE-2.0\n" -"//\n" -"// Unless required by applicable law or agreed to in writing, software\n" -"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" -"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" -"// See the License for the specific language governing permissions and\n" -"// limitations under the License.\n" -"\n" -"// ANCHOR: main\n" -"use crate::pl011::Uart;\n" -"use core::fmt::Write;\n" -"use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};\n" -"use spin::mutex::SpinMutex;\n" -"\n" -"static LOGGER: Logger = Logger {\n" -" uart: SpinMutex::new(None),\n" -"};\n" -"\n" -"struct Logger {\n" -" uart: SpinMutex>,\n" -"}\n" -"\n" -"impl Log for Logger {\n" -" fn enabled(&self, _metadata: &Metadata) -> bool {\n" -" true\n" -" }\n" -"\n" -" fn log(&self, record: &Record) {\n" -" writeln!(\n" -" self.uart.lock().as_mut().unwrap(),\n" -" \"[{}] {}\",\n" -" record.level(),\n" -" record.args()\n" -" )\n" -" .unwrap();\n" -" }\n" -"\n" -" fn flush(&self) {}\n" -"}\n" -"\n" -"/// Initialises UART logger.\n" -"pub fn init(uart: Uart, max_level: LevelFilter) -> Result<(), " -"SetLoggerError> {\n" -" LOGGER.uart.lock().replace(uart);\n" -"\n" -" log::set_logger(&LOGGER)?;\n" -" log::set_max_level(max_level);\n" -" Ok(())\n" -"}\n" -"```" +#: src/exercises/bare-metal/rtc.md:167 +msgid "// ANCHOR: main\n" msgstr "" #: src/exercises/bare-metal/rtc.md:210 msgid "_src/pl011.rs_ (you shouldn't need to change this):" msgstr "" -#: src/exercises/bare-metal/rtc.md:214 +#: src/exercises/bare-metal/rtc.md:233 +msgid "// ANCHOR: Flags\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:261 +msgid "// ANCHOR_END: Flags\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:265 +msgid "" +"/// Flags from the UART Receive Status Register / Error Clear Register.\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:269 +msgid "/// Framing error.\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:271 +msgid "/// Parity error.\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:273 +msgid "/// Break error.\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:275 +msgid "/// Overrun error.\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:279 +msgid "// ANCHOR: Registers\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:311 +msgid "// ANCHOR_END: Registers\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:313 msgid "" -"```rust,compile_fail\n" -"// Copyright 2023 Google LLC\n" -"//\n" -"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" -"// you may not use this file except in compliance with the License.\n" -"// You may obtain a copy of the License at\n" -"//\n" -"// http://www.apache.org/licenses/LICENSE-2.0\n" -"//\n" -"// Unless required by applicable law or agreed to in writing, software\n" -"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" -"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" -"// See the License for the specific language governing permissions and\n" -"// limitations under the License.\n" -"\n" -"#![allow(unused)]\n" -"\n" -"use core::fmt::{self, Write};\n" -"use core::ptr::{addr_of, addr_of_mut};\n" -"\n" -"// ANCHOR: Flags\n" -"use bitflags::bitflags;\n" -"\n" -"bitflags! {\n" -" /// Flags from the UART flag register.\n" -" #[repr(transparent)]\n" -" #[derive(Copy, Clone, Debug, Eq, PartialEq)]\n" -" struct Flags: u16 {\n" -" /// Clear to send.\n" -" const CTS = 1 << 0;\n" -" /// Data set ready.\n" -" const DSR = 1 << 1;\n" -" /// Data carrier detect.\n" -" const DCD = 1 << 2;\n" -" /// UART busy transmitting data.\n" -" const BUSY = 1 << 3;\n" -" /// Receive FIFO is empty.\n" -" const RXFE = 1 << 4;\n" -" /// Transmit FIFO is full.\n" -" const TXFF = 1 << 5;\n" -" /// Receive FIFO is full.\n" -" const RXFF = 1 << 6;\n" -" /// Transmit FIFO is empty.\n" -" const TXFE = 1 << 7;\n" -" /// Ring indicator.\n" -" const RI = 1 << 8;\n" -" }\n" -"}\n" -"// ANCHOR_END: Flags\n" -"\n" -"bitflags! {\n" -" /// Flags from the UART Receive Status Register / Error Clear Register.\n" -" #[repr(transparent)]\n" -" #[derive(Copy, Clone, Debug, Eq, PartialEq)]\n" -" struct ReceiveStatus: u16 {\n" -" /// Framing error.\n" -" const FE = 1 << 0;\n" -" /// Parity error.\n" -" const PE = 1 << 1;\n" -" /// Break error.\n" -" const BE = 1 << 2;\n" -" /// Overrun error.\n" -" const OE = 1 << 3;\n" -" }\n" -"}\n" -"\n" -"// ANCHOR: Registers\n" -"#[repr(C, align(4))]\n" -"struct Registers {\n" -" dr: u16,\n" -" _reserved0: [u8; 2],\n" -" rsr: ReceiveStatus,\n" -" _reserved1: [u8; 19],\n" -" fr: Flags,\n" -" _reserved2: [u8; 6],\n" -" ilpr: u8,\n" -" _reserved3: [u8; 3],\n" -" ibrd: u16,\n" -" _reserved4: [u8; 2],\n" -" fbrd: u8,\n" -" _reserved5: [u8; 3],\n" -" lcr_h: u8,\n" -" _reserved6: [u8; 3],\n" -" cr: u16,\n" -" _reserved7: [u8; 3],\n" -" ifls: u8,\n" -" _reserved8: [u8; 3],\n" -" imsc: u16,\n" -" _reserved9: [u8; 2],\n" -" ris: u16,\n" -" _reserved10: [u8; 2],\n" -" mis: u16,\n" -" _reserved11: [u8; 2],\n" -" icr: u16,\n" -" _reserved12: [u8; 2],\n" -" dmacr: u8,\n" -" _reserved13: [u8; 3],\n" -"}\n" -"// ANCHOR_END: Registers\n" -"\n" "// ANCHOR: Uart\n" "/// Driver for a PL011 UART.\n" -"#[derive(Debug)]\n" -"pub struct Uart {\n" -" registers: *mut Registers,\n" -"}\n" -"\n" -"impl Uart {\n" -" /// Constructs a new instance of the UART driver for a PL011 device at " -"the\n" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:322 +msgid "" +"/// Constructs a new instance of the UART driver for a PL011 device at the\n" " /// given base address.\n" " ///\n" " /// # Safety\n" @@ -14457,101 +13299,48 @@ msgid "" " /// PL011 device, which must be mapped into the address space of the " "process\n" " /// as device memory and not have any other aliases.\n" -" pub unsafe fn new(base_address: *mut u32) -> Self {\n" -" Self {\n" -" registers: base_address as *mut Registers,\n" -" }\n" -" }\n" -"\n" -" /// Writes a single byte to the UART.\n" -" pub fn write_byte(&self, byte: u8) {\n" -" // Wait until there is room in the TX buffer.\n" -" while self.read_flag_register().contains(Flags::TXFF) {}\n" -"\n" -" // Safe because we know that self.registers points to the control\n" -" // registers of a PL011 device which is appropriately mapped.\n" -" unsafe {\n" -" // Write to the TX buffer.\n" -" addr_of_mut!((*self.registers).dr).write_volatile(byte.into());\n" -" }\n" -"\n" -" // Wait until the UART is no longer busy.\n" -" while self.read_flag_register().contains(Flags::BUSY) {}\n" -" }\n" -"\n" -" /// Reads and returns a pending byte, or `None` if nothing has been " -"received.\n" -" pub fn read_byte(&self) -> Option {\n" -" if self.read_flag_register().contains(Flags::RXFE) {\n" -" None\n" -" } else {\n" -" let data = unsafe { addr_of!((*self.registers).dr)." -"read_volatile() };\n" -" // TODO: Check for error conditions in bits 8-11.\n" -" Some(data as u8)\n" -" }\n" -" }\n" -"\n" -" fn read_flag_register(&self) -> Flags {\n" -" // Safe because we know that self.registers points to the control\n" -" // registers of a PL011 device which is appropriately mapped.\n" -" unsafe { addr_of!((*self.registers).fr).read_volatile() }\n" -" }\n" -"}\n" -"// ANCHOR_END: Uart\n" -"\n" -"impl Write for Uart {\n" -" fn write_str(&mut self, s: &str) -> fmt::Result {\n" -" for c in s.as_bytes() {\n" -" self.write_byte(*c);\n" -" }\n" -" Ok(())\n" -" }\n" -"}\n" -"\n" -"// Safe because it just contains a pointer to device memory, which can be\n" -"// accessed from any context.\n" -"unsafe impl Send for Uart {}\n" -"```" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:368 +msgid "// ANCHOR_END: Uart\n" msgstr "" #: src/exercises/bare-metal/rtc.md:410 msgid "_build.rs_ (you shouldn't need to change this):" msgstr "" -#: src/exercises/bare-metal/rtc.md:414 -msgid "" -"```rust,compile_fail\n" -"// Copyright 2023 Google LLC\n" -"//\n" -"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" -"// you may not use this file except in compliance with the License.\n" -"// You may obtain a copy of the License at\n" -"//\n" -"// http://www.apache.org/licenses/LICENSE-2.0\n" -"//\n" -"// Unless required by applicable law or agreed to in writing, software\n" -"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" -"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" -"// See the License for the specific language governing permissions and\n" -"// limitations under the License.\n" -"\n" -"use cc::Build;\n" -"use std::env;\n" -"\n" -"fn main() {\n" -" #[cfg(target_os = \"linux\")]\n" -" env::set_var(\"CROSS_COMPILE\", \"aarch64-linux-gnu\");\n" -" #[cfg(not(target_os = \"linux\"))]\n" -" env::set_var(\"CROSS_COMPILE\", \"aarch64-none-elf\");\n" -"\n" -" Build::new()\n" -" .file(\"entry.S\")\n" -" .file(\"exceptions.S\")\n" -" .file(\"idmap.S\")\n" -" .compile(\"empty\")\n" -"}\n" -"```" +#: src/exercises/bare-metal/rtc.md:433 src/exercises/bare-metal/rtc.md:435 +msgid "\"linux\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:434 src/exercises/bare-metal/rtc.md:436 +msgid "\"CROSS_COMPILE\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:434 +#, fuzzy +msgid "\"aarch64-linux-gnu\"" +msgstr "aarch64-paging" + +#: src/exercises/bare-metal/rtc.md:436 +msgid "\"aarch64-none-elf\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:439 +msgid "\"entry.S\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:440 +#, fuzzy +msgid "\"exceptions.S\"" +msgstr "استثناها" + +#: src/exercises/bare-metal/rtc.md:441 +msgid "\"idmap.S\"" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:442 +msgid "\"empty\"" msgstr "" #: src/exercises/bare-metal/rtc.md:446 @@ -15090,49 +13879,25 @@ msgstr "" msgid "_Makefile_ (you shouldn't need to change this):" msgstr "" -#: src/exercises/bare-metal/rtc.md:944 -msgid "" -"```makefile\n" -"# Copyright 2023 Google LLC\n" -"#\n" -"# Licensed under the Apache License, Version 2.0 (the \"License\");\n" -"# you may not use this file except in compliance with the License.\n" -"# You may obtain a copy of the License at\n" -"#\n" -"# http://www.apache.org/licenses/LICENSE-2.0\n" -"#\n" -"# Unless required by applicable law or agreed to in writing, software\n" -"# distributed under the License is distributed on an \"AS IS\" BASIS,\n" -"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" -"# See the License for the specific language governing permissions and\n" -"# limitations under the License.\n" -"\n" -"UNAME := $(shell uname -s)\n" -"ifeq ($(UNAME),Linux)\n" -"\tTARGET = aarch64-linux-gnu\n" -"else\n" -"\tTARGET = aarch64-none-elf\n" -"endif\n" -"OBJCOPY = $(TARGET)-objcopy\n" -"\n" -".PHONY: build qemu_minimal qemu qemu_logger\n" -"\n" -"all: rtc.bin\n" -"\n" -"build:\n" -"\tcargo build\n" -"\n" -"rtc.bin: build\n" -"\t$(OBJCOPY) -O binary target/aarch64-unknown-none/debug/rtc $@\n" -"\n" -"qemu: rtc.bin\n" -"\tqemu-system-aarch64 -machine virt,gic-version=3 -cpu max -serial mon:stdio " -"-display none -kernel $< -s\n" -"\n" -"clean:\n" -"\tcargo clean\n" -"\trm -f *.bin\n" -"```" +#: src/exercises/bare-metal/rtc.md:945 +msgid "# Copyright 2023 Google LLC" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:959 +msgid "$(shell uname -s)" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:961 +#, fuzzy +msgid "aarch64-linux-gnu" +msgstr "aarch64-paging" + +#: src/exercises/bare-metal/rtc.md:978 +msgid "stdio -display none -kernel $< -s" +msgstr "" + +#: src/exercises/bare-metal/rtc.md:981 +msgid "cargo clean" msgstr "" #: src/exercises/bare-metal/rtc.md:995 @@ -15160,26 +13925,12 @@ msgstr "" msgid "Rust threads work similarly to threads in other languages:" msgstr "" -#: src/concurrency/threads.md:5 -msgid "" -"```rust,editable\n" -"use std::thread;\n" -"use std::time::Duration;\n" -"\n" -"fn main() {\n" -" thread::spawn(|| {\n" -" for i in 1..10 {\n" -" println!(\"Count in thread: {i}!\");\n" -" thread::sleep(Duration::from_millis(5));\n" -" }\n" -" });\n" -"\n" -" for i in 1..5 {\n" -" println!(\"Main thread: {i}\");\n" -" thread::sleep(Duration::from_millis(5));\n" -" }\n" -"}\n" -"```" +#: src/concurrency/threads.md:12 +msgid "\"Count in thread: {i}!\"" +msgstr "" + +#: src/concurrency/threads.md:18 +msgid "\"Main thread: {i}\"" msgstr "" #: src/concurrency/threads.md:24 @@ -15221,22 +13972,8 @@ msgstr "" msgid "Normal threads cannot borrow from their environment:" msgstr "" -#: src/concurrency/scoped-threads.md:5 -msgid "" -"```rust,editable,compile_fail\n" -"use std::thread;\n" -"\n" -"fn foo() {\n" -" let s = String::from(\"Hello\");\n" -" thread::spawn(|| {\n" -" println!(\"Length: {}\", s.len());\n" -" });\n" -"}\n" -"\n" -"fn main() {\n" -" foo();\n" -"}\n" -"```" +#: src/concurrency/scoped-threads.md:11 src/concurrency/scoped-threads.md:30 +msgid "\"Length: {}\"" msgstr "" #: src/concurrency/scoped-threads.md:20 @@ -15245,23 +13982,6 @@ msgid "" "fn.scope.html) for this:" msgstr "" -#: src/concurrency/scoped-threads.md:22 -msgid "" -"```rust,editable\n" -"use std::thread;\n" -"\n" -"fn main() {\n" -" let s = String::from(\"Hello\");\n" -"\n" -" thread::scope(|scope| {\n" -" scope.spawn(|| {\n" -" println!(\"Length: {}\", s.len());\n" -" });\n" -" });\n" -"}\n" -"```" -msgstr "" - #: src/concurrency/scoped-threads.md:40 msgid "" "The reason for that is that when the `thread::scope` function completes, all " @@ -15280,25 +14000,9 @@ msgid "" "parts are connected via the channel, but you only see the end-points." msgstr "" -#: src/concurrency/channels.md:6 -msgid "" -"```rust,editable\n" -"use std::sync::mpsc;\n" -"\n" -"fn main() {\n" -" let (tx, rx) = mpsc::channel();\n" -"\n" -" tx.send(10).unwrap();\n" -" tx.send(20).unwrap();\n" -"\n" -" println!(\"Received: {:?}\", rx.recv());\n" -" println!(\"Received: {:?}\", rx.recv());\n" -"\n" -" let tx2 = tx.clone();\n" -" tx2.send(30).unwrap();\n" -" println!(\"Received: {:?}\", rx.recv());\n" -"}\n" -"```" +#: src/concurrency/channels.md:15 src/concurrency/channels.md:16 +#: src/concurrency/channels.md:20 +msgid "\"Received: {:?}\"" msgstr "" #: src/concurrency/channels.md:26 @@ -15318,63 +14022,29 @@ msgstr "" msgid "You get an unbounded and asynchronous channel with `mpsc::channel()`:" msgstr "" -#: src/concurrency/channels/unbounded.md:5 -msgid "" -"```rust,editable\n" -"use std::sync::mpsc;\n" -"use std::thread;\n" -"use std::time::Duration;\n" -"\n" -"fn main() {\n" -" let (tx, rx) = mpsc::channel();\n" -"\n" -" thread::spawn(move || {\n" -" let thread_id = thread::current().id();\n" -" for i in 1..10 {\n" -" tx.send(format!(\"Message {i}\")).unwrap();\n" -" println!(\"{thread_id:?}: sent Message {i}\");\n" -" }\n" -" println!(\"{thread_id:?}: done\");\n" -" });\n" -" thread::sleep(Duration::from_millis(100));\n" -"\n" -" for msg in rx.iter() {\n" -" println!(\"Main: got {msg}\");\n" -" }\n" -"}\n" -"```" +#: src/concurrency/channels/unbounded.md:16 +#: src/concurrency/channels/bounded.md:16 +msgid "\"Message {i}\"" msgstr "" -#: src/concurrency/channels/bounded.md:3 -msgid "" -"With bounded (synchronous) channels, `send` can block the current thread:" +#: src/concurrency/channels/unbounded.md:17 +#: src/concurrency/channels/bounded.md:17 +msgid "\"{thread_id:?}: sent Message {i}\"" +msgstr "" + +#: src/concurrency/channels/unbounded.md:19 +#: src/concurrency/channels/bounded.md:19 +msgid "\"{thread_id:?}: done\"" +msgstr "" + +#: src/concurrency/channels/unbounded.md:24 +#: src/concurrency/channels/bounded.md:24 +msgid "\"Main: got {msg}\"" msgstr "" -#: src/concurrency/channels/bounded.md:5 +#: src/concurrency/channels/bounded.md:3 msgid "" -"```rust,editable\n" -"use std::sync::mpsc;\n" -"use std::thread;\n" -"use std::time::Duration;\n" -"\n" -"fn main() {\n" -" let (tx, rx) = mpsc::sync_channel(3);\n" -"\n" -" thread::spawn(move || {\n" -" let thread_id = thread::current().id();\n" -" for i in 1..10 {\n" -" tx.send(format!(\"Message {i}\")).unwrap();\n" -" println!(\"{thread_id:?}: sent Message {i}\");\n" -" }\n" -" println!(\"{thread_id:?}: done\");\n" -" });\n" -" thread::sleep(Duration::from_millis(100));\n" -"\n" -" for msg in rx.iter() {\n" -" println!(\"Main: got {msg}\");\n" -" }\n" -"}\n" -"```" +"With bounded (synchronous) channels, `send` can block the current thread:" msgstr "" #: src/concurrency/channels/bounded.md:31 @@ -15621,27 +14291,14 @@ msgid "" "read-only access via `Arc::clone`:" msgstr "" -#: src/concurrency/shared_state/arc.md:5 -msgid "" -"```rust,editable\n" -"use std::thread;\n" -"use std::sync::Arc;\n" -"\n" -"fn main() {\n" -" let v = Arc::new(vec![10, 20, 30]);\n" -" let mut handles = Vec::new();\n" -" for _ in 1..5 {\n" -" let v = Arc::clone(&v);\n" -" handles.push(thread::spawn(move || {\n" -" let thread_id = thread::current().id();\n" -" println!(\"{thread_id:?}: {v:?}\");\n" -" }));\n" -" }\n" -"\n" -" handles.into_iter().for_each(|h| h.join().unwrap());\n" -" println!(\"v: {v:?}\");\n" -"}\n" -"```" +#: src/concurrency/shared_state/arc.md:16 +msgid "\"{thread_id:?}: {v:?}\"" +msgstr "" + +#: src/concurrency/shared_state/arc.md:21 +#: src/concurrency/shared_state/example.md:17 +#: src/concurrency/shared_state/example.md:45 +msgid "\"v: {v:?}\"" msgstr "" #: src/concurrency/shared_state/arc.md:29 @@ -15683,23 +14340,9 @@ msgid "" "interface:" msgstr "" -#: src/concurrency/shared_state/mutex.md:6 -msgid "" -"```rust,editable\n" -"use std::sync::Mutex;\n" -"\n" -"fn main() {\n" -" let v = Mutex::new(vec![10, 20, 30]);\n" -" println!(\"v: {:?}\", v.lock().unwrap());\n" -"\n" -" {\n" -" let mut guard = v.lock().unwrap();\n" -" guard.push(40);\n" -" }\n" -"\n" -" println!(\"v: {:?}\", v.lock().unwrap());\n" -"}\n" -"```" +#: src/concurrency/shared_state/mutex.md:11 +#: src/concurrency/shared_state/mutex.md:18 +msgid "\"v: {:?}\"" msgstr "" #: src/concurrency/shared_state/mutex.md:22 @@ -15754,56 +14397,14 @@ msgstr "" msgid "Let us see `Arc` and `Mutex` in action:" msgstr "" -#: src/concurrency/shared_state/example.md:5 -msgid "" -"```rust,editable,compile_fail\n" -"use std::thread;\n" -"// use std::sync::{Arc, Mutex};\n" -"\n" -"fn main() {\n" -" let v = vec![10, 20, 30];\n" -" let handle = thread::spawn(|| {\n" -" v.push(10);\n" -" });\n" -" v.push(1000);\n" -"\n" -" handle.join().unwrap();\n" -" println!(\"v: {v:?}\");\n" -"}\n" -"```" +#: src/concurrency/shared_state/example.md:6 +msgid "// use std::sync::{Arc, Mutex};" msgstr "" #: src/concurrency/shared_state/example.md:23 msgid "Possible solution:" msgstr "" -#: src/concurrency/shared_state/example.md:25 -msgid "" -"```rust,editable\n" -"use std::sync::{Arc, Mutex};\n" -"use std::thread;\n" -"\n" -"fn main() {\n" -" let v = Arc::new(Mutex::new(vec![10, 20, 30]));\n" -"\n" -" let v2 = Arc::clone(&v);\n" -" let handle = thread::spawn(move || {\n" -" let mut v2 = v2.lock().unwrap();\n" -" v2.push(10);\n" -" });\n" -"\n" -" {\n" -" let mut v = v.lock().unwrap();\n" -" v.push(1000);\n" -" }\n" -"\n" -" handle.join().unwrap();\n" -"\n" -" println!(\"v: {v:?}\");\n" -"}\n" -"```" -msgstr "" - #: src/concurrency/shared_state/example.md:49 msgid "Notable parts:" msgstr "" @@ -15869,49 +14470,92 @@ msgid "" "out the blanks, and test that `cargo run` does not deadlock:" msgstr "" -#: src/exercises/concurrency/dining-philosophers.md:19 -msgid "" -"```rust,compile_fail\n" -"use std::sync::{mpsc, Arc, Mutex};\n" -"use std::thread;\n" -"use std::time::Duration;\n" -"\n" -"struct Fork;\n" -"\n" -"struct Philosopher {\n" -" name: String,\n" -" // left_fork: ...\n" -" // right_fork: ...\n" -" // thoughts: ...\n" -"}\n" -"\n" -"impl Philosopher {\n" -" fn think(&self) {\n" -" self.thoughts\n" -" .send(format!(\"Eureka! {} has a new idea!\", &self.name))\n" -" .unwrap();\n" -" }\n" -"\n" -" fn eat(&self) {\n" -" // Pick up forks...\n" -" println!(\"{} is eating...\", &self.name);\n" -" thread::sleep(Duration::from_millis(10));\n" -" }\n" -"}\n" -"\n" -"static PHILOSOPHERS: &[&str] =\n" -" &[\"Socrates\", \"Hypatia\", \"Plato\", \"Aristotle\", \"Pythagoras\"];\n" -"\n" -"fn main() {\n" -" // Create forks\n" -"\n" -" // Create philosophers\n" -"\n" -" // Make each of them think and eat 100 times\n" -"\n" -" // Output their thoughts\n" -"}\n" -"```" +#: src/exercises/concurrency/dining-philosophers.md:28 +#: src/exercises/concurrency/dining-philosophers-async.md:23 +msgid "// left_fork: ..." +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:29 +#: src/exercises/concurrency/dining-philosophers-async.md:24 +msgid "// right_fork: ..." +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:30 +#: src/exercises/concurrency/dining-philosophers-async.md:25 +msgid "// thoughts: ..." +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:36 +#: src/exercises/concurrency/dining-philosophers-async.md:31 +#: src/exercises/concurrency/solutions-morning.md:24 +#: src/exercises/concurrency/solutions-afternoon.md:25 +msgid "\"Eureka! {} has a new idea!\"" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:41 +#: src/exercises/concurrency/dining-philosophers-async.md:36 +msgid "// Pick up forks..." +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:42 +#: src/exercises/concurrency/dining-philosophers-async.md:37 +#: src/exercises/concurrency/solutions-morning.md:33 +#: src/exercises/concurrency/solutions-afternoon.md:37 +msgid "\"{} is eating...\"" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:48 +#: src/exercises/concurrency/dining-philosophers-async.md:43 +#: src/exercises/concurrency/solutions-morning.md:39 +#: src/exercises/concurrency/solutions-afternoon.md:45 +msgid "\"Socrates\"" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:48 +#: src/exercises/concurrency/dining-philosophers-async.md:43 +#: src/exercises/concurrency/solutions-morning.md:39 +#: src/exercises/concurrency/solutions-afternoon.md:45 +msgid "\"Hypatia\"" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:48 +#: src/exercises/concurrency/dining-philosophers-async.md:43 +#: src/exercises/concurrency/solutions-morning.md:39 +#: src/exercises/concurrency/solutions-afternoon.md:45 +msgid "\"Plato\"" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:48 +#: src/exercises/concurrency/dining-philosophers-async.md:43 +#: src/exercises/concurrency/solutions-morning.md:39 +#: src/exercises/concurrency/solutions-afternoon.md:45 +msgid "\"Aristotle\"" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:48 +#: src/exercises/concurrency/dining-philosophers-async.md:43 +#: src/exercises/concurrency/solutions-morning.md:39 +#: src/exercises/concurrency/solutions-afternoon.md:45 +msgid "\"Pythagoras\"" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:51 +#: src/exercises/concurrency/dining-philosophers-async.md:47 +msgid "// Create forks" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:53 +#: src/exercises/concurrency/dining-philosophers-async.md:49 +msgid "// Create philosophers" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:55 +msgid "// Make each of them think and eat 100 times" +msgstr "" + +#: src/exercises/concurrency/dining-philosophers.md:57 +#: src/exercises/concurrency/dining-philosophers-async.md:53 +msgid "// Output their thoughts" msgstr "" #: src/exercises/concurrency/dining-philosophers.md:61 @@ -15992,73 +14636,42 @@ msgstr "" msgid "Your `src/main.rs` file should look something like this:" msgstr "" -#: src/exercises/concurrency/link-checker.md:57 -msgid "" -"```rust,compile_fail\n" -"use reqwest::{blocking::Client, Url};\n" -"use scraper::{Html, Selector};\n" -"use thiserror::Error;\n" -"\n" -"#[derive(Error, Debug)]\n" -"enum Error {\n" -" #[error(\"request error: {0}\")]\n" -" ReqwestError(#[from] reqwest::Error),\n" -" #[error(\"bad http response: {0}\")]\n" -" BadResponse(String),\n" -"}\n" -"\n" -"#[derive(Debug)]\n" -"struct CrawlCommand {\n" -" url: Url,\n" -" extract_links: bool,\n" -"}\n" -"\n" -"fn visit_page(client: &Client, command: &CrawlCommand) -> Result, " -"Error> {\n" -" println!(\"Checking {:#}\", command.url);\n" -" let response = client.get(command.url.clone()).send()?;\n" -" if !response.status().is_success() {\n" -" return Err(Error::BadResponse(response.status().to_string()));\n" -" }\n" -"\n" -" let mut link_urls = Vec::new();\n" -" if !command.extract_links {\n" -" return Ok(link_urls);\n" -" }\n" -"\n" -" let base_url = response.url().to_owned();\n" -" let body_text = response.text()?;\n" -" let document = Html::parse_document(&body_text);\n" -"\n" -" let selector = Selector::parse(\"a\").unwrap();\n" -" let href_values = document\n" -" .select(&selector)\n" -" .filter_map(|element| element.value().attr(\"href\"));\n" -" for href in href_values {\n" -" match base_url.join(href) {\n" -" Ok(link_url) => {\n" -" link_urls.push(link_url);\n" -" }\n" -" Err(err) => {\n" -" println!(\"On {base_url:#}: ignored unparsable {href:?}: " -"{err}\");\n" -" }\n" -" }\n" -" }\n" -" Ok(link_urls)\n" -"}\n" -"\n" -"fn main() {\n" -" let client = Client::new();\n" -" let start_url = Url::parse(\"https://www.google.org\").unwrap();\n" -" let crawl_command = CrawlCommand{ url: start_url, extract_links: " -"true };\n" -" match visit_page(&client, &crawl_command) {\n" -" Ok(links) => println!(\"Links: {links:#?}\"),\n" -" Err(err) => println!(\"Could not extract links: {err:#}\"),\n" -" }\n" -"}\n" -"```" +#: src/exercises/concurrency/link-checker.md:64 +#: src/exercises/concurrency/solutions-morning.md:95 +msgid "\"request error: {0}\"" +msgstr "" + +#: src/exercises/concurrency/link-checker.md:66 +#: src/exercises/concurrency/solutions-morning.md:97 +msgid "\"bad http response: {0}\"" +msgstr "" + +#: src/exercises/concurrency/link-checker.md:77 +#: src/exercises/concurrency/solutions-morning.md:108 +msgid "\"Checking {:#}\"" +msgstr "" + +#: src/exercises/concurrency/link-checker.md:95 +#: src/exercises/concurrency/solutions-morning.md:126 +msgid "\"href\"" +msgstr "" + +#: src/exercises/concurrency/link-checker.md:102 +#: src/exercises/concurrency/solutions-morning.md:133 +msgid "\"On {base_url:#}: ignored unparsable {href:?}: {err}\"" +msgstr "" + +#: src/exercises/concurrency/link-checker.md:111 +#: src/exercises/concurrency/solutions-morning.md:246 +msgid "\"https://www.google.org\"" +msgstr "" + +#: src/exercises/concurrency/link-checker.md:114 +msgid "\"Links: {links:#?}\"" +msgstr "" + +#: src/exercises/concurrency/link-checker.md:115 +msgid "\"Could not extract links: {err:#}\"" msgstr "" #: src/exercises/concurrency/link-checker.md:120 @@ -16133,25 +14746,8 @@ msgid "" "code:" msgstr "" -#: src/async/async-await.md:5 -msgid "" -"```rust,editable,compile_fail\n" -"use futures::executor::block_on;\n" -"\n" -"async fn count_to(count: i32) {\n" -" for i in 1..=count {\n" -" println!(\"Count is: {i}!\");\n" -" }\n" -"}\n" -"\n" -"async fn async_main(count: i32) {\n" -" count_to(count).await;\n" -"}\n" -"\n" -"fn main() {\n" -" block_on(async_main(10));\n" -"}\n" -"```" +#: src/async/async-await.md:10 +msgid "\"Count is: {i}!\"" msgstr "" #: src/async/async-await.md:27 @@ -16307,28 +14903,12 @@ msgstr "" msgid "A large ecosystem of libraries." msgstr "" -#: src/async/runtimes/tokio.md:10 -msgid "" -"```rust,editable,compile_fail\n" -"use tokio::time;\n" -"\n" -"async fn count_to(count: i32) {\n" -" for i in 1..=count {\n" -" println!(\"Count in task: {i}!\");\n" -" time::sleep(time::Duration::from_millis(5)).await;\n" -" }\n" -"}\n" -"\n" -"#[tokio::main]\n" -"async fn main() {\n" -" tokio::spawn(count_to(10));\n" -"\n" -" for i in 1..5 {\n" -" println!(\"Main task: {i}\");\n" -" time::sleep(time::Duration::from_millis(5)).await;\n" -" }\n" -"}\n" -"```" +#: src/async/runtimes/tokio.md:15 +msgid "\"Count in task: {i}!\"" +msgstr "" + +#: src/async/runtimes/tokio.md:25 +msgid "\"Main task: {i}\"" msgstr "" #: src/async/runtimes/tokio.md:33 @@ -16375,48 +14955,28 @@ msgid "" "and an I/O operation." msgstr "" -#: src/async/tasks.md:10 -msgid "" -"```rust,compile_fail\n" -"use tokio::io::{self, AsyncReadExt, AsyncWriteExt};\n" -"use tokio::net::TcpListener;\n" -"\n" -"#[tokio::main]\n" -"async fn main() -> io::Result<()> {\n" -" let listener = TcpListener::bind(\"127.0.0.1:6142\").await?;\n" -"\tprintln!(\"listening on port 6142\");\n" -"\n" -" loop {\n" -" let (mut socket, addr) = listener.accept().await?;\n" -"\n" -" println!(\"connection from {addr:?}\");\n" -"\n" -" tokio::spawn(async move {\n" -" if let Err(e) = socket.write_all(b\"Who are you?\\n\").await {\n" -" println!(\"socket error: {e:?}\");\n" -" return;\n" -" }\n" -"\n" -" let mut buf = vec![0; 1024];\n" -" let reply = match socket.read(&mut buf).await {\n" -" Ok(n) => {\n" -" let name = std::str::from_utf8(&buf[..n]).unwrap()." -"trim();\n" -" format!(\"Thanks for dialing in, {name}!\\n\")\n" -" }\n" -" Err(e) => {\n" -" println!(\"socket error: {e:?}\");\n" -" return;\n" -" }\n" -" };\n" -"\n" -" if let Err(e) = socket.write_all(reply.as_bytes()).await {\n" -" println!(\"socket error: {e:?}\");\n" -" }\n" -" });\n" -" }\n" -"}\n" -"```" +#: src/async/tasks.md:16 +msgid "\"127.0.0.1:6142\"" +msgstr "" + +#: src/async/tasks.md:17 +msgid "\"listening on port 6142\"" +msgstr "" + +#: src/async/tasks.md:22 +msgid "\"connection from {addr:?}\"" +msgstr "" + +#: src/async/tasks.md:25 +msgid "b\"Who are you?\\n\"" +msgstr "" + +#: src/async/tasks.md:26 src/async/tasks.md:37 src/async/tasks.md:43 +msgid "\"socket error: {e:?}\"" +msgstr "" + +#: src/async/tasks.md:34 +msgid "\"Thanks for dialing in, {name}!\\n\"" msgstr "" #: src/async/tasks.md:52 src/async/control-flow/join.md:36 @@ -16455,36 +15015,24 @@ msgid "" "Several crates have support for asynchronous channels. For instance `tokio`:" msgstr "" -#: src/async/channels.md:5 -msgid "" -"```rust,editable,compile_fail\n" -"use tokio::sync::mpsc::{self, Receiver};\n" -"\n" -"async fn ping_handler(mut input: Receiver<()>) {\n" -" let mut count: usize = 0;\n" -"\n" -" while let Some(_) = input.recv().await {\n" -" count += 1;\n" -" println!(\"Received {count} pings so far.\");\n" -" }\n" -"\n" -" println!(\"ping_handler complete\");\n" -"}\n" -"\n" -"#[tokio::main]\n" -"async fn main() {\n" -" let (sender, receiver) = mpsc::channel(32);\n" -" let ping_handler_task = tokio::spawn(ping_handler(receiver));\n" -" for i in 0..10 {\n" -" sender.send(()).await.expect(\"Failed to send ping.\");\n" -" println!(\"Sent {} pings so far.\", i + 1);\n" -" }\n" -"\n" -" drop(sender);\n" -" ping_handler_task.await.expect(\"Something went wrong in ping handler " -"task.\");\n" -"}\n" -"```" +#: src/async/channels.md:13 +msgid "\"Received {count} pings so far.\"" +msgstr "" + +#: src/async/channels.md:16 +msgid "\"ping_handler complete\"" +msgstr "" + +#: src/async/channels.md:24 +msgid "\"Failed to send ping.\"" +msgstr "" + +#: src/async/channels.md:25 +msgid "\"Sent {} pings so far.\"" +msgstr "" + +#: src/async/channels.md:29 +msgid "\"Something went wrong in ping handler task.\"" msgstr "" #: src/async/channels.md:35 @@ -16541,34 +15089,25 @@ msgid "" "JavaScript or `asyncio.gather` in Python." msgstr "" -#: src/async/control-flow/join.md:7 -msgid "" -"```rust,editable,compile_fail\n" -"use anyhow::Result;\n" -"use futures::future;\n" -"use reqwest;\n" -"use std::collections::HashMap;\n" -"\n" -"async fn size_of_page(url: &str) -> Result {\n" -" let resp = reqwest::get(url).await?;\n" -" Ok(resp.text().await?.len())\n" -"}\n" -"\n" -"#[tokio::main]\n" -"async fn main() {\n" -" let urls: [&str; 4] = [\n" -" \"https://google.com\",\n" -" \"https://httpbin.org/ip\",\n" -" \"https://play.rust-lang.org/\",\n" -" \"BAD_URL\",\n" -" ];\n" -" let futures_iter = urls.into_iter().map(size_of_page);\n" -" let results = future::join_all(futures_iter).await;\n" -" let page_sizes_dict: HashMap<&str, Result> =\n" -" urls.into_iter().zip(results.into_iter()).collect();\n" -" println!(\"{:?}\", page_sizes_dict);\n" -"}\n" -"```" +#: src/async/control-flow/join.md:21 +msgid "\"https://google.com\"" +msgstr "" + +#: src/async/control-flow/join.md:22 +msgid "\"https://httpbin.org/ip\"" +msgstr "" + +#: src/async/control-flow/join.md:23 +msgid "\"https://play.rust-lang.org/\"" +msgstr "" + +#: src/async/control-flow/join.md:24 +msgid "\"BAD_URL\"" +msgstr "" + +#: src/async/control-flow/join.md:30 +#: src/exercises/day-1/solutions-morning.md:78 +msgid "\"{:?}\"" msgstr "" #: src/async/control-flow/join.md:38 @@ -16609,54 +15148,28 @@ msgid "" "the `future`'s result." msgstr "" -#: src/async/control-flow/select.md:13 -msgid "" -"```rust,editable,compile_fail\n" -"use tokio::sync::mpsc::{self, Receiver};\n" -"use tokio::time::{sleep, Duration};\n" -"\n" -"#[derive(Debug, PartialEq)]\n" -"enum Animal {\n" -" Cat { name: String },\n" -" Dog { name: String },\n" -"}\n" -"\n" -"async fn first_animal_to_finish_race(\n" -" mut cat_rcv: Receiver,\n" -" mut dog_rcv: Receiver,\n" -") -> Option {\n" -" tokio::select! {\n" -" cat_name = cat_rcv.recv() => Some(Animal::Cat { name: cat_name? }),\n" -" dog_name = dog_rcv.recv() => Some(Animal::Dog { name: dog_name? })\n" -" }\n" -"}\n" -"\n" -"#[tokio::main]\n" -"async fn main() {\n" -" let (cat_sender, cat_receiver) = mpsc::channel(32);\n" -" let (dog_sender, dog_receiver) = mpsc::channel(32);\n" -" tokio::spawn(async move {\n" -" sleep(Duration::from_millis(500)).await;\n" -" cat_sender\n" -" .send(String::from(\"Felix\"))\n" -" .await\n" -" .expect(\"Failed to send cat.\");\n" -" });\n" -" tokio::spawn(async move {\n" -" sleep(Duration::from_millis(50)).await;\n" -" dog_sender\n" -" .send(String::from(\"Rex\"))\n" -" .await\n" -" .expect(\"Failed to send dog.\");\n" -" });\n" -"\n" -" let winner = first_animal_to_finish_race(cat_receiver, dog_receiver)\n" -" .await\n" -" .expect(\"Failed to receive winner\");\n" -"\n" -" println!(\"Winner is {winner:?}\");\n" -"}\n" -"```" +#: src/async/control-flow/select.md:40 +msgid "\"Felix\"" +msgstr "" + +#: src/async/control-flow/select.md:42 +msgid "\"Failed to send cat.\"" +msgstr "" + +#: src/async/control-flow/select.md:47 +msgid "\"Rex\"" +msgstr "" + +#: src/async/control-flow/select.md:49 +msgid "\"Failed to send dog.\"" +msgstr "" + +#: src/async/control-flow/select.md:54 +msgid "\"Failed to receive winner\"" +msgstr "" + +#: src/async/control-flow/select.md:56 +msgid "\"Winner is {winner:?}\"" msgstr "" #: src/async/control-flow/select.md:62 @@ -16731,27 +15244,12 @@ msgid "" "possible." msgstr "" -#: src/async/pitfalls/blocking-executor.md:7 -msgid "" -"```rust,editable,compile_fail\n" -"use futures::future::join_all;\n" -"use std::time::Instant;\n" -"\n" -"async fn sleep_ms(start: &Instant, id: u64, duration_ms: u64) {\n" -" std::thread::sleep(std::time::Duration::from_millis(duration_ms));\n" -" println!(\n" -" \"future {id} slept for {duration_ms}ms, finished after {}ms\",\n" -" start.elapsed().as_millis()\n" -" );\n" -"}\n" -"\n" -"#[tokio::main(flavor = \"current_thread\")]\n" -"async fn main() {\n" -" let start = Instant::now();\n" -" let sleep_futures = (1..=10).map(|t| sleep_ms(&start, t, t * 10));\n" -" join_all(sleep_futures).await;\n" -"}\n" -"```" +#: src/async/pitfalls/blocking-executor.md:14 +msgid "\"future {id} slept for {duration_ms}ms, finished after {}ms\"" +msgstr "" + +#: src/async/pitfalls/blocking-executor.md:19 +msgid "\"current_thread\"" msgstr "" #: src/async/pitfalls/blocking-executor.md:29 @@ -16809,61 +15307,44 @@ msgid "" "repeatedly in a `select!` often leads to issues with pinned values." msgstr "" -#: src/async/pitfalls/pin.md:12 -msgid "" -"```rust,editable,compile_fail\n" -"use tokio::sync::{mpsc, oneshot};\n" -"use tokio::task::spawn;\n" -"use tokio::time::{sleep, Duration};\n" -"\n" -"// A work item. In this case, just sleep for the given time and respond\n" -"// with a message on the `respond_on` channel.\n" -"#[derive(Debug)]\n" -"struct Work {\n" -" input: u32,\n" -" respond_on: oneshot::Sender,\n" -"}\n" -"\n" -"// A worker which listens for work on a queue and performs it.\n" -"async fn worker(mut work_queue: mpsc::Receiver) {\n" -" let mut iterations = 0;\n" -" loop {\n" -" tokio::select! {\n" -" Some(work) = work_queue.recv() => {\n" -" sleep(Duration::from_millis(10)).await; // Pretend to work.\n" -" work.respond_on\n" -" .send(work.input * 1000)\n" -" .expect(\"failed to send response\");\n" -" iterations += 1;\n" -" }\n" -" // TODO: report number of iterations every 100ms\n" -" }\n" -" }\n" -"}\n" -"\n" -"// A requester which requests work and waits for it to complete.\n" -"async fn do_work(work_queue: &mpsc::Sender, input: u32) -> u32 {\n" -" let (tx, rx) = oneshot::channel();\n" -" work_queue\n" -" .send(Work {\n" -" input,\n" -" respond_on: tx,\n" -" })\n" -" .await\n" -" .expect(\"failed to send on work queue\");\n" -" rx.await.expect(\"failed waiting for response\")\n" -"}\n" -"\n" -"#[tokio::main]\n" -"async fn main() {\n" -" let (tx, rx) = mpsc::channel(10);\n" -" spawn(worker(rx));\n" -" for i in 0..100 {\n" -" let resp = do_work(&tx, i).await;\n" -" println!(\"work result for iteration {i}: {resp}\");\n" -" }\n" -"}\n" -"```" +#: src/async/pitfalls/pin.md:16 +msgid "// A work item. In this case, just sleep for the given time and respond" +msgstr "" + +#: src/async/pitfalls/pin.md:17 +msgid "// with a message on the `respond_on` channel." +msgstr "" + +#: src/async/pitfalls/pin.md:24 +msgid "// A worker which listens for work on a queue and performs it." +msgstr "" + +#: src/async/pitfalls/pin.md:31 +msgid "// Pretend to work." +msgstr "" + +#: src/async/pitfalls/pin.md:34 +msgid "\"failed to send response\"" +msgstr "" + +#: src/async/pitfalls/pin.md:37 +msgid "// TODO: report number of iterations every 100ms" +msgstr "" + +#: src/async/pitfalls/pin.md:41 +msgid "// A requester which requests work and waits for it to complete." +msgstr "" + +#: src/async/pitfalls/pin.md:51 +msgid "\"failed to send on work queue\"" +msgstr "" + +#: src/async/pitfalls/pin.md:52 +msgid "\"failed waiting for response\"" +msgstr "" + +#: src/async/pitfalls/pin.md:61 +msgid "\"work result for iteration {i}: {resp}\"" msgstr "" #: src/async/pitfalls/pin.md:68 @@ -16930,50 +15411,12 @@ msgid "" "provides a workaround through a macro:" msgstr "" -#: src/async/pitfalls/async-traits.md:7 -msgid "" -"```rust,editable,compile_fail\n" -"use async_trait::async_trait;\n" -"use std::time::Instant;\n" -"use tokio::time::{sleep, Duration};\n" -"\n" -"#[async_trait]\n" -"trait Sleeper {\n" -" async fn sleep(&self);\n" -"}\n" -"\n" -"struct FixedSleeper {\n" -" sleep_ms: u64,\n" -"}\n" -"\n" -"#[async_trait]\n" -"impl Sleeper for FixedSleeper {\n" -" async fn sleep(&self) {\n" -" sleep(Duration::from_millis(self.sleep_ms)).await;\n" -" }\n" -"}\n" -"\n" -"async fn run_all_sleepers_multiple_times(sleepers: Vec>, " -"n_times: usize) {\n" -" for _ in 0..n_times {\n" -" println!(\"running all sleepers..\");\n" -" for sleeper in &sleepers {\n" -" let start = Instant::now();\n" -" sleeper.sleep().await;\n" -" println!(\"slept for {}ms\", start.elapsed().as_millis());\n" -" }\n" -" }\n" -"}\n" -"\n" -"#[tokio::main]\n" -"async fn main() {\n" -" let sleepers: Vec> = vec![\n" -" Box::new(FixedSleeper { sleep_ms: 50 }),\n" -" Box::new(FixedSleeper { sleep_ms: 100 }),\n" -" ];\n" -" run_all_sleepers_multiple_times(sleepers, 5).await;\n" -"}\n" -"```" +#: src/async/pitfalls/async-traits.md:30 +msgid "\"running all sleepers..\"" +msgstr "" + +#: src/async/pitfalls/async-traits.md:34 +msgid "\"slept for {}ms\"" msgstr "" #: src/async/pitfalls/async-traits.md:51 @@ -17005,72 +15448,16 @@ msgid "" "example, it shouldn't deadlock or lose data." msgstr "" -#: src/async/pitfalls/cancellation.md:8 -msgid "" -"```rust,editable,compile_fail\n" -"use std::io::{self, ErrorKind};\n" -"use std::time::Duration;\n" -"use tokio::io::{AsyncReadExt, AsyncWriteExt, DuplexStream};\n" -"\n" -"struct LinesReader {\n" -" stream: DuplexStream,\n" -"}\n" -"\n" -"impl LinesReader {\n" -" fn new(stream: DuplexStream) -> Self {\n" -" Self { stream }\n" -" }\n" -"\n" -" async fn next(&mut self) -> io::Result> {\n" -" let mut bytes = Vec::new();\n" -" let mut buf = [0];\n" -" while self.stream.read(&mut buf[..]).await? != 0 {\n" -" bytes.push(buf[0]);\n" -" if buf[0] == b'\\n' {\n" -" break;\n" -" }\n" -" }\n" -" if bytes.is_empty() {\n" -" return Ok(None)\n" -" }\n" -" let s = String::from_utf8(bytes)\n" -" .map_err(|_| io::Error::new(ErrorKind::InvalidData, \"not " -"UTF-8\"))?;\n" -" Ok(Some(s))\n" -" }\n" -"}\n" -"\n" -"async fn slow_copy(source: String, mut dest: DuplexStream) -> std::io::" -"Result<()> {\n" -" for b in source.bytes() {\n" -" dest.write_u8(b).await?;\n" -" tokio::time::sleep(Duration::from_millis(10)).await\n" -" }\n" -" Ok(())\n" -"}\n" -"\n" -"#[tokio::main]\n" -"async fn main() -> std::io::Result<()> {\n" -" let (client, server) = tokio::io::duplex(5);\n" -" let handle = tokio::spawn(slow_copy(\"hi\\nthere\\n\".to_owned(), " -"client));\n" -"\n" -" let mut lines = LinesReader::new(server);\n" -" let mut interval = tokio::time::interval(Duration::from_millis(60));\n" -" loop {\n" -" tokio::select! {\n" -" _ = interval.tick() => println!(\"tick!\"),\n" -" line = lines.next() => if let Some(l) = line? {\n" -" print!(\"{}\", l)\n" -" } else {\n" -" break\n" -" },\n" -" }\n" -" }\n" -" handle.await.unwrap()?;\n" -" Ok(())\n" -"}\n" -"```" +#: src/async/pitfalls/cancellation.md:35 +msgid "\"not UTF-8\"" +msgstr "" + +#: src/async/pitfalls/cancellation.md:51 +msgid "\"hi\\nthere\\n\"" +msgstr "" + +#: src/async/pitfalls/cancellation.md:57 +msgid "\"tick!\"" msgstr "" #: src/async/pitfalls/cancellation.md:72 @@ -17101,28 +15488,8 @@ msgid "" "struct:" msgstr "" -#: src/async/pitfalls/cancellation.md:83 -msgid "" -"```rust,compile_fail\n" -"struct LinesReader {\n" -" stream: DuplexStream,\n" -" bytes: Vec,\n" -" buf: [u8; 1],\n" -"}\n" -"\n" -"impl LinesReader {\n" -" fn new(stream: DuplexStream) -> Self {\n" -" Self { stream, bytes: Vec::new(), buf: [0] }\n" -" }\n" -" async fn next(&mut self) -> io::Result> {\n" -" // prefix buf and bytes with self.\n" -" // ...\n" -" let raw = std::mem::take(&mut self.bytes);\n" -" let s = String::from_utf8(raw)\n" -" // ...\n" -" }\n" -"}\n" -"```" +#: src/async/pitfalls/cancellation.md:95 +msgid "// prefix buf and bytes with self." msgstr "" #: src/async/pitfalls/cancellation.md:104 @@ -17181,52 +15548,8 @@ msgid "" "main.rs`, fill out the blanks, and test that `cargo run` does not deadlock:" msgstr "" -#: src/exercises/concurrency/dining-philosophers-async.md:13 -msgid "" -"```rust,compile_fail\n" -"use std::sync::Arc;\n" -"use tokio::time;\n" -"use tokio::sync::mpsc::{self, Sender};\n" -"use tokio::sync::Mutex;\n" -"\n" -"struct Fork;\n" -"\n" -"struct Philosopher {\n" -" name: String,\n" -" // left_fork: ...\n" -" // right_fork: ...\n" -" // thoughts: ...\n" -"}\n" -"\n" -"impl Philosopher {\n" -" async fn think(&self) {\n" -" self.thoughts\n" -" .send(format!(\"Eureka! {} has a new idea!\", &self.name))." -"await\n" -" .unwrap();\n" -" }\n" -"\n" -" async fn eat(&self) {\n" -" // Pick up forks...\n" -" println!(\"{} is eating...\", &self.name);\n" -" time::sleep(time::Duration::from_millis(5)).await;\n" -" }\n" -"}\n" -"\n" -"static PHILOSOPHERS: &[&str] =\n" -" &[\"Socrates\", \"Hypatia\", \"Plato\", \"Aristotle\", \"Pythagoras\"];\n" -"\n" -"#[tokio::main]\n" -"async fn main() {\n" -" // Create forks\n" -"\n" -" // Create philosophers\n" -"\n" -" // Make them think and eat\n" -"\n" -" // Output their thoughts\n" -"}\n" -"```" +#: src/exercises/concurrency/dining-philosophers-async.md:51 +msgid "// Make them think and eat" msgstr "" #: src/exercises/concurrency/dining-philosophers-async.md:57 @@ -17367,47 +15690,29 @@ msgstr "" msgid "_src/bin/server.rs_:" msgstr "" -#: src/exercises/concurrency/chat-app.md:63 -msgid "" -"```rust,compile_fail\n" -"use futures_util::sink::SinkExt;\n" -"use futures_util::stream::StreamExt;\n" -"use std::error::Error;\n" -"use std::net::SocketAddr;\n" -"use tokio::net::{TcpListener, TcpStream};\n" -"use tokio::sync::broadcast::{channel, Sender};\n" -"use tokio_websockets::{Message, ServerBuilder, WebsocketStream};\n" -"\n" -"async fn handle_connection(\n" -" addr: SocketAddr,\n" -" mut ws_stream: WebsocketStream,\n" -" bcast_tx: Sender,\n" -") -> Result<(), Box> {\n" -"\n" -" // TODO: For a hint, see the description of the task below.\n" -"\n" -"}\n" -"\n" -"#[tokio::main]\n" -"async fn main() -> Result<(), Box> {\n" -" let (bcast_tx, _) = channel(16);\n" -"\n" -" let listener = TcpListener::bind(\"127.0.0.1:2000\").await?;\n" -" println!(\"listening on port 2000\");\n" -"\n" -" loop {\n" -" let (socket, addr) = listener.accept().await?;\n" -" println!(\"New connection from {addr:?}\");\n" -" let bcast_tx = bcast_tx.clone();\n" -" tokio::spawn(async move {\n" -" // Wrap the raw TCP stream into a websocket.\n" -" let ws_stream = ServerBuilder::new().accept(socket).await?;\n" -"\n" -" handle_connection(addr, ws_stream, bcast_tx).await\n" -" });\n" -" }\n" -"}\n" -"```" +#: src/exercises/concurrency/chat-app.md:78 +#: src/exercises/concurrency/chat-app.md:125 +msgid "// TODO: For a hint, see the description of the task below." +msgstr "" + +#: src/exercises/concurrency/chat-app.md:86 +#: src/exercises/concurrency/solutions-afternoon.md:149 +msgid "\"127.0.0.1:2000\"" +msgstr "" + +#: src/exercises/concurrency/chat-app.md:87 +#: src/exercises/concurrency/solutions-afternoon.md:150 +msgid "\"listening on port 2000\"" +msgstr "" + +#: src/exercises/concurrency/chat-app.md:91 +#: src/exercises/concurrency/solutions-afternoon.md:154 +msgid "\"New connection from {addr:?}\"" +msgstr "" + +#: src/exercises/concurrency/chat-app.md:94 +#: src/exercises/concurrency/solutions-afternoon.md:157 +msgid "// Wrap the raw TCP stream into a websocket.\n" msgstr "" #: src/exercises/concurrency/chat-app.md:103 @@ -17415,30 +15720,9 @@ msgstr "" msgid "_src/bin/client.rs_:" msgstr "" -#: src/exercises/concurrency/chat-app.md:107 -msgid "" -"```rust,compile_fail\n" -"use futures_util::stream::StreamExt;\n" -"use futures_util::SinkExt;\n" -"use http::Uri;\n" -"use tokio::io::{AsyncBufReadExt, BufReader};\n" -"use tokio_websockets::{ClientBuilder, Message};\n" -"\n" -"#[tokio::main]\n" -"async fn main() -> Result<(), tokio_websockets::Error> {\n" -" let (mut ws_stream, _) =\n" -" ClientBuilder::from_uri(Uri::from_static(\"ws://127.0.0.1:2000\"))\n" -" .connect()\n" -" .await?;\n" -"\n" -" let stdin = tokio::io::stdin();\n" -" let mut stdin = BufReader::new(stdin).lines();\n" -"\n" -"\n" -" // TODO: For a hint, see the description of the task below.\n" -"\n" -"}\n" -"```" +#: src/exercises/concurrency/chat-app.md:117 +#: src/exercises/concurrency/solutions-afternoon.md:178 +msgid "\"ws://127.0.0.1:2000\"" msgstr "" #: src/exercises/concurrency/chat-app.md:130 @@ -17641,176 +15925,189 @@ msgid "library:" msgstr "کتابخانه" #: src/glossary.md:67 -msgid "macro:" +msgid "" +"macro: \n" +"Rust macros can be recognized by a `!` in the name. Macros are used when " +"normal functions are not enough. A typical example is `format!`, which takes " +"a variable number of arguments, which isn't supported by Rust functions." msgstr "" -#: src/glossary.md:68 -#, fuzzy -msgid "main function:" -msgstr "فراخوانی متدهای ناامن" +#: src/glossary.md:72 +msgid "" +"`main` function: \n" +"Rust programs start executing with the `main` function." +msgstr "" -#: src/glossary.md:69 +#: src/glossary.md:74 msgid "match:" msgstr "" -#: src/glossary.md:70 +#: src/glossary.md:75 msgid "memory leak:" msgstr "" -#: src/glossary.md:71 +#: src/glossary.md:76 #, fuzzy msgid "method:" msgstr "متدها" -#: src/glossary.md:72 +#: src/glossary.md:77 #, fuzzy msgid "module:" msgstr "ماژول‌ها" -#: src/glossary.md:73 +#: src/glossary.md:78 msgid "move:" msgstr "" -#: src/glossary.md:74 +#: src/glossary.md:79 msgid "mutable:" msgstr "" -#: src/glossary.md:75 +#: src/glossary.md:80 #, fuzzy msgid "ownership:" msgstr "مالکیت" -#: src/glossary.md:76 +#: src/glossary.md:81 #, fuzzy msgid "panic:" msgstr "Panics" -#: src/glossary.md:77 +#: src/glossary.md:82 msgid "parameter:" msgstr "" -#: src/glossary.md:78 +#: src/glossary.md:83 msgid "pattern:" msgstr "" -#: src/glossary.md:79 +#: src/glossary.md:84 msgid "payload:" msgstr "" -#: src/glossary.md:80 +#: src/glossary.md:85 msgid "program:" msgstr "" -#: src/glossary.md:81 +#: src/glossary.md:86 msgid "programming language:" msgstr "" -#: src/glossary.md:82 +#: src/glossary.md:87 #, fuzzy msgid "receiver:" msgstr "درایور" -#: src/glossary.md:83 +#: src/glossary.md:88 msgid "reference counting:" msgstr "" -#: src/glossary.md:84 +#: src/glossary.md:89 msgid "return:" msgstr "" -#: src/glossary.md:85 +#: src/glossary.md:90 #, fuzzy msgid "Rust:" msgstr "Rustdoc" -#: src/glossary.md:86 +#: src/glossary.md:91 msgid "" "Rust Fundamentals: \n" "Days 1 to 3 of this course." msgstr "" -#: src/glossary.md:88 +#: src/glossary.md:93 msgid "" "Rust in Android: \n" "See [Rust in Android](android.md)." msgstr "" -#: src/glossary.md:90 +#: src/glossary.md:95 msgid "safe:" msgstr "" -#: src/glossary.md:91 +#: src/glossary.md:96 msgid "scope:" msgstr "" -#: src/glossary.md:92 +#: src/glossary.md:97 #, fuzzy msgid "standard library:" msgstr "کتابخانه‌های استاندارد" -#: src/glossary.md:93 +#: src/glossary.md:98 msgid "static:" msgstr "" -#: src/glossary.md:94 -#, fuzzy -msgid "string:" -msgstr "String" +#: src/glossary.md:99 +msgid "" +"string: \n" +"A data type storing textual data. See [`String` vs `str`](basic-syntax/" +"string-slices.html) for more." +msgstr "" -#: src/glossary.md:95 +#: src/glossary.md:102 #, fuzzy msgid "struct:" msgstr "ساختارها" -#: src/glossary.md:96 +#: src/glossary.md:103 msgid "test:" msgstr "" -#: src/glossary.md:97 +#: src/glossary.md:104 #, fuzzy msgid "thread:" msgstr "تردها" -#: src/glossary.md:98 +#: src/glossary.md:105 msgid "thread safety:" msgstr "" -#: src/glossary.md:99 +#: src/glossary.md:106 #, fuzzy msgid "trait:" msgstr "صفت‌ها" -#: src/glossary.md:100 +#: src/glossary.md:107 msgid "type:" msgstr "" -#: src/glossary.md:101 +#: src/glossary.md:108 #, fuzzy msgid "type inference:" msgstr "Type Inference" -#: src/glossary.md:102 +#: src/glossary.md:109 msgid "undefined behavior:" msgstr "" -#: src/glossary.md:103 +#: src/glossary.md:110 #, fuzzy msgid "union:" msgstr "Unions" -#: src/glossary.md:104 -#, fuzzy -msgid "unit test:" -msgstr "تست‌های واحد (Unit Tests)" +#: src/glossary.md:111 +msgid "" +"unit test: \n" +"Rust comes with built-in support for running small unit tests and larger " +"integration tests. See [Unit Tests](testing/unit-tests.html)." +msgstr "" -#: src/glossary.md:105 -msgid "unsafe:" +#: src/glossary.md:114 +msgid "" +"unsafe: \n" +"The subset of Rust which allows you to trigger _undefined behavior_. See " +"[Unsafe Rust](unsafe.html)." msgstr "" -#: src/glossary.md:106 -#, fuzzy -msgid "variable:\\" -msgstr "متغیرها" +#: src/glossary.md:117 +msgid "" +"variable: \n" +"A memory location storing data. Variables are valid in a _scope_." +msgstr "" #: src/other-resources.md:1 msgid "Other Rust Resources" @@ -17940,7 +16237,20 @@ msgid "" "rules, through implementing a few different types of list structures." msgstr "" -#: src/other-resources.md:63 +#: src/other-resources.md:62 +msgid "" +"[Rust Primer](https://app.codecrafters.io/collections/rust-primer): Key Rust " +"fundamentals, no fluff, aimed at experienced engineers." +msgstr "" + +#: src/other-resources.md:64 +msgid "" +"[CodeCrafters](https://app.codecrafters.io/tracks/rust): Recreate popular " +"devtools from scratch in Rust (e.g. Build your own BitTorrent, Git, Docker, " +"etc)" +msgstr "" + +#: src/other-resources.md:67 msgid "" "Please see the [Little Book of Rust Books](https://lborb.github.io/book/) " "for even more Rust books." @@ -18022,58 +16332,13 @@ msgstr "" msgid "([back to exercise](for-loops.md))" msgstr "" -#: src/exercises/day-1/solutions-morning.md:7 -msgid "" -"```rust\n" -"fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {\n" -" let mut result = [[0; 3]; 3];\n" -" for i in 0..3 {\n" -" for j in 0..3 {\n" -" result[j][i] = matrix[i][j];\n" -" }\n" -" }\n" -" return result;\n" -"}\n" -"\n" -"fn pretty_print(matrix: &[[i32; 3]; 3]) {\n" -" for row in matrix {\n" -" println!(\"{row:?}\");\n" -" }\n" -"}\n" -"\n" -"#[test]\n" -"fn test_transpose() {\n" -" let matrix = [\n" -" [101, 102, 103], //\n" -" [201, 202, 203],\n" -" [301, 302, 303],\n" -" ];\n" -" let transposed = transpose(matrix);\n" -" assert_eq!(\n" -" transposed,\n" -" [\n" -" [101, 201, 301], //\n" -" [102, 202, 302],\n" -" [103, 203, 303],\n" -" ]\n" -" );\n" -"}\n" -"\n" -"fn main() {\n" -" let matrix = [\n" -" [101, 102, 103], // <-- the comment makes rustfmt add a newline\n" -" [201, 202, 203],\n" -" [301, 302, 303],\n" -" ];\n" -"\n" -" println!(\"matrix:\");\n" -" pretty_print(&matrix);\n" -"\n" -" let transposed = transpose(matrix);\n" -" println!(\"transposed:\");\n" -" pretty_print(&transposed);\n" -"}\n" -"```" +#: src/exercises/day-1/solutions-morning.md:20 +msgid "\"{row:?}\"" +msgstr "" + +#: src/exercises/day-1/solutions-morning.md:27 +#: src/exercises/day-1/solutions-morning.md:35 +msgid "//\n" msgstr "" #: src/exercises/day-1/solutions-morning.md:57 @@ -18102,34 +16367,24 @@ msgid "" "abstract over anything that can be referenced as a slice." msgstr "" -#: src/exercises/day-1/solutions-morning.md:65 -msgid "" -"```rust\n" -"use std::convert::AsRef;\n" -"use std::fmt::Debug;\n" -"\n" -"fn pretty_print(matrix: Matrix)\n" -"where\n" -" T: Debug,\n" -" // A line references a slice of items\n" -" Line: AsRef<[T]>,\n" -" // A matrix references a slice of lines\n" -" Matrix: AsRef<[Line]>\n" -"{\n" -" for row in matrix.as_ref() {\n" -" println!(\"{:?}\", row.as_ref());\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" // &[&[i32]]\n" -" pretty_print(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]);\n" -" // [[&str; 2]; 2]\n" -" pretty_print([[\"a\", \"b\"], [\"c\", \"d\"]]);\n" -" // Vec>\n" -" pretty_print(vec![vec![1, 2], vec![3, 4]]);\n" -"}\n" -"```" +#: src/exercises/day-1/solutions-morning.md:72 +msgid "// A line references a slice of items" +msgstr "" + +#: src/exercises/day-1/solutions-morning.md:74 +msgid "// A matrix references a slice of lines" +msgstr "" + +#: src/exercises/day-1/solutions-morning.md:83 +msgid "// &[&[i32]]" +msgstr "" + +#: src/exercises/day-1/solutions-morning.md:85 +msgid "// [[&str; 2]; 2]" +msgstr "" + +#: src/exercises/day-1/solutions-morning.md:87 +msgid "// Vec>" msgstr "" #: src/exercises/day-1/solutions-morning.md:92 @@ -18146,222 +16401,25 @@ msgstr "" msgid "([back to exercise](luhn.md))" msgstr "" -#: src/exercises/day-1/solutions-afternoon.md:7 -msgid "" -"```rust\n" -"pub fn luhn(cc_number: &str) -> bool {\n" -" let mut sum = 0;\n" -" let mut double = false;\n" -" let mut digit_seen = 0;\n" -"\n" -" for c in cc_number.chars().filter(|&f| f != ' ').rev() {\n" -" if let Some(digit) = c.to_digit(10) {\n" -" if double {\n" -" let double_digit = digit * 2;\n" -" sum += if double_digit > 9 {\n" -" double_digit - 9\n" -" } else {\n" -" double_digit\n" -" };\n" -" } else {\n" -" sum += digit;\n" -" }\n" -" double = !double;\n" -" digit_seen += 1;\n" -" } else {\n" -" return false;\n" -" }\n" -" }\n" -"\n" -" if digit_seen < 2 {\n" -" return false;\n" -" }\n" -"\n" -" sum % 10 == 0\n" -"}\n" -"\n" -"fn main() {\n" -" let cc_number = \"1234 5678 1234 5670\";\n" -" println!(\n" -" \"Is {cc_number} a valid credit card number? {}\",\n" -" if luhn(cc_number) { \"yes\" } else { \"no\" }\n" -" );\n" -"}\n" -"\n" -"#[test]\n" -"fn test_non_digit_cc_number() {\n" -" assert!(!luhn(\"foo\"));\n" -" assert!(!luhn(\"foo 0 0\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_empty_cc_number() {\n" -" assert!(!luhn(\"\"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_single_digit_cc_number() {\n" -" assert!(!luhn(\"0\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_two_digit_cc_number() {\n" -" assert!(luhn(\" 0 0 \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_valid_cc_number() {\n" -" assert!(luhn(\"4263 9826 4026 9299\"));\n" -" assert!(luhn(\"4539 3195 0343 6467\"));\n" -" assert!(luhn(\"7992 7398 713\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_invalid_cc_number() {\n" -" assert!(!luhn(\"4223 9826 4026 9299\"));\n" -" assert!(!luhn(\"4539 3195 0343 6476\"));\n" -" assert!(!luhn(\"8273 1232 7352 0569\"));\n" -"}\n" -"```" +#: src/exercises/day-1/solutions-afternoon.md:40 +msgid "\"1234 5678 1234 5670\"" +msgstr "" + +#: src/exercises/day-1/solutions-afternoon.md:42 +msgid "\"Is {cc_number} a valid credit card number? {}\"" msgstr "" #: src/exercises/day-1/solutions-afternoon.md:86 #, fuzzy msgid "Pattern matching" msgstr "تطبیق الگو" - -#: src/exercises/day-1/solutions-afternoon.md:88 -msgid "" -"```rust\n" -"/// An operation to perform on two subexpressions.\n" -"#[derive(Debug)]\n" -"enum Operation {\n" -" Add,\n" -" Sub,\n" -" Mul,\n" -" Div,\n" -"}\n" -"\n" -"/// An expression, in tree form.\n" -"#[derive(Debug)]\n" -"enum Expression {\n" -" /// An operation on two subexpressions.\n" -" Op {\n" -" op: Operation,\n" -" left: Box,\n" -" right: Box,\n" -" },\n" -"\n" -" /// A literal value\n" -" Value(i64),\n" -"}\n" -"\n" -"/// The result of evaluating an expression.\n" -"#[derive(Debug, PartialEq, Eq)]\n" -"enum Res {\n" -" /// Evaluation was successful, with the given result.\n" -" Ok(i64),\n" -" /// Evaluation failed, with the given error message.\n" -" Err(String),\n" -"}\n" -"// Allow `Ok` and `Err` as shorthands for `Res::Ok` and `Res::Err`.\n" -"use Res::{Err, Ok};\n" -"\n" -"fn eval(e: Expression) -> Res {\n" -" match e {\n" -" Expression::Op { op, left, right } => {\n" -" let left = match eval(*left) {\n" -" Ok(v) => v,\n" -" Err(msg) => return Err(msg),\n" -" };\n" -" let right = match eval(*right) {\n" -" Ok(v) => v,\n" -" Err(msg) => return Err(msg),\n" -" };\n" -" Ok(match op {\n" -" Operation::Add => left + right,\n" -" Operation::Sub => left - right,\n" -" Operation::Mul => left * right,\n" -" Operation::Div => {\n" -" if right == 0 {\n" -" return Err(String::from(\"division by zero\"));\n" -" } else {\n" -" left / right\n" -" }\n" -" }\n" -" })\n" -" }\n" -" Expression::Value(v) => Ok(v),\n" -" }\n" -"}\n" -"\n" -"#[test]\n" -"fn test_value() {\n" -" assert_eq!(eval(Expression::Value(19)), Ok(19));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_sum() {\n" -" assert_eq!(\n" -" eval(Expression::Op {\n" -" op: Operation::Add,\n" -" left: Box::new(Expression::Value(10)),\n" -" right: Box::new(Expression::Value(20)),\n" -" }),\n" -" Ok(30)\n" -" );\n" -"}\n" -"\n" -"#[test]\n" -"fn test_recursion() {\n" -" let term1 = Expression::Op {\n" -" op: Operation::Mul,\n" -" left: Box::new(Expression::Value(10)),\n" -" right: Box::new(Expression::Value(9)),\n" -" };\n" -" let term2 = Expression::Op {\n" -" op: Operation::Mul,\n" -" left: Box::new(Expression::Op {\n" -" op: Operation::Sub,\n" -" left: Box::new(Expression::Value(3)),\n" -" right: Box::new(Expression::Value(4)),\n" -" }),\n" -" right: Box::new(Expression::Value(5)),\n" -" };\n" -" assert_eq!(\n" -" eval(Expression::Op {\n" -" op: Operation::Add,\n" -" left: Box::new(term1),\n" -" right: Box::new(term2),\n" -" }),\n" -" Ok(85)\n" -" );\n" -"}\n" -"\n" -"#[test]\n" -"fn test_error() {\n" -" assert_eq!(\n" -" eval(Expression::Op {\n" -" op: Operation::Div,\n" -" left: Box::new(Expression::Value(99)),\n" -" right: Box::new(Expression::Value(0)),\n" -" }),\n" -" Err(String::from(\"division by zero\"))\n" -" );\n" -"}\n" -"fn main() {\n" -" let expr = Expression::Op {\n" -" op: Operation::Sub,\n" -" left: Box::new(Expression::Value(20)),\n" -" right: Box::new(Expression::Value(10)),\n" -" };\n" -" println!(\"expr: {:?}\", expr);\n" -" println!(\"result: {:?}\", eval(expr));\n" -"}\n" -"```" + +#: src/exercises/day-1/solutions-afternoon.md:211 +msgid "\"expr: {:?}\"" +msgstr "" + +#: src/exercises/day-1/solutions-afternoon.md:212 +msgid "\"result: {:?}\"" msgstr "" #: src/exercises/day-2/solutions-morning.md:1 @@ -18376,281 +16434,28 @@ msgstr "" msgid "([back to exercise](book-library.md))" msgstr "" -#: src/exercises/day-2/solutions-morning.md:7 +#: src/exercises/day-2/solutions-morning.md:54 +msgid "\"{}, published in {}\"" +msgstr "" + +#: src/exercises/day-2/solutions-morning.md:59 msgid "" -"```rust\n" -"struct Library {\n" -" books: Vec,\n" -"}\n" -"\n" -"struct Book {\n" -" title: String,\n" -" year: u16,\n" -"}\n" -"\n" -"impl Book {\n" -" // This is a constructor, used below.\n" -" fn new(title: &str, year: u16) -> Book {\n" -" Book {\n" -" title: String::from(title),\n" -" year,\n" -" }\n" -" }\n" -"}\n" -"\n" -"// Implement the methods below. Notice how the `self` parameter\n" -"// changes type to indicate the method's required level of ownership\n" -"// over the object:\n" -"//\n" -"// - `&self` for shared read-only access,\n" -"// - `&mut self` for unique and mutable access,\n" -"// - `self` for unique access by value.\n" -"impl Library {\n" -"\n" -" fn new() -> Library {\n" -" Library { books: Vec::new() }\n" -" }\n" -"\n" -" fn len(&self) -> usize {\n" -" self.books.len()\n" -" }\n" -"\n" -" fn is_empty(&self) -> bool {\n" -" self.books.is_empty()\n" -" }\n" -"\n" -" fn add_book(&mut self, book: Book) {\n" -" self.books.push(book)\n" -" }\n" -"\n" -" fn print_books(&self) {\n" -" for book in &self.books {\n" -" println!(\"{}, published in {}\", book.title, book.year);\n" -" }\n" -" }\n" -"\n" -" fn oldest_book(&self) -> Option<&Book> {\n" -" // Using a closure and a built-in method:\n" +"// Using a closure and a built-in method:\n" " // self.books.iter().min_by_key(|book| book.year)\n" -"\n" -" // Longer hand-written solution:\n" -" let mut oldest: Option<&Book> = None;\n" -" for book in self.books.iter() {\n" -" if oldest.is_none() || book.year < oldest.unwrap().year {\n" -" oldest = Some(book);\n" -" }\n" -" }\n" -"\n" -" oldest\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let mut library = Library::new();\n" -"\n" -" println!(\n" -" \"The library is empty: library.is_empty() -> {}\",\n" -" library.is_empty()\n" -" );\n" -"\n" -" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n" -" library.add_book(Book::new(\"Alice's Adventures in Wonderland\", " -"1865));\n" -"\n" -" println!(\n" -" \"The library is no longer empty: library.is_empty() -> {}\",\n" -" library.is_empty()\n" -" );\n" -"\n" -" library.print_books();\n" -"\n" -" match library.oldest_book() {\n" -" Some(book) => println!(\"The oldest book is {}\", book.title),\n" -" None => println!(\"The library is empty!\"),\n" -" }\n" -"\n" -" println!(\"The library has {} books\", library.len());\n" -" library.print_books();\n" -"}\n" -"\n" -"#[test]\n" -"fn test_library_len() {\n" -" let mut library = Library::new();\n" -" assert_eq!(library.len(), 0);\n" -" assert!(library.is_empty());\n" -"\n" -" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n" -" library.add_book(Book::new(\"Alice's Adventures in Wonderland\", " -"1865));\n" -" assert_eq!(library.len(), 2);\n" -" assert!(!library.is_empty());\n" -"}\n" -"\n" -"#[test]\n" -"fn test_library_is_empty() {\n" -" let mut library = Library::new();\n" -" assert!(library.is_empty());\n" -"\n" -" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n" -" assert!(!library.is_empty());\n" -"}\n" -"\n" -"#[test]\n" -"fn test_library_print_books() {\n" -" let mut library = Library::new();\n" -" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n" -" library.add_book(Book::new(\"Alice's Adventures in Wonderland\", " -"1865));\n" -" // We could try and capture stdout, but let us just call the\n" -" // method to start with.\n" -" library.print_books();\n" -"}\n" -"\n" -"#[test]\n" -"fn test_library_oldest_book() {\n" -" let mut library = Library::new();\n" -" assert!(library.oldest_book().is_none());\n" -"\n" -" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n" -" assert_eq!(\n" -" library.oldest_book().map(|b| b.title.as_str()),\n" -" Some(\"Lord of the Rings\")\n" -" );\n" -"\n" -" library.add_book(Book::new(\"Alice's Adventures in Wonderland\", " -"1865));\n" -" assert_eq!(\n" -" library.oldest_book().map(|b| b.title.as_str()),\n" -" Some(\"Alice's Adventures in Wonderland\")\n" -" );\n" -"}\n" -"```" msgstr "" -#: src/exercises/day-2/solutions-morning.md:153 -msgid "([back to exercise](health-statistics.md))" +#: src/exercises/day-2/solutions-morning.md:62 +msgid "// Longer hand-written solution:\n" msgstr "" -#: src/exercises/day-2/solutions-morning.md:155 +#: src/exercises/day-2/solutions-morning.md:127 msgid "" -"```rust\n" -"pub struct User {\n" -" name: String,\n" -" age: u32,\n" -" height: f32,\n" -" visit_count: usize,\n" -" last_blood_pressure: Option<(u32, u32)>,\n" -"}\n" -"\n" -"pub struct Measurements {\n" -" height: f32,\n" -" blood_pressure: (u32, u32),\n" -"}\n" -"\n" -"pub struct HealthReport<'a> {\n" -" patient_name: &'a str,\n" -" visit_count: u32,\n" -" height_change: f32,\n" -" blood_pressure_change: Option<(i32, i32)>,\n" -"}\n" -"\n" -"impl User {\n" -" pub fn new(name: String, age: u32, height: f32) -> Self {\n" -" Self {\n" -" name,\n" -" age,\n" -" height,\n" -" visit_count: 0,\n" -" last_blood_pressure: None,\n" -" }\n" -" }\n" -"\n" -" pub fn name(&self) -> &str {\n" -" &self.name\n" -" }\n" -"\n" -" pub fn age(&self) -> u32 {\n" -" self.age\n" -" }\n" -"\n" -" pub fn height(&self) -> f32 {\n" -" self.height\n" -" }\n" -"\n" -" pub fn doctor_visits(&self) -> u32 {\n" -" self.visit_count as u32\n" -" }\n" -"\n" -" pub fn set_age(&mut self, new_age: u32) {\n" -" self.age = new_age\n" -" }\n" -"\n" -" pub fn set_height(&mut self, new_height: f32) {\n" -" self.height = new_height\n" -" }\n" -"\n" -" pub fn visit_doctor(&mut self, measurements: Measurements) -> " -"HealthReport {\n" -" self.visit_count += 1;\n" -" let bp = measurements.blood_pressure;\n" -" let report = HealthReport {\n" -" patient_name: &self.name,\n" -" visit_count: self.visit_count as u32,\n" -" height_change: measurements.height - self.height,\n" -" blood_pressure_change: match self.last_blood_pressure {\n" -" Some(lbp) => Some((\n" -" bp.0 as i32 - lbp.0 as i32,\n" -" bp.1 as i32 - lbp.1 as i32\n" -" )),\n" -" None => None,\n" -" }\n" -" };\n" -" self.height = measurements.height;\n" -" self.last_blood_pressure = Some(bp);\n" -" report\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let bob = User::new(String::from(\"Bob\"), 32, 155.2);\n" -" println!(\"I'm {} and my age is {}\", bob.name(), bob.age());\n" -"}\n" -"\n" -"#[test]\n" -"fn test_height() {\n" -" let bob = User::new(String::from(\"Bob\"), 32, 155.2);\n" -" assert_eq!(bob.height(), 155.2);\n" -"}\n" -"\n" -"#[test]\n" -"fn test_set_age() {\n" -" let mut bob = User::new(String::from(\"Bob\"), 32, 155.2);\n" -" assert_eq!(bob.age(), 32);\n" -" bob.set_age(33);\n" -" assert_eq!(bob.age(), 33);\n" -"}\n" -"\n" -"#[test]\n" -"fn test_visit() {\n" -" let mut bob = User::new(String::from(\"Bob\"), 32, 155.2);\n" -" assert_eq!(bob.doctor_visits(), 0);\n" -" let report = bob.visit_doctor(Measurements {\n" -" height: 156.1,\n" -" blood_pressure: (120, 80),\n" -" });\n" -" assert_eq!(report.patient_name, \"Bob\");\n" -" assert_eq!(report.visit_count, 1);\n" -" assert_eq!(report.blood_pressure_change, None);\n" -"\n" -" let report = bob.visit_doctor(Measurements {\n" -" height: 156.1,\n" -" blood_pressure: (115, 76),\n" -" });\n" -"\n" -" assert_eq!(report.visit_count, 2);\n" -" assert_eq!(report.blood_pressure_change, Some((-5, -4)));\n" -"}\n" -"```" +"// We could try and capture stdout, but let us just call the\n" +" // method to start with.\n" +msgstr "" + +#: src/exercises/day-2/solutions-morning.md:153 +msgid "([back to exercise](health-statistics.md))" msgstr "" #: src/exercises/day-2/solutions-afternoon.md:1 @@ -18661,24 +16466,18 @@ msgstr "" msgid "([back to exercise](strings-iterators.md))" msgstr "" -#: src/exercises/day-2/solutions-afternoon.md:7 +#: src/exercises/day-2/solutions-afternoon.md:10 +#: src/exercises/day-2/solutions-afternoon.md:12 +msgid "'/'" +msgstr "" + +#: src/exercises/day-2/solutions-afternoon.md:16 +msgid "\"*\"" +msgstr "" + +#: src/exercises/day-2/solutions-afternoon.md:22 msgid "" -"```rust\n" -"pub fn prefix_matches(prefix: &str, request_path: &str) -> bool {\n" -"\n" -" let mut request_segments = request_path.split('/');\n" -"\n" -" for prefix_segment in prefix.split('/') {\n" -" let Some(request_segment) = request_segments.next() else {\n" -" return false;\n" -" };\n" -" if request_segment != prefix_segment && prefix_segment != \"*\" {\n" -" return false;\n" -" }\n" -" }\n" -" true\n" -"\n" -" // Alternatively, Iterator::zip() lets us iterate simultaneously over " +"// Alternatively, Iterator::zip() lets us iterate simultaneously over " "prefix\n" " // and request segments. The zip() iterator is finished as soon as one " "of\n" @@ -18689,47 +16488,6 @@ msgid "" " // to produce an iterator that returns Some(str) for each pattern " "segments,\n" " // and then returns None indefinitely.\n" -"}\n" -"\n" -"#[test]\n" -"fn test_matches_without_wildcard() {\n" -" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers\"));\n" -" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/" -"abc-123\"));\n" -" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/abc/" -"books\"));\n" -"\n" -" assert!(!prefix_matches(\"/v1/publishers\", \"/v1\"));\n" -" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/publishersBooks\"));\n" -" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/parent/" -"publishers\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_matches_with_wildcard() {\n" -" assert!(prefix_matches(\n" -" \"/v1/publishers/*/books\",\n" -" \"/v1/publishers/foo/books\"\n" -" ));\n" -" assert!(prefix_matches(\n" -" \"/v1/publishers/*/books\",\n" -" \"/v1/publishers/bar/books\"\n" -" ));\n" -" assert!(prefix_matches(\n" -" \"/v1/publishers/*/books\",\n" -" \"/v1/publishers/foo/books/book1\"\n" -" ));\n" -"\n" -" assert!(!prefix_matches(\"/v1/publishers/*/books\", \"/v1/" -"publishers\"));\n" -" assert!(!prefix_matches(\n" -" \"/v1/publishers/*/books\",\n" -" \"/v1/publishers/foo/booksByAuthor\"\n" -" ));\n" -"}\n" -"\n" -"fn main() {}\n" -"```" msgstr "" #: src/exercises/day-3/solutions-morning.md:1 @@ -18740,230 +16498,54 @@ msgstr "" msgid "([back to exercise](simple-gui.md))" msgstr "" -#: src/exercises/day-3/solutions-morning.md:7 +#: src/exercises/day-3/solutions-morning.md:75 +msgid "// Add 4 paddings for borders\n" +msgstr "" + +#: src/exercises/day-3/solutions-morning.md:87 msgid "" -"```rust\n" -"pub trait Widget {\n" -" /// Natural width of `self`.\n" -" fn width(&self) -> usize;\n" -"\n" -" /// Draw the widget into a buffer.\n" -" fn draw_into(&self, buffer: &mut dyn std::fmt::Write);\n" -"\n" -" /// Draw the widget on standard output.\n" -" fn draw(&self) {\n" -" let mut buffer = String::new();\n" -" self.draw_into(&mut buffer);\n" -" println!(\"{buffer}\");\n" -" }\n" -"}\n" -"\n" -"pub struct Label {\n" -" label: String,\n" -"}\n" -"\n" -"impl Label {\n" -" fn new(label: &str) -> Label {\n" -" Label {\n" -" label: label.to_owned(),\n" -" }\n" -" }\n" -"}\n" -"\n" -"pub struct Button {\n" -" label: Label,\n" -"}\n" -"\n" -"impl Button {\n" -" fn new(label: &str) -> Button {\n" -" Button {\n" -" label: Label::new(label),\n" -" }\n" -" }\n" -"}\n" -"\n" -"pub struct Window {\n" -" title: String,\n" -" widgets: Vec>,\n" -"}\n" -"\n" -"impl Window {\n" -" fn new(title: &str) -> Window {\n" -" Window {\n" -" title: title.to_owned(),\n" -" widgets: Vec::new(),\n" -" }\n" -" }\n" -"\n" -" fn add_widget(&mut self, widget: Box) {\n" -" self.widgets.push(widget);\n" -" }\n" -"\n" -" fn inner_width(&self) -> usize {\n" -" std::cmp::max(\n" -" self.title.chars().count(),\n" -" self.widgets.iter().map(|w| w.width()).max().unwrap_or(0),\n" -" )\n" -" }\n" -"}\n" -"\n" -"\n" -"impl Widget for Window {\n" -" fn width(&self) -> usize {\n" -" // Add 4 paddings for borders\n" -" self.inner_width() + 4\n" -" }\n" -"\n" -" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n" -" let mut inner = String::new();\n" -" for widget in &self.widgets {\n" -" widget.draw_into(&mut inner);\n" -" }\n" -"\n" -" let inner_width = self.inner_width();\n" -"\n" -" // TODO: after learning about error handling, you can change\n" +"// TODO: after learning about error handling, you can change\n" " // draw_into to return Result<(), std::fmt::Error>. Then use\n" " // the ?-operator here instead of .unwrap().\n" -" writeln!(buffer, \"+-{:- usize {\n" -" self.label.width() + 8 // add a bit of padding\n" -" }\n" -"\n" -" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n" -" let width = self.width();\n" -" let mut label = String::new();\n" -" self.label.draw_into(&mut label);\n" -"\n" -" writeln!(buffer, \"+{:- usize {\n" -" self.label\n" -" .lines()\n" -" .map(|line| line.chars().count())\n" -" .max()\n" -" .unwrap_or(0)\n" -" }\n" -"\n" -" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n" -" writeln!(buffer, \"{}\", &self.label).unwrap();\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let mut window = Window::new(\"Rust GUI Demo 1.23\");\n" -" window.add_widget(Box::new(Label::new(\"This is a small text GUI demo." -"\")));\n" -" window.add_widget(Box::new(Button::new(\n" -" \"Click me!\"\n" -" )));\n" -" window.draw();\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/day-3/solutions-morning.md:90 +#: src/exercises/day-3/solutions-morning.md:96 +msgid "\"+-{:- Point {\n" -" Point { x, y }\n" -" }\n" -"\n" -" pub fn magnitude(self) -> f64 {\n" -" f64::from(self.x.pow(2) + self.y.pow(2)).sqrt()\n" -" }\n" -"\n" -" pub fn dist(self, other: Point) -> f64 {\n" -" (self - other).magnitude()\n" -" }\n" -"}\n" -"\n" -"impl std::ops::Add for Point {\n" -" type Output = Self;\n" -"\n" -" fn add(self, other: Self) -> Self::Output {\n" -" Self {\n" -" x: self.x + other.x,\n" -" y: self.y + other.y,\n" -" }\n" -" }\n" -"}\n" -"\n" -"impl std::ops::Sub for Point {\n" -" type Output = Self;\n" -"\n" -" fn sub(self, other: Self) -> Self::Output {\n" -" Self {\n" -" x: self.x - other.x,\n" -" y: self.y - other.y,\n" -" }\n" -" }\n" -"}\n" -"\n" -"pub struct Polygon {\n" -" points: Vec,\n" -"}\n" -"\n" -"impl Polygon {\n" -" pub fn new() -> Polygon {\n" -" Polygon { points: Vec::new() }\n" -" }\n" -"\n" -" pub fn add_point(&mut self, point: Point) {\n" -" self.points.push(point);\n" -" }\n" -"\n" -" pub fn left_most_point(&self) -> Option {\n" -" self.points.iter().min_by_key(|p| p.x).copied()\n" -" }\n" -"\n" -" pub fn iter(&self) -> impl Iterator {\n" -" self.points.iter()\n" -" }\n" -"\n" -" pub fn length(&self) -> f64 {\n" -" if self.points.is_empty() {\n" -" return 0.0;\n" -" }\n" -"\n" -" let mut result = 0.0;\n" -" let mut last_point = self.points[0];\n" -" for point in &self.points[1..] {\n" -" result += last_point.dist(*point);\n" -" last_point = *point;\n" -" }\n" -" result += last_point.dist(self.points[0]);\n" -" result\n" -" // Alternatively, Iterator::zip() lets us iterate over the points as " -"pairs\n" +"// Alternatively, Iterator::zip() lets us iterate over the points as pairs\n" " // but we need to pair each point with the next one, and the last " "point\n" " // with the first point. The zip() iterator is finished as soon as " @@ -18973,127 +16555,6 @@ msgid "" " // with Iterator::skip to create the second iterator for the zip and " "using map \n" " // and sum to calculate the total length.\n" -" }\n" -"}\n" -"\n" -"pub struct Circle {\n" -" center: Point,\n" -" radius: i32,\n" -"}\n" -"\n" -"impl Circle {\n" -" pub fn new(center: Point, radius: i32) -> Circle {\n" -" Circle { center, radius }\n" -" }\n" -"\n" -" pub fn circumference(&self) -> f64 {\n" -" 2.0 * std::f64::consts::PI * f64::from(self.radius)\n" -" }\n" -"\n" -" pub fn dist(&self, other: &Self) -> f64 {\n" -" self.center.dist(other.center)\n" -" }\n" -"}\n" -"\n" -"pub enum Shape {\n" -" Polygon(Polygon),\n" -" Circle(Circle),\n" -"}\n" -"\n" -"impl From for Shape {\n" -" fn from(poly: Polygon) -> Self {\n" -" Shape::Polygon(poly)\n" -" }\n" -"}\n" -"\n" -"impl From for Shape {\n" -" fn from(circle: Circle) -> Self {\n" -" Shape::Circle(circle)\n" -" }\n" -"}\n" -"\n" -"impl Shape {\n" -" pub fn perimeter(&self) -> f64 {\n" -" match self {\n" -" Shape::Polygon(poly) => poly.length(),\n" -" Shape::Circle(circle) => circle.circumference(),\n" -" }\n" -" }\n" -"}\n" -"\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::*;\n" -"\n" -" fn round_two_digits(x: f64) -> f64 {\n" -" (x * 100.0).round() / 100.0\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_magnitude() {\n" -" let p1 = Point::new(12, 13);\n" -" assert_eq!(round_two_digits(p1.magnitude()), 17.69);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_dist() {\n" -" let p1 = Point::new(10, 10);\n" -" let p2 = Point::new(14, 13);\n" -" assert_eq!(round_two_digits(p1.dist(p2)), 5.00);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_add() {\n" -" let p1 = Point::new(16, 16);\n" -" let p2 = p1 + Point::new(-4, 3);\n" -" assert_eq!(p2, Point::new(12, 19));\n" -" }\n" -"\n" -" #[test]\n" -" fn test_polygon_left_most_point() {\n" -" let p1 = Point::new(12, 13);\n" -" let p2 = Point::new(16, 16);\n" -"\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(p1);\n" -" poly.add_point(p2);\n" -" assert_eq!(poly.left_most_point(), Some(p1));\n" -" }\n" -"\n" -" #[test]\n" -" fn test_polygon_iter() {\n" -" let p1 = Point::new(12, 13);\n" -" let p2 = Point::new(16, 16);\n" -"\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(p1);\n" -" poly.add_point(p2);\n" -"\n" -" let points = poly.iter().cloned().collect::>();\n" -" assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_shape_perimeters() {\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(Point::new(12, 13));\n" -" poly.add_point(Point::new(17, 11));\n" -" poly.add_point(Point::new(16, 16));\n" -" let shapes = vec![\n" -" Shape::from(poly),\n" -" Shape::from(Circle::new(Point::new(10, 20), 5)),\n" -" ];\n" -" let perimeters = shapes\n" -" .iter()\n" -" .map(Shape::perimeter)\n" -" .map(round_two_digits)\n" -" .collect::>();\n" -" assert_eq!(perimeters, vec![15.48, 31.42]);\n" -" }\n" -"}\n" -"\n" -"fn main() {}\n" -"```" msgstr "" #: src/exercises/day-3/solutions-afternoon.md:1 @@ -19104,172 +16565,91 @@ msgstr "" msgid "([back to exercise](safe-ffi-wrapper.md))" msgstr "" -#: src/exercises/day-3/solutions-afternoon.md:7 +#: src/exercises/day-3/solutions-afternoon.md:75 msgid "" -"```rust\n" -"mod ffi {\n" -" use std::os::raw::{c_char, c_int};\n" -" #[cfg(not(target_os = \"macos\"))]\n" -" use std::os::raw::{c_long, c_ulong, c_ushort, c_uchar};\n" -"\n" -" // Opaque type. See https://doc.rust-lang.org/nomicon/ffi.html.\n" -" #[repr(C)]\n" -" pub struct DIR {\n" -" _data: [u8; 0],\n" -" _marker: core::marker::PhantomData<(*mut u8, core::marker::" -"PhantomPinned)>,\n" -" }\n" -"\n" -" // Layout according to the Linux man page for readdir(3), where ino_t " -"and\n" -" // off_t are resolved according to the definitions in\n" -" // /usr/include/x86_64-linux-gnu/{sys/types.h, bits/typesizes.h}.\n" -" #[cfg(not(target_os = \"macos\"))]\n" -" #[repr(C)]\n" -" pub struct dirent {\n" -" pub d_ino: c_ulong,\n" -" pub d_off: c_long,\n" -" pub d_reclen: c_ushort,\n" -" pub d_type: c_uchar,\n" -" pub d_name: [c_char; 256],\n" -" }\n" -"\n" -" // Layout according to the macOS man page for dir(5).\n" -" #[cfg(all(target_os = \"macos\"))]\n" -" #[repr(C)]\n" -" pub struct dirent {\n" -" pub d_fileno: u64,\n" -" pub d_seekoff: u64,\n" -" pub d_reclen: u16,\n" -" pub d_namlen: u16,\n" -" pub d_type: u8,\n" -" pub d_name: [c_char; 1024],\n" -" }\n" -"\n" -" extern \"C\" {\n" -" pub fn opendir(s: *const c_char) -> *mut DIR;\n" -"\n" -" #[cfg(not(all(target_os = \"macos\", target_arch = \"x86_64\")))]\n" -" pub fn readdir(s: *mut DIR) -> *const dirent;\n" -"\n" -" // See https://github.com/rust-lang/libc/issues/414 and the section " -"on\n" -" // _DARWIN_FEATURE_64_BIT_INODE in the macOS man page for stat(2).\n" -" //\n" -" // \"Platforms that existed before these updates were available\" " -"refers\n" -" // to macOS (as opposed to iOS / wearOS / etc.) on Intel and " -"PowerPC.\n" -" #[cfg(all(target_os = \"macos\", target_arch = \"x86_64\"))]\n" -" #[link_name = \"readdir$INODE64\"]\n" -" pub fn readdir(s: *mut DIR) -> *const dirent;\n" -"\n" -" pub fn closedir(s: *mut DIR) -> c_int;\n" -" }\n" -"}\n" -"\n" -"use std::ffi::{CStr, CString, OsStr, OsString};\n" -"use std::os::unix::ffi::OsStrExt;\n" -"\n" -"#[derive(Debug)]\n" -"struct DirectoryIterator {\n" -" path: CString,\n" -" dir: *mut ffi::DIR,\n" -"}\n" -"\n" -"impl DirectoryIterator {\n" -" fn new(path: &str) -> Result {\n" -" // Call opendir and return a Ok value if that worked,\n" +"// Call opendir and return a Ok value if that worked,\n" " // otherwise return Err with a message.\n" -" let path = CString::new(path).map_err(|err| format!(\"Invalid path: " -"{err}\"))?;\n" -" // SAFETY: path.as_ptr() cannot be NULL.\n" -" let dir = unsafe { ffi::opendir(path.as_ptr()) };\n" -" if dir.is_null() {\n" -" Err(format!(\"Could not open {:?}\", path))\n" -" } else {\n" -" Ok(DirectoryIterator { path, dir })\n" -" }\n" -" }\n" -"}\n" -"\n" -"impl Iterator for DirectoryIterator {\n" -" type Item = OsString;\n" -" fn next(&mut self) -> Option {\n" -" // Keep calling readdir until we get a NULL pointer back.\n" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:77 +msgid "\"Invalid path: {err}\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:78 +msgid "// SAFETY: path.as_ptr() cannot be NULL.\n" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:81 +msgid "\"Could not open {:?}\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:91 +msgid "" +"// Keep calling readdir until we get a NULL pointer back.\n" " // SAFETY: self.dir is never NULL.\n" -" let dirent = unsafe { ffi::readdir(self.dir) };\n" -" if dirent.is_null() {\n" -" // We have reached the end of the directory.\n" -" return None;\n" -" }\n" -" // SAFETY: dirent is not NULL and dirent.d_name is NUL\n" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:95 +msgid "// We have reached the end of the directory.\n" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:98 +msgid "" +"// SAFETY: dirent is not NULL and dirent.d_name is NUL\n" " // terminated.\n" -" let d_name = unsafe { CStr::from_ptr((*dirent).d_name.as_ptr()) };\n" -" let os_str = OsStr::from_bytes(d_name.to_bytes());\n" -" Some(os_str.to_owned())\n" -" }\n" -"}\n" -"\n" -"impl Drop for DirectoryIterator {\n" -" fn drop(&mut self) {\n" -" // Call closedir as needed.\n" -" if !self.dir.is_null() {\n" -" // SAFETY: self.dir is not NULL.\n" -" if unsafe { ffi::closedir(self.dir) } != 0 {\n" -" panic!(\"Could not close {:?}\", self.path);\n" -" }\n" -" }\n" -" }\n" -"}\n" -"\n" -"fn main() -> Result<(), String> {\n" -" let iter = DirectoryIterator::new(\".\")?;\n" -" println!(\"files: {:#?}\", iter.collect::>());\n" -" Ok(())\n" -"}\n" -"\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::*;\n" -" use std::error::Error;\n" -"\n" -" #[test]\n" -" fn test_nonexisting_directory() {\n" -" let iter = DirectoryIterator::new(\"no-such-directory\");\n" -" assert!(iter.is_err());\n" -" }\n" -"\n" -" #[test]\n" -" fn test_empty_directory() -> Result<(), Box> {\n" -" let tmp = tempfile::TempDir::new()?;\n" -" let iter = DirectoryIterator::new(\n" -" tmp.path().to_str().ok_or(\"Non UTF-8 character in path\")?,\n" -" )?;\n" -" let mut entries = iter.collect::>();\n" -" entries.sort();\n" -" assert_eq!(entries, &[\".\", \"..\"]);\n" -" Ok(())\n" -" }\n" -"\n" -" #[test]\n" -" fn test_nonempty_directory() -> Result<(), Box> {\n" -" let tmp = tempfile::TempDir::new()?;\n" -" std::fs::write(tmp.path().join(\"foo.txt\"), \"The Foo " -"Diaries\\n\")?;\n" -" std::fs::write(tmp.path().join(\"bar.png\"), \"\\n\")?;\n" -" std::fs::write(tmp.path().join(\"crab.rs\"), \"//! Crab\\n\")?;\n" -" let iter = DirectoryIterator::new(\n" -" tmp.path().to_str().ok_or(\"Non UTF-8 character in path\")?,\n" -" )?;\n" -" let mut entries = iter.collect::>();\n" -" entries.sort();\n" -" assert_eq!(entries, &[\".\", \"..\", \"bar.png\", \"crab.rs\", \"foo." -"txt\"]);\n" -" Ok(())\n" -" }\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:108 +msgid "// Call closedir as needed.\n" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:110 +msgid "// SAFETY: self.dir is not NULL.\n" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:112 +msgid "\"Could not close {:?}\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:131 +msgid "\"no-such-directory\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:139 +#: src/exercises/day-3/solutions-afternoon.md:154 +msgid "\"Non UTF-8 character in path\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:143 +#: src/exercises/day-3/solutions-afternoon.md:158 +msgid "\"..\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:150 +#: src/exercises/day-3/solutions-afternoon.md:158 +msgid "\"foo.txt\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:150 +msgid "\"The Foo Diaries\\n\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:151 +#: src/exercises/day-3/solutions-afternoon.md:158 +msgid "\"bar.png\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:151 +msgid "\"\\n\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:152 +#: src/exercises/day-3/solutions-afternoon.md:158 +msgid "\"crab.rs\"" +msgstr "" + +#: src/exercises/day-3/solutions-afternoon.md:152 +msgid "\"//! Crab\\n\"" msgstr "" #: src/exercises/bare-metal/solutions-morning.md:1 @@ -19280,151 +16660,30 @@ msgstr "" msgid "([back to exercise](compass.md))" msgstr "" -#: src/exercises/bare-metal/solutions-morning.md:7 +#: src/exercises/bare-metal/solutions-morning.md:40 +msgid "// Set up the I2C controller and Inertial Measurement Unit.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-morning.md:41 +msgid "\"Setting up IMU...\"" +msgstr "" + +#: src/exercises/bare-metal/solutions-morning.md:49 +msgid "// Set up display and timer.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-morning.md:59 +msgid "// Read compass data and log it to the serial port.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-morning.md:67 +msgid "\"{},{},{}\\t{},{},{}\"" +msgstr "" + +#: src/exercises/bare-metal/solutions-morning.md:103 msgid "" -"```rust,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"extern crate panic_halt as _;\n" -"\n" -"use core::fmt::Write;\n" -"use cortex_m_rt::entry;\n" -"use core::cmp::{max, min};\n" -"use lsm303agr::{AccelOutputDataRate, Lsm303agr, MagOutputDataRate};\n" -"use microbit::display::blocking::Display;\n" -"use microbit::hal::prelude::*;\n" -"use microbit::hal::twim::Twim;\n" -"use microbit::hal::uarte::{Baudrate, Parity, Uarte};\n" -"use microbit::hal::Timer;\n" -"use microbit::pac::twim0::frequency::FREQUENCY_A;\n" -"use microbit::Board;\n" -"\n" -"const COMPASS_SCALE: i32 = 30000;\n" -"const ACCELEROMETER_SCALE: i32 = 700;\n" -"\n" -"#[entry]\n" -"fn main() -> ! {\n" -" let board = Board::take().unwrap();\n" -"\n" -" // Configure serial port.\n" -" let mut serial = Uarte::new(\n" -" board.UARTE0,\n" -" board.uart.into(),\n" -" Parity::EXCLUDED,\n" -" Baudrate::BAUD115200,\n" -" );\n" -"\n" -" // Set up the I2C controller and Inertial Measurement Unit.\n" -" writeln!(serial, \"Setting up IMU...\").unwrap();\n" -" let i2c = Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::" -"K100);\n" -" let mut imu = Lsm303agr::new_with_i2c(i2c);\n" -" imu.init().unwrap();\n" -" imu.set_mag_odr(MagOutputDataRate::Hz50).unwrap();\n" -" imu.set_accel_odr(AccelOutputDataRate::Hz50).unwrap();\n" -" let mut imu = imu.into_mag_continuous().ok().unwrap();\n" -"\n" -" // Set up display and timer.\n" -" let mut timer = Timer::new(board.TIMER0);\n" -" let mut display = Display::new(board.display_pins);\n" -"\n" -" let mut mode = Mode::Compass;\n" -" let mut button_pressed = false;\n" -"\n" -" writeln!(serial, \"Ready.\").unwrap();\n" -"\n" -" loop {\n" -" // Read compass data and log it to the serial port.\n" -" while !(imu.mag_status().unwrap().xyz_new_data\n" -" && imu.accel_status().unwrap().xyz_new_data)\n" -" {}\n" -" let compass_reading = imu.mag_data().unwrap();\n" -" let accelerometer_reading = imu.accel_data().unwrap();\n" -" writeln!(\n" -" serial,\n" -" \"{},{},{}\\t{},{},{}\",\n" -" compass_reading.x,\n" -" compass_reading.y,\n" -" compass_reading.z,\n" -" accelerometer_reading.x,\n" -" accelerometer_reading.y,\n" -" accelerometer_reading.z,\n" -" )\n" -" .unwrap();\n" -"\n" -" let mut image = [[0; 5]; 5];\n" -" let (x, y) = match mode {\n" -" Mode::Compass => (\n" -" scale(-compass_reading.x, -COMPASS_SCALE, COMPASS_SCALE, 0, " -"4) as usize,\n" -" scale(compass_reading.y, -COMPASS_SCALE, COMPASS_SCALE, 0, " -"4) as usize,\n" -" ),\n" -" Mode::Accelerometer => (\n" -" scale(\n" -" accelerometer_reading.x,\n" -" -ACCELEROMETER_SCALE,\n" -" ACCELEROMETER_SCALE,\n" -" 0,\n" -" 4,\n" -" ) as usize,\n" -" scale(\n" -" -accelerometer_reading.y,\n" -" -ACCELEROMETER_SCALE,\n" -" ACCELEROMETER_SCALE,\n" -" 0,\n" -" 4,\n" -" ) as usize,\n" -" ),\n" -" };\n" -" image[y][x] = 255;\n" -" display.show(&mut timer, image, 100);\n" -"\n" -" // If button A is pressed, switch to the next mode and briefly blink " -"all LEDs on.\n" -" if board.buttons.button_a.is_low().unwrap() {\n" -" if !button_pressed {\n" -" mode = mode.next();\n" -" display.show(&mut timer, [[255; 5]; 5], 200);\n" -" }\n" -" button_pressed = true;\n" -" } else {\n" -" button_pressed = false;\n" -" }\n" -" }\n" -"}\n" -"\n" -"#[derive(Copy, Clone, Debug, Eq, PartialEq)]\n" -"enum Mode {\n" -" Compass,\n" -" Accelerometer,\n" -"}\n" -"\n" -"impl Mode {\n" -" fn next(self) -> Self {\n" -" match self {\n" -" Self::Compass => Self::Accelerometer,\n" -" Self::Accelerometer => Self::Compass,\n" -" }\n" -" }\n" -"}\n" -"\n" -"fn scale(value: i32, min_in: i32, max_in: i32, min_out: i32, max_out: i32) -" -"> i32 {\n" -" let range_in = max_in - min_in;\n" -" let range_out = max_out - min_out;\n" -" cap(\n" -" min_out + range_out * (value - min_in) / range_in,\n" -" min_out,\n" -" max_out,\n" -" )\n" -"}\n" -"\n" -"fn cap(value: i32, min_value: i32, max_value: i32) -> i32 {\n" -" max(min_value, min(value, max_value))\n" -"}\n" -"```" +"// If button A is pressed, switch to the next mode and briefly blink all " +"LEDs on.\n" msgstr "" #: src/exercises/bare-metal/solutions-afternoon.md:5 @@ -19435,174 +16694,92 @@ msgstr "" msgid "_main.rs_:" msgstr "" -#: src/exercises/bare-metal/solutions-afternoon.md:9 +#: src/exercises/bare-metal/solutions-afternoon.md:36 +msgid "/// Base address of the PL031 RTC.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:38 +msgid "/// The IRQ used by the PL031 RTC.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:57 msgid "" -"```rust,compile_fail\n" -"#![no_main]\n" -"#![no_std]\n" -"\n" -"mod exceptions;\n" -"mod logger;\n" -"mod pl011;\n" -"mod pl031;\n" -"\n" -"use crate::pl031::Rtc;\n" -"use arm_gic::gicv3::{IntId, Trigger};\n" -"use arm_gic::{irq_enable, wfi};\n" -"use chrono::{TimeZone, Utc};\n" -"use core::hint::spin_loop;\n" -"use crate::pl011::Uart;\n" -"use arm_gic::gicv3::GicV3;\n" -"use core::panic::PanicInfo;\n" -"use log::{error, info, trace, LevelFilter};\n" -"use smccc::psci::system_off;\n" -"use smccc::Hvc;\n" -"\n" -"/// Base addresses of the GICv3.\n" -"const GICD_BASE_ADDRESS: *mut u64 = 0x800_0000 as _;\n" -"const GICR_BASE_ADDRESS: *mut u64 = 0x80A_0000 as _;\n" -"\n" -"/// Base address of the primary PL011 UART.\n" -"const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;\n" -"\n" -"/// Base address of the PL031 RTC.\n" -"const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;\n" -"/// The IRQ used by the PL031 RTC.\n" -"const PL031_IRQ: IntId = IntId::spi(2);\n" -"\n" -"#[no_mangle]\n" -"extern \"C\" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {\n" -" // Safe because `PL011_BASE_ADDRESS` is the base address of a PL011 " -"device,\n" -" // and nothing else accesses that address range.\n" -" let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };\n" -" logger::init(uart, LevelFilter::Trace).unwrap();\n" -"\n" -" info!(\"main({:#x}, {:#x}, {:#x}, {:#x})\", x0, x1, x2, x3);\n" -"\n" -" // Safe because `GICD_BASE_ADDRESS` and `GICR_BASE_ADDRESS` are the " -"base\n" -" // addresses of a GICv3 distributor and redistributor respectively, and\n" -" // nothing else accesses those address ranges.\n" -" let mut gic = unsafe { GicV3::new(GICD_BASE_ADDRESS, " -"GICR_BASE_ADDRESS) };\n" -" gic.setup();\n" -"\n" -" // Safe because `PL031_BASE_ADDRESS` is the base address of a PL031 " -"device,\n" +"// Safe because `PL031_BASE_ADDRESS` is the base address of a PL031 device,\n" " // and nothing else accesses that address range.\n" -" let mut rtc = unsafe { Rtc::new(PL031_BASE_ADDRESS) };\n" -" let timestamp = rtc.read();\n" -" let time = Utc.timestamp_opt(timestamp.into(), 0).unwrap();\n" -" info!(\"RTC: {time}\");\n" -"\n" -" GicV3::set_priority_mask(0xff);\n" -" gic.set_interrupt_priority(PL031_IRQ, 0x80);\n" -" gic.set_trigger(PL031_IRQ, Trigger::Level);\n" -" irq_enable();\n" -" gic.enable_interrupt(PL031_IRQ, true);\n" -"\n" -" // Wait for 3 seconds, without interrupts.\n" -" let target = timestamp + 3;\n" -" rtc.set_match(target);\n" -" info!(\n" -" \"Waiting for {}\",\n" -" Utc.timestamp_opt(target.into(), 0).unwrap()\n" -" );\n" -" trace!(\n" -" \"matched={}, interrupt_pending={}\",\n" -" rtc.matched(),\n" -" rtc.interrupt_pending()\n" -" );\n" -" while !rtc.matched() {\n" -" spin_loop();\n" -" }\n" -" trace!(\n" -" \"matched={}, interrupt_pending={}\",\n" -" rtc.matched(),\n" -" rtc.interrupt_pending()\n" -" );\n" -" info!(\"Finished waiting\");\n" -"\n" -" // Wait another 3 seconds for an interrupt.\n" -" let target = timestamp + 6;\n" -" info!(\n" -" \"Waiting for {}\",\n" -" Utc.timestamp_opt(target.into(), 0).unwrap()\n" -" );\n" -" rtc.set_match(target);\n" -" rtc.clear_interrupt();\n" -" rtc.enable_interrupt(true);\n" -" trace!(\n" -" \"matched={}, interrupt_pending={}\",\n" -" rtc.matched(),\n" -" rtc.interrupt_pending()\n" -" );\n" -" while !rtc.interrupt_pending() {\n" -" wfi();\n" -" }\n" -" trace!(\n" -" \"matched={}, interrupt_pending={}\",\n" -" rtc.matched(),\n" -" rtc.interrupt_pending()\n" -" );\n" -" info!(\"Finished waiting\");\n" -"\n" -" system_off::().unwrap();\n" -"}\n" -"\n" -"#[panic_handler]\n" -"fn panic(info: &PanicInfo) -> ! {\n" -" error!(\"{info}\");\n" -" system_off::().unwrap();\n" -" loop {}\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:62 +msgid "\"RTC: {time}\"" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:70 +msgid "// Wait for 3 seconds, without interrupts.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:74 +#: src/exercises/bare-metal/solutions-afternoon.md:95 +msgid "\"Waiting for {}\"" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:78 +#: src/exercises/bare-metal/solutions-afternoon.md:86 +#: src/exercises/bare-metal/solutions-afternoon.md:102 +#: src/exercises/bare-metal/solutions-afternoon.md:110 +msgid "\"matched={}, interrupt_pending={}\"" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:90 +#: src/exercises/bare-metal/solutions-afternoon.md:114 +msgid "\"Finished waiting\"" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:92 +msgid "// Wait another 3 seconds for an interrupt.\n" msgstr "" #: src/exercises/bare-metal/solutions-afternoon.md:127 msgid "_pl031.rs_:" msgstr "" -#: src/exercises/bare-metal/solutions-afternoon.md:129 +#: src/exercises/bare-metal/solutions-afternoon.md:134 +msgid "/// Data register\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:136 +msgid "/// Match register\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:138 +msgid "/// Load register\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:140 +msgid "/// Control register\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:143 +msgid "/// Interrupt Mask Set or Clear register\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:146 +msgid "/// Raw Interrupt Status\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:149 +msgid "/// Masked Interrupt Status\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:152 +msgid "/// Interrupt Clear Register\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:156 +msgid "/// Driver for a PL031 real-time clock.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:164 msgid "" -"```rust\n" -"use core::ptr::{addr_of, addr_of_mut};\n" -"\n" -"#[repr(C, align(4))]\n" -"struct Registers {\n" -" /// Data register\n" -" dr: u32,\n" -" /// Match register\n" -" mr: u32,\n" -" /// Load register\n" -" lr: u32,\n" -" /// Control register\n" -" cr: u8,\n" -" _reserved0: [u8; 3],\n" -" /// Interrupt Mask Set or Clear register\n" -" imsc: u8,\n" -" _reserved1: [u8; 3],\n" -" /// Raw Interrupt Status\n" -" ris: u8,\n" -" _reserved2: [u8; 3],\n" -" /// Masked Interrupt Status\n" -" mis: u8,\n" -" _reserved3: [u8; 3],\n" -" /// Interrupt Clear Register\n" -" icr: u8,\n" -" _reserved4: [u8; 3],\n" -"}\n" -"\n" -"/// Driver for a PL031 real-time clock.\n" -"#[derive(Debug)]\n" -"pub struct Rtc {\n" -" registers: *mut Registers,\n" -"}\n" -"\n" -"impl Rtc {\n" -" /// Constructs a new instance of the RTC driver for a PL031 device at " -"the\n" +"/// Constructs a new instance of the RTC driver for a PL031 device at the\n" " /// given base address.\n" " ///\n" " /// # Safety\n" @@ -19612,76 +16789,55 @@ msgid "" " /// PL031 device, which must be mapped into the address space of the " "process\n" " /// as device memory and not have any other aliases.\n" -" pub unsafe fn new(base_address: *mut u32) -> Self {\n" -" Self {\n" -" registers: base_address as *mut Registers,\n" -" }\n" -" }\n" -"\n" -" /// Reads the current RTC value.\n" -" pub fn read(&self) -> u32 {\n" -" // Safe because we know that self.registers points to the control\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:178 +msgid "/// Reads the current RTC value.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:180 +#: src/exercises/bare-metal/solutions-afternoon.md:188 +#: src/exercises/bare-metal/solutions-afternoon.md:196 +#: src/exercises/bare-metal/solutions-afternoon.md:207 +#: src/exercises/bare-metal/solutions-afternoon.md:219 +#: src/exercises/bare-metal/solutions-afternoon.md:226 +msgid "" +"// Safe because we know that self.registers points to the control\n" " // registers of a PL031 device which is appropriately mapped.\n" -" unsafe { addr_of!((*self.registers).dr).read_volatile() }\n" -" }\n" -"\n" -" /// Writes a match value. When the RTC value matches this then an " -"interrupt\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:185 +msgid "" +"/// Writes a match value. When the RTC value matches this then an interrupt\n" " /// will be generated (if it is enabled).\n" -" pub fn set_match(&mut self, value: u32) {\n" -" // Safe because we know that self.registers points to the control\n" -" // registers of a PL031 device which is appropriately mapped.\n" -" unsafe { addr_of_mut!((*self.registers).mr).write_volatile(value) }\n" -" }\n" -"\n" -" /// Returns whether the match register matches the RTC value, whether or " +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:193 +msgid "" +"/// Returns whether the match register matches the RTC value, whether or " "not\n" " /// the interrupt is enabled.\n" -" pub fn matched(&self) -> bool {\n" -" // Safe because we know that self.registers points to the control\n" -" // registers of a PL031 device which is appropriately mapped.\n" -" let ris = unsafe { addr_of!((*self.registers).ris)." -"read_volatile() };\n" -" (ris & 0x01) != 0\n" -" }\n" -"\n" -" /// Returns whether there is currently an interrupt pending.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:202 +msgid "" +"/// Returns whether there is currently an interrupt pending.\n" " ///\n" " /// This should be true if and only if `matched` returns true and the\n" " /// interrupt is masked.\n" -" pub fn interrupt_pending(&self) -> bool {\n" -" // Safe because we know that self.registers points to the control\n" -" // registers of a PL031 device which is appropriately mapped.\n" -" let ris = unsafe { addr_of!((*self.registers).mis)." -"read_volatile() };\n" -" (ris & 0x01) != 0\n" -" }\n" -"\n" -" /// Sets or clears the interrupt mask.\n" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:213 +msgid "" +"/// Sets or clears the interrupt mask.\n" " ///\n" " /// When the mask is true the interrupt is enabled; when it is false " "the\n" " /// interrupt is disabled.\n" -" pub fn enable_interrupt(&mut self, mask: bool) {\n" -" let imsc = if mask { 0x01 } else { 0x00 };\n" -" // Safe because we know that self.registers points to the control\n" -" // registers of a PL031 device which is appropriately mapped.\n" -" unsafe { addr_of_mut!((*self.registers).imsc)." -"write_volatile(imsc) }\n" -" }\n" -"\n" -" /// Clears a pending interrupt, if any.\n" -" pub fn clear_interrupt(&mut self) {\n" -" // Safe because we know that self.registers points to the control\n" -" // registers of a PL031 device which is appropriately mapped.\n" -" unsafe { addr_of_mut!((*self.registers).icr).write_volatile(0x01) }\n" -" }\n" -"}\n" -"\n" -"// Safe because it just contains a pointer to device memory, which can be\n" -"// accessed from any context.\n" -"unsafe impl Send for Rtc {}\n" -"```" +msgstr "" + +#: src/exercises/bare-metal/solutions-afternoon.md:224 +msgid "/// Clears a pending interrupt, if any.\n" msgstr "" #: src/exercises/concurrency/solutions-morning.md:1 @@ -19692,82 +16848,19 @@ msgstr "" msgid "([back to exercise](dining-philosophers.md))" msgstr "" -#: src/exercises/concurrency/solutions-morning.md:7 +#: src/exercises/concurrency/solutions-morning.md:29 +msgid "\"{} is trying to eat\"" +msgstr "" + +#: src/exercises/concurrency/solutions-morning.md:53 msgid "" -"```rust\n" -"use std::sync::{mpsc, Arc, Mutex};\n" -"use std::thread;\n" -"use std::time::Duration;\n" -"\n" -"struct Fork;\n" -"\n" -"struct Philosopher {\n" -" name: String,\n" -" left_fork: Arc>,\n" -" right_fork: Arc>,\n" -" thoughts: mpsc::SyncSender,\n" -"}\n" -"\n" -"impl Philosopher {\n" -" fn think(&self) {\n" -" self.thoughts\n" -" .send(format!(\"Eureka! {} has a new idea!\", &self.name))\n" -" .unwrap();\n" -" }\n" -"\n" -" fn eat(&self) {\n" -" println!(\"{} is trying to eat\", &self.name);\n" -" let left = self.left_fork.lock().unwrap();\n" -" let right = self.right_fork.lock().unwrap();\n" -"\n" -" println!(\"{} is eating...\", &self.name);\n" -" thread::sleep(Duration::from_millis(10));\n" -" }\n" -"}\n" -"\n" -"static PHILOSOPHERS: &[&str] =\n" -" &[\"Socrates\", \"Hypatia\", \"Plato\", \"Aristotle\", \"Pythagoras\"];\n" -"\n" -"fn main() {\n" -" let (tx, rx) = mpsc::sync_channel(10);\n" -"\n" -" let forks = (0..PHILOSOPHERS.len())\n" -" .map(|_| Arc::new(Mutex::new(Fork)))\n" -" .collect::>();\n" -"\n" -" for i in 0..forks.len() {\n" -" let tx = tx.clone();\n" -" let mut left_fork = Arc::clone(&forks[i]);\n" -" let mut right_fork = Arc::clone(&forks[(i + 1) % forks.len()]);\n" -"\n" -" // To avoid a deadlock, we have to break the symmetry\n" +"// To avoid a deadlock, we have to break the symmetry\n" " // somewhere. This will swap the forks without deinitializing\n" " // either of them.\n" -" if i == forks.len() - 1 {\n" -" std::mem::swap(&mut left_fork, &mut right_fork);\n" -" }\n" -"\n" -" let philosopher = Philosopher {\n" -" name: PHILOSOPHERS[i].to_string(),\n" -" thoughts: tx,\n" -" left_fork,\n" -" right_fork,\n" -" };\n" -"\n" -" thread::spawn(move || {\n" -" for _ in 0..100 {\n" -" philosopher.eat();\n" -" philosopher.think();\n" -" }\n" -" });\n" -" }\n" -"\n" -" drop(tx);\n" -" for thought in rx {\n" -" println!(\"{thought}\");\n" -" }\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/concurrency/solutions-morning.md:77 +msgid "\"{thought}\"" msgstr "" #: src/exercises/concurrency/solutions-morning.md:82 @@ -19778,181 +16871,27 @@ msgstr "" msgid "([back to exercise](link-checker.md))" msgstr "" -#: src/exercises/concurrency/solutions-morning.md:86 +#: src/exercises/concurrency/solutions-morning.md:155 msgid "" -"```rust,compile_fail\n" -"use std::{sync::Arc, sync::Mutex, sync::mpsc, thread};\n" -"\n" -"use reqwest::{blocking::Client, Url};\n" -"use scraper::{Html, Selector};\n" -"use thiserror::Error;\n" -"\n" -"#[derive(Error, Debug)]\n" -"enum Error {\n" -" #[error(\"request error: {0}\")]\n" -" ReqwestError(#[from] reqwest::Error),\n" -" #[error(\"bad http response: {0}\")]\n" -" BadResponse(String),\n" -"}\n" -"\n" -"#[derive(Debug)]\n" -"struct CrawlCommand {\n" -" url: Url,\n" -" extract_links: bool,\n" -"}\n" -"\n" -"fn visit_page(client: &Client, command: &CrawlCommand) -> Result, " -"Error> {\n" -" println!(\"Checking {:#}\", command.url);\n" -" let response = client.get(command.url.clone()).send()?;\n" -" if !response.status().is_success() {\n" -" return Err(Error::BadResponse(response.status().to_string()));\n" -" }\n" -"\n" -" let mut link_urls = Vec::new();\n" -" if !command.extract_links {\n" -" return Ok(link_urls);\n" -" }\n" -"\n" -" let base_url = response.url().to_owned();\n" -" let body_text = response.text()?;\n" -" let document = Html::parse_document(&body_text);\n" -"\n" -" let selector = Selector::parse(\"a\").unwrap();\n" -" let href_values = document\n" -" .select(&selector)\n" -" .filter_map(|element| element.value().attr(\"href\"));\n" -" for href in href_values {\n" -" match base_url.join(href) {\n" -" Ok(link_url) => {\n" -" link_urls.push(link_url);\n" -" }\n" -" Err(err) => {\n" -" println!(\"On {base_url:#}: ignored unparsable {href:?}: " -"{err}\");\n" -" }\n" -" }\n" -" }\n" -" Ok(link_urls)\n" -"}\n" -"\n" -"struct CrawlState {\n" -" domain: String,\n" -" visited_pages: std::collections::HashSet,\n" -"}\n" -"\n" -"impl CrawlState {\n" -" fn new(start_url: &Url) -> CrawlState {\n" -" let mut visited_pages = std::collections::HashSet::new();\n" -" visited_pages.insert(start_url.as_str().to_string());\n" -" CrawlState {\n" -" domain: start_url.domain().unwrap().to_string(),\n" -" visited_pages,\n" -" }\n" -" }\n" -"\n" -" /// Determine whether links within the given page should be extracted.\n" -" fn should_extract_links(&self, url: &Url) -> bool {\n" -" let Some(url_domain) = url.domain() else {\n" -" return false;\n" -" };\n" -" url_domain == self.domain\n" -" }\n" -"\n" -" /// Mark the given page as visited, returning false if it had already\n" +"/// Determine whether links within the given page should be extracted.\n" +msgstr "" + +#: src/exercises/concurrency/solutions-morning.md:163 +msgid "" +"/// Mark the given page as visited, returning false if it had already\n" " /// been visited.\n" -" fn mark_visited(&mut self, url: &Url) -> bool {\n" -" self.visited_pages.insert(url.as_str().to_string())\n" -" }\n" -"}\n" -"\n" -"type CrawlResult = Result, (Url, Error)>;\n" -"fn spawn_crawler_threads(\n" -" command_receiver: mpsc::Receiver,\n" -" result_sender: mpsc::Sender,\n" -" thread_count: u32,\n" -") {\n" -" let command_receiver = Arc::new(Mutex::new(command_receiver));\n" -"\n" -" for _ in 0..thread_count {\n" -" let result_sender = result_sender.clone();\n" -" let command_receiver = command_receiver.clone();\n" -" thread::spawn(move || {\n" -" let client = Client::new();\n" -" loop {\n" -" let command_result = {\n" -" let receiver_guard = command_receiver.lock().unwrap();\n" -" receiver_guard.recv()\n" -" };\n" -" let Ok(crawl_command) = command_result else {\n" -" // The sender got dropped. No more commands coming in.\n" -" break;\n" -" };\n" -" let crawl_result = match visit_page(&client, &crawl_command) " -"{\n" -" Ok(link_urls) => Ok(link_urls),\n" -" Err(error) => Err((crawl_command.url, error)),\n" -" };\n" -" result_sender.send(crawl_result).unwrap();\n" -" }\n" -" });\n" -" }\n" -"}\n" -"\n" -"fn control_crawl(\n" -" start_url: Url,\n" -" command_sender: mpsc::Sender,\n" -" result_receiver: mpsc::Receiver,\n" -") -> Vec {\n" -" let mut crawl_state = CrawlState::new(&start_url);\n" -" let start_command = CrawlCommand { url: start_url, extract_links: " -"true };\n" -" command_sender.send(start_command).unwrap();\n" -" let mut pending_urls = 1;\n" -"\n" -" let mut bad_urls = Vec::new();\n" -" while pending_urls > 0 {\n" -" let crawl_result = result_receiver.recv().unwrap();\n" -" pending_urls -= 1;\n" -"\n" -" match crawl_result {\n" -" Ok(link_urls) => {\n" -" for url in link_urls {\n" -" if crawl_state.mark_visited(&url) {\n" -" let extract_links = crawl_state." -"should_extract_links(&url);\n" -" let crawl_command = CrawlCommand { url, " -"extract_links };\n" -" command_sender.send(crawl_command).unwrap();\n" -" pending_urls += 1;\n" -" }\n" -" }\n" -" }\n" -" Err((url, error)) => {\n" -" bad_urls.push(url);\n" -" println!(\"Got crawling error: {:#}\", error);\n" -" continue;\n" -" }\n" -" }\n" -" }\n" -" bad_urls\n" -"}\n" -"\n" -"fn check_links(start_url: Url) -> Vec {\n" -" let (result_sender, result_receiver) = mpsc::channel::();\n" -" let (command_sender, command_receiver) = mpsc::channel::" -"();\n" -" spawn_crawler_threads(command_receiver, result_sender, 16);\n" -" control_crawl(start_url, command_sender, result_receiver)\n" -"}\n" -"\n" -"fn main() {\n" -" let start_url = reqwest::Url::parse(\"https://www.google.org\")." -"unwrap();\n" -" let bad_urls = check_links(start_url);\n" -" println!(\"Bad URLs: {:#?}\", bad_urls);\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/concurrency/solutions-morning.md:189 +msgid "// The sender got dropped. No more commands coming in.\n" +msgstr "" + +#: src/exercises/concurrency/solutions-morning.md:230 +msgid "\"Got crawling error: {:#}\"" +msgstr "" + +#: src/exercises/concurrency/solutions-morning.md:248 +msgid "\"Bad URLs: {:#?}\"" msgstr "" #: src/exercises/concurrency/solutions-afternoon.md:1 @@ -19963,218 +16902,145 @@ msgstr "" msgid "([back to exercise](dining-philosophers-async.md))" msgstr "" -#: src/exercises/concurrency/solutions-afternoon.md:7 +#: src/exercises/concurrency/solutions-afternoon.md:30 +msgid "// Pick up forks...\n" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:32 msgid "" -"```rust,compile_fail\n" -"use std::sync::Arc;\n" -"use tokio::time;\n" -"use tokio::sync::mpsc::{self, Sender};\n" -"use tokio::sync::Mutex;\n" -"\n" -"struct Fork;\n" -"\n" -"struct Philosopher {\n" -" name: String,\n" -" left_fork: Arc>,\n" -" right_fork: Arc>,\n" -" thoughts: Sender,\n" -"}\n" -"\n" -"impl Philosopher {\n" -" async fn think(&self) {\n" -" self.thoughts\n" -" .send(format!(\"Eureka! {} has a new idea!\", &self.name))." -"await\n" -" .unwrap();\n" -" }\n" -"\n" -" async fn eat(&self) {\n" -" // Pick up forks...\n" -" let _first_lock = self.left_fork.lock().await;\n" -" // Add a delay before picking the second fork to allow the " -"execution\n" +"// Add a delay before picking the second fork to allow the execution\n" " // to transfer to another task\n" -" time::sleep(time::Duration::from_millis(1)).await;\n" -" let _second_lock = self.right_fork.lock().await;\n" -"\n" -" println!(\"{} is eating...\", &self.name);\n" -" time::sleep(time::Duration::from_millis(5)).await;\n" -"\n" -" // The locks are dropped here\n" -" }\n" -"}\n" -"\n" -"static PHILOSOPHERS: &[&str] =\n" -" &[\"Socrates\", \"Hypatia\", \"Plato\", \"Aristotle\", \"Pythagoras\"];\n" -"\n" -"#[tokio::main]\n" -"async fn main() {\n" -" // Create forks\n" -" let mut forks = vec![];\n" -" (0..PHILOSOPHERS.len()).for_each(|_| forks.push(Arc::new(Mutex::" -"new(Fork))));\n" -"\n" -" // Create philosophers\n" -" let (philosophers, mut rx) = {\n" -" let mut philosophers = vec![];\n" -" let (tx, rx) = mpsc::channel(10);\n" -" for (i, name) in PHILOSOPHERS.iter().enumerate() {\n" -" let left_fork = Arc::clone(&forks[i]);\n" -" let right_fork = Arc::clone(&forks[(i + 1) % PHILOSOPHERS." -"len()]);\n" -" // To avoid a deadlock, we have to break the symmetry\n" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:40 +msgid "// The locks are dropped here\n" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:49 +msgid "// Create forks\n" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:53 +msgid "// Create philosophers\n" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:60 +msgid "" +"// To avoid a deadlock, we have to break the symmetry\n" " // somewhere. This will swap the forks without deinitializing\n" " // either of them.\n" -" if i == 0 {\n" -" std::mem::swap(&mut left_fork, &mut right_fork);\n" -" }\n" -" philosophers.push(Philosopher {\n" -" name: name.to_string(),\n" -" left_fork,\n" -" right_fork,\n" -" thoughts: tx.clone(),\n" -" });\n" -" }\n" -" (philosophers, rx)\n" -" // tx is dropped here, so we don't need to explicitly drop it later\n" -" };\n" -"\n" -" // Make them think and eat\n" -" for phil in philosophers {\n" -" tokio::spawn(async move {\n" -" for _ in 0..100 {\n" -" phil.think().await;\n" -" phil.eat().await;\n" -" }\n" -" });\n" -"\n" -" }\n" -"\n" -" // Output their thoughts\n" -" while let Some(thought) = rx.recv().await {\n" -" println!(\"Here is a thought: {thought}\");\n" -" }\n" -"}\n" -"```" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:74 +msgid "// tx is dropped here, so we don't need to explicitly drop it later\n" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:77 +msgid "// Make them think and eat\n" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:88 +msgid "// Output their thoughts\n" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:90 +msgid "\"Here is a thought: {thought}\"" msgstr "" #: src/exercises/concurrency/solutions-afternoon.md:97 msgid "([back to exercise](chat-app.md))" msgstr "" -#: src/exercises/concurrency/solutions-afternoon.md:101 +#: src/exercises/concurrency/solutions-afternoon.md:117 +msgid "\"Welcome to chat! Type a message\"" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:121 msgid "" -"```rust,compile_fail\n" -"use futures_util::sink::SinkExt;\n" -"use futures_util::stream::StreamExt;\n" -"use std::error::Error;\n" -"use std::net::SocketAddr;\n" -"use tokio::net::{TcpListener, TcpStream};\n" -"use tokio::sync::broadcast::{channel, Sender};\n" -"use tokio_websockets::{Message, ServerBuilder, WebsocketStream};\n" -"\n" -"async fn handle_connection(\n" -" addr: SocketAddr,\n" -" mut ws_stream: WebsocketStream,\n" -" bcast_tx: Sender,\n" -") -> Result<(), Box> {\n" -"\n" -" ws_stream\n" -" .send(Message::text(\"Welcome to chat! Type a message\".into()))\n" -" .await?;\n" -" let mut bcast_rx = bcast_tx.subscribe();\n" -"\n" -" // A continuous loop for concurrently performing two tasks: (1) " -"receiving\n" +"// A continuous loop for concurrently performing two tasks: (1) receiving\n" " // messages from `ws_stream` and broadcasting them, and (2) receiving\n" " // messages on `bcast_rx` and sending them to the client.\n" -" loop {\n" -" tokio::select! {\n" -" incoming = ws_stream.next() => {\n" -" match incoming {\n" -" Some(Ok(msg)) => {\n" -" if let Some(text) = msg.as_text() {\n" -" println!(\"From client {addr:?} {text:?}\");\n" -" bcast_tx.send(text.into())?;\n" -" }\n" -" }\n" -" Some(Err(err)) => return Err(err.into()),\n" -" None => return Ok(()),\n" -" }\n" -" }\n" -" msg = bcast_rx.recv() => {\n" -" ws_stream.send(Message::text(msg?)).await?;\n" -" }\n" -" }\n" -" }\n" -"}\n" -"\n" -"#[tokio::main]\n" -"async fn main() -> Result<(), Box> {\n" -" let (bcast_tx, _) = channel(16);\n" -"\n" -" let listener = TcpListener::bind(\"127.0.0.1:2000\").await?;\n" -" println!(\"listening on port 2000\");\n" -"\n" -" loop {\n" -" let (socket, addr) = listener.accept().await?;\n" -" println!(\"New connection from {addr:?}\");\n" -" let bcast_tx = bcast_tx.clone();\n" -" tokio::spawn(async move {\n" -" // Wrap the raw TCP stream into a websocket.\n" -" let ws_stream = ServerBuilder::new().accept(socket).await?;\n" -"\n" -" handle_connection(addr, ws_stream, bcast_tx).await\n" -" });\n" -" }\n" -"}\n" -"```" msgstr "" -#: src/exercises/concurrency/solutions-afternoon.md:168 -msgid "" -"```rust,compile_fail\n" -"use futures_util::stream::StreamExt;\n" -"use futures_util::SinkExt;\n" -"use http::Uri;\n" -"use tokio::io::{AsyncBufReadExt, BufReader};\n" -"use tokio_websockets::{ClientBuilder, Message};\n" -"\n" -"#[tokio::main]\n" -"async fn main() -> Result<(), tokio_websockets::Error> {\n" -" let (mut ws_stream, _) =\n" -" ClientBuilder::from_uri(Uri::from_static(\"ws://127.0.0.1:2000\"))\n" -" .connect()\n" -" .await?;\n" -"\n" -" let stdin = tokio::io::stdin();\n" -" let mut stdin = BufReader::new(stdin).lines();\n" -"\n" -" // Continuous loop for concurrently sending and receiving messages.\n" -" loop {\n" -" tokio::select! {\n" -" incoming = ws_stream.next() => {\n" -" match incoming {\n" -" Some(Ok(msg)) => {\n" -" if let Some(text) = msg.as_text() {\n" -" println!(\"From server: {}\", text);\n" -" }\n" -" },\n" -" Some(Err(err)) => return Err(err.into()),\n" -" None => return Ok(()),\n" -" }\n" -" }\n" -" res = stdin.next_line() => {\n" -" match res {\n" -" Ok(None) => return Ok(()),\n" -" Ok(Some(line)) => ws_stream.send(Message::text(line." -"to_string())).await?,\n" -" Err(err) => return Err(err.into()),\n" -" }\n" -" }\n" -"\n" -" }\n" -" }\n" -"}\n" -"```" -msgstr "" +#: src/exercises/concurrency/solutions-afternoon.md:130 +msgid "\"From client {addr:?} {text:?}\"" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:185 +msgid "// Continuous loop for concurrently sending and receiving messages.\n" +msgstr "" + +#: src/exercises/concurrency/solutions-afternoon.md:192 +msgid "\"From server: {}\"" +msgstr "" + +#~ msgid "" +#~ "```rust,editable\n" +#~ "fn main() {\n" +#~ " println!(\"Edit me!\");\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust,editable\n" +#~ "fn main() {\n" +#~ " println!(\"Edit me!\");\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "fn main() {\n" +#~ " println!(\"Edit me!\");\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "fn main() {\n" +#~ " println!(\"Edit me!\");\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust,editable\n" +#~ "fn main() { // Program entry point\n" +#~ " let mut x: i32 = 6; // Mutable variable binding\n" +#~ " print!(\"{x}\"); // Macro for printing, like printf\n" +#~ " while x != 1 { // No parenthesis around expression\n" +#~ " if x % 2 == 0 { // Math like in other languages\n" +#~ " x = x / 2;\n" +#~ " } else {\n" +#~ " x = 3 * x + 1;\n" +#~ " }\n" +#~ " print!(\" -> {x}\");\n" +#~ " }\n" +#~ " println!();\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust,editable\n" +#~ "fn main() { // نقطه ورودی برنامه\n" +#~ " let mut x: i32 = 6; //انتساب متغیر قابل تغییر\n" +#~ " print!(\"{x}\"); // ماکرویی برای چاپ‌کردن به مانند printf\n" +#~ " while x != 1 { // هیچ پرانتزی اطراف دستور نیست\n" +#~ " if x % 2 == 0 { // محاسبات مانند بقیه زبان ها \n" +#~ " x = x / 2;\n" +#~ " } else {\n" +#~ " x = 3 * x + 1;\n" +#~ " }\n" +#~ " print!(\" -> {x}\");\n" +#~ " }\n" +#~ " println!();\n" +#~ "}\n" +#~ "```" + +#, fuzzy +#~ msgid "main function:" +#~ msgstr "فراخوانی متدهای ناامن" + +#, fuzzy +#~ msgid "unit test:" +#~ msgstr "تست‌های واحد (Unit Tests)" + +#, fuzzy +#~ msgid "variable:\\" +#~ msgstr "متغیرها" From 3b8c2acedf86ac3425d910eeb16a214f72bdd6c5 Mon Sep 17 00:00:00 2001 From: Amin Sharifi Date: Sat, 11 Nov 2023 13:31:04 +0330 Subject: [PATCH 2/2] revert `POT-Creation-Date` --- po/fa.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/fa.po b/po/fa.po index 1191754be92..d7841fdda8d 100644 --- a/po/fa.po +++ b/po/fa.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: Comprehensive Rust 🦀\n" -"POT-Creation-Date: 2023-11-11T13:22:58+03:30\n" +"POT-Creation-Date: 2023-08-23\n" "PO-Revision-Date: 2023-08-08 21:41+0330\n" "Last-Translator: danny \n" "Language-Team: Persian\n"