diff --git a/po/fr.po b/po/fr.po index 89f59a033e37..cb4c2f1dde6d 100644 --- a/po/fr.po +++ b/po/fr.po @@ -53,7 +53,7 @@ msgid "Day 1: Morning" msgstr "Jour 1 : Matin" #: src/SUMMARY.md:18 src/SUMMARY.md:75 src/SUMMARY.md:128 src/SUMMARY.md:185 -#: src/SUMMARY.md:211 src/SUMMARY.md:259 +#: src/SUMMARY.md:211 src/SUMMARY.md:261 msgid "Welcome" msgstr "Bienvenue" @@ -131,7 +131,7 @@ msgstr "Surcharge" #: src/SUMMARY.md:37 src/SUMMARY.md:66 src/SUMMARY.md:90 src/SUMMARY.md:119 #: src/SUMMARY.md:148 src/SUMMARY.md:177 src/SUMMARY.md:204 src/SUMMARY.md:225 -#: src/SUMMARY.md:251 src/SUMMARY.md:273 src/SUMMARY.md:293 +#: src/SUMMARY.md:253 src/SUMMARY.md:275 src/SUMMARY.md:296 msgid "Exercises" msgstr "Exercices" @@ -279,7 +279,7 @@ msgstr "Tailles d'énumération" msgid "Method Receiver" msgstr "Récepteur de méthode" -#: src/SUMMARY.md:84 src/SUMMARY.md:159 src/SUMMARY.md:272 +#: src/SUMMARY.md:84 src/SUMMARY.md:159 src/SUMMARY.md:274 msgid "Example" msgstr "Exemple" @@ -315,7 +315,7 @@ msgstr "Points et polygones" msgid "Day 2: Afternoon" msgstr "Jour 2 : Après-midi" -#: src/SUMMARY.md:96 src/SUMMARY.md:286 +#: src/SUMMARY.md:96 src/SUMMARY.md:288 msgid "Control Flow" msgstr "Flux de contrôle" @@ -600,7 +600,7 @@ msgstr "Implémentation de traits risqués" msgid "Safe FFI Wrapper" msgstr "Enveloppe FFI sûre" -#: src/SUMMARY.md:181 src/SUMMARY.md:249 +#: src/SUMMARY.md:181 src/SUMMARY.md:251 msgid "Android" msgstr "Android" @@ -648,7 +648,7 @@ msgstr "Client" msgid "Changing API" msgstr "Modification de l'API" -#: src/SUMMARY.md:197 src/SUMMARY.md:240 +#: src/SUMMARY.md:197 src/SUMMARY.md:241 msgid "Logging" msgstr "Journalisation" @@ -728,7 +728,7 @@ msgstr "probe-rs, cargo-embed" msgid "Debugging" msgstr "Débogage" -#: src/SUMMARY.md:224 src/SUMMARY.md:242 +#: src/SUMMARY.md:224 src/SUMMARY.md:244 msgid "Other Projects" msgstr "Autres projets" @@ -745,253 +745,266 @@ msgid "Application Processors" msgstr "Processeurs d'applications" #: src/SUMMARY.md:231 +msgid "Getting Ready to Rust" +msgstr "" + +#: src/SUMMARY.md:232 msgid "Inline Assembly" msgstr "Assembleur en ligne" -#: src/SUMMARY.md:232 +#: src/SUMMARY.md:233 msgid "MMIO" msgstr "MMIO" -#: src/SUMMARY.md:233 +#: src/SUMMARY.md:234 msgid "Let's Write a UART Driver" msgstr "Écrivons un pilote UART" -#: src/SUMMARY.md:234 +#: src/SUMMARY.md:235 msgid "More Traits" msgstr "Plus de traits" -#: src/SUMMARY.md:235 +#: src/SUMMARY.md:236 msgid "A Better UART Driver" msgstr "Un meilleur pilote UART" -#: src/SUMMARY.md:236 +#: src/SUMMARY.md:237 msgid "Bitflags" msgstr "Bitflags" -#: src/SUMMARY.md:237 +#: src/SUMMARY.md:238 msgid "Multiple Registers" msgstr "Registres multiples" -#: src/SUMMARY.md:238 +#: src/SUMMARY.md:239 msgid "Driver" msgstr "Pilote" -#: src/SUMMARY.md:239 src/SUMMARY.md:241 +#: src/SUMMARY.md:240 src/SUMMARY.md:242 msgid "Using It" msgstr "En l'utilisant" #: src/SUMMARY.md:243 +#, fuzzy +msgid "Exceptions" +msgstr "Fonctions" + +#: src/SUMMARY.md:245 msgid "Useful Crates" msgstr "Crates utiles" -#: src/SUMMARY.md:244 +#: src/SUMMARY.md:246 msgid "zerocopy" msgstr "zerocopy" -#: src/SUMMARY.md:245 +#: src/SUMMARY.md:247 msgid "aarch64-paging" msgstr "aarch64-paging" -#: src/SUMMARY.md:246 +#: src/SUMMARY.md:248 msgid "buddy_system_allocator" msgstr "buddy_system_allocator" -#: src/SUMMARY.md:247 +#: src/SUMMARY.md:249 msgid "tinyvec" msgstr "tinyvec" -#: src/SUMMARY.md:248 +#: src/SUMMARY.md:250 msgid "spin" msgstr "spin" -#: src/SUMMARY.md:250 +#: src/SUMMARY.md:252 msgid "vmbase" msgstr "vmbase" -#: src/SUMMARY.md:252 +#: src/SUMMARY.md:254 msgid "RTC Driver" msgstr "Pilote RTC" -#: src/SUMMARY.md:255 +#: src/SUMMARY.md:257 msgid "Concurrency: Morning" msgstr "Concurrence : Matin" -#: src/SUMMARY.md:260 +#: src/SUMMARY.md:262 msgid "Threads" msgstr "Threads" -#: src/SUMMARY.md:261 +#: src/SUMMARY.md:263 msgid "Scoped Threads" msgstr "Threads délimités" -#: src/SUMMARY.md:262 +#: src/SUMMARY.md:264 msgid "Channels" msgstr "Canaux" -#: src/SUMMARY.md:263 +#: src/SUMMARY.md:265 msgid "Unbounded Channels" msgstr "Canaux illimités" -#: src/SUMMARY.md:264 +#: src/SUMMARY.md:266 msgid "Bounded Channels" msgstr "Canaux limités" -#: src/SUMMARY.md:265 +#: src/SUMMARY.md:267 msgid "Send and Sync" msgstr "Send et Sync" -#: src/SUMMARY.md:265 +#: src/SUMMARY.md:267 msgid "Send" msgstr "Send" -#: src/SUMMARY.md:265 +#: src/SUMMARY.md:267 msgid "Sync" msgstr "Sync" -#: src/SUMMARY.md:268 +#: src/SUMMARY.md:270 msgid "Examples" msgstr "Exemples" -#: src/SUMMARY.md:269 +#: src/SUMMARY.md:271 msgid "Shared State" msgstr "État partagé" -#: src/SUMMARY.md:270 +#: src/SUMMARY.md:272 msgid "Arc" msgstr "Arc" -#: src/SUMMARY.md:271 +#: src/SUMMARY.md:273 msgid "Mutex" msgstr "Mutex" -#: src/SUMMARY.md:274 src/SUMMARY.md:294 +#: src/SUMMARY.md:276 src/SUMMARY.md:297 msgid "Dining Philosophers" msgstr "Dîner des philosophes" -#: src/SUMMARY.md:275 +#: src/SUMMARY.md:277 msgid "Multi-threaded Link Checker" msgstr "Vérificateur de liens à plusieurs threads" -#: src/SUMMARY.md:277 +#: src/SUMMARY.md:279 #, fuzzy msgid "Concurrency: Afternoon" msgstr "Concurrence : Après-midi" -#: src/SUMMARY.md:279 +#: src/SUMMARY.md:281 msgid "Async Basics" msgstr "" -#: src/SUMMARY.md:280 +#: src/SUMMARY.md:282 msgid "async/await" msgstr "" -#: src/SUMMARY.md:281 +#: src/SUMMARY.md:283 msgid "Futures" msgstr "" -#: src/SUMMARY.md:282 +#: src/SUMMARY.md:284 #, fuzzy msgid "Runtimes" msgstr "Garanties d'exécution" -#: src/SUMMARY.md:283 +#: src/SUMMARY.md:285 msgid "Tokio" msgstr "" -#: src/SUMMARY.md:284 +#: src/SUMMARY.md:286 msgid "Tasks" msgstr "Tâches" -#: src/SUMMARY.md:285 +#: src/SUMMARY.md:287 msgid "Async Channels" msgstr "Canaux asynchrones" -#: src/SUMMARY.md:287 +#: src/SUMMARY.md:289 msgid "Join" msgstr "" -#: src/SUMMARY.md:288 +#: src/SUMMARY.md:290 msgid "Select" msgstr "" -#: src/SUMMARY.md:289 +#: src/SUMMARY.md:291 msgid "Pitfalls" msgstr "Pièges" -#: src/SUMMARY.md:290 +#: src/SUMMARY.md:292 msgid "Blocking the Executor" msgstr "" -#: src/SUMMARY.md:291 +#: src/SUMMARY.md:293 msgid "Pin" msgstr "" -#: src/SUMMARY.md:292 +#: src/SUMMARY.md:294 #, fuzzy msgid "Async Traits" msgstr "Traits asynchrones" #: src/SUMMARY.md:295 -msgid "Broadcast Chat Application" +msgid "Cancellation" msgstr "" #: src/SUMMARY.md:298 +msgid "Broadcast Chat Application" +msgstr "" + +#: src/SUMMARY.md:301 msgid "Final Words" msgstr "Derniers mots" -#: src/SUMMARY.md:302 +#: src/SUMMARY.md:305 msgid "Thanks!" msgstr "Merci!" -#: src/SUMMARY.md:303 +#: src/SUMMARY.md:306 msgid "Other Resources" msgstr "Autres ressources" -#: src/SUMMARY.md:304 +#: src/SUMMARY.md:307 msgid "Credits" msgstr "Crédits" -#: src/SUMMARY.md:307 +#: src/SUMMARY.md:310 msgid "Solutions" msgstr "Solutions" -#: src/SUMMARY.md:312 +#: src/SUMMARY.md:315 msgid "Day 1 Morning" msgstr "Jour 1 Matin" -#: src/SUMMARY.md:313 +#: src/SUMMARY.md:316 msgid "Day 1 Afternoon" msgstr "Jour 1 Après-midi" -#: src/SUMMARY.md:314 +#: src/SUMMARY.md:317 msgid "Day 2 Morning" msgstr "Jour 2 Matin" -#: src/SUMMARY.md:315 +#: src/SUMMARY.md:318 msgid "Day 2 Afternoon" msgstr "Jour 2 Après-midi" -#: src/SUMMARY.md:316 +#: src/SUMMARY.md:319 msgid "Day 3 Morning" msgstr "Jour 3 Matin" -#: src/SUMMARY.md:317 +#: src/SUMMARY.md:320 msgid "Day 3 Afternoon" msgstr "Jour 3 Après-midi" -#: src/SUMMARY.md:318 +#: src/SUMMARY.md:321 msgid "Bare Metal Rust Morning" msgstr "Bare Metal Rust Matin" -#: src/SUMMARY.md:319 +#: src/SUMMARY.md:322 msgid "Bare Metal Rust Afternoon" msgstr "Bare Metal Rust Après-midi" -#: src/SUMMARY.md:320 +#: src/SUMMARY.md:323 msgid "Concurrency Morning" msgstr "Matin concurrence" -#: src/SUMMARY.md:321 +#: src/SUMMARY.md:324 msgid "Concurrency Afternoon" msgstr "Après-midi concurrence" @@ -1203,7 +1216,7 @@ msgstr "" #: src/ownership/lifetimes-data-structures.md:23 #: src/exercises/day-1/afternoon.md:9 src/exercises/day-1/book-library.md:100 #: src/structs.md:29 src/structs/tuple-structs.md:35 -#: src/structs/field-shorthand.md:25 src/enums.md:31 +#: src/structs/field-shorthand.md:25 src/enums.md:32 #: src/enums/variant-payloads.md:33 src/enums/sizes.md:27 src/methods.md:28 #: src/methods/receiver.md:22 src/methods/example.md:44 #: src/pattern-matching.md:23 src/pattern-matching/destructuring-enums.md:33 @@ -1250,6 +1263,7 @@ msgstr "" #: src/bare-metal/microcontrollers/debugging.md:25 #: src/bare-metal/microcontrollers/other-projects.md:16 #: src/exercises/bare-metal/morning.md:5 src/bare-metal/aps.md:7 +#: src/bare-metal/aps/entry-point.md:75 #: src/bare-metal/aps/inline-assembly.md:41 src/bare-metal/aps/mmio.md:7 #: src/bare-metal/aps/uart.md:53 src/bare-metal/aps/uart/traits.md:22 #: src/bare-metal/aps/better-uart.md:24 @@ -1257,7 +1271,8 @@ msgstr "" #: src/bare-metal/aps/better-uart/registers.md:39 #: src/bare-metal/aps/better-uart/driver.md:62 #: src/bare-metal/aps/better-uart/using.md:49 src/bare-metal/aps/logging.md:48 -#: src/bare-metal/aps/logging/using.md:44 +#: src/bare-metal/aps/logging/using.md:44 src/bare-metal/aps/exceptions.md:62 +#: src/bare-metal/aps/other-projects.md:15 #: src/bare-metal/useful-crates/zerocopy.md:43 #: src/bare-metal/useful-crates/aarch64-paging.md:26 #: src/bare-metal/useful-crates/buddy_system_allocator.md:24 @@ -1265,16 +1280,18 @@ msgstr "" #: src/bare-metal/useful-crates/spin.md:21 src/bare-metal/android/vmbase.md:19 #: src/exercises/bare-metal/afternoon.md:5 src/concurrency/threads.md:28 #: src/concurrency/scoped-threads.md:35 src/concurrency/channels.md:25 -#: src/concurrency/send-sync.md:18 src/concurrency/send-sync/send.md:11 -#: src/concurrency/send-sync/sync.md:12 src/concurrency/shared_state/arc.md:27 +#: src/concurrency/channels/bounded.md:29 src/concurrency/send-sync.md:18 +#: src/concurrency/send-sync/send.md:11 src/concurrency/send-sync/sync.md:12 +#: src/concurrency/shared_state/arc.md:27 #: src/concurrency/shared_state/mutex.md:29 #: src/concurrency/shared_state/example.md:21 #: src/exercises/concurrency/morning.md:10 src/async/async-await.md:23 #: src/async/futures.md:30 src/async/runtimes.md:18 -#: src/async/runtimes/tokio.md:31 src/async/tasks.md:51 +#: src/async/runtimes/tokio.md:31 src/async/tasks.md:50 #: src/async/channels.md:33 src/async/control-flow/join.md:34 -#: src/async/control-flow/select.md:59 +#: src/async/control-flow/select.md:60 #: src/async/pitfalls/blocking-executor.md:27 src/async/pitfalls/pin.md:66 +#: src/async/pitfalls/cancellation.md:70 #: src/exercises/concurrency/afternoon.md:11 #: src/exercises/concurrency/dining-philosophers-async.md:75 msgid "
" @@ -1296,7 +1313,7 @@ msgstr "" #: src/welcome.md:56 src/cargo/rust-ecosystem.md:67 #: src/cargo/code-samples.md:35 src/cargo/running-locally.md:74 #: src/welcome-day-1.md:42 src/welcome-day-1/what-is-rust.md:29 -#: src/hello-world.md:40 src/hello-world/small-example.md:44 src/why-rust.md:24 +#: src/hello-world.md:40 src/hello-world/small-example.md:46 src/why-rust.md:24 #: src/why-rust/compile-time.md:35 src/why-rust/runtime.md:22 #: src/why-rust/modern.md:66 src/basic-syntax/scalar-types.md:43 #: src/basic-syntax/compound-types.md:62 src/basic-syntax/references.md:29 @@ -1313,8 +1330,8 @@ msgstr "" #: src/ownership/lifetimes-function-calls.md:60 #: src/ownership/lifetimes-data-structures.md:30 #: src/exercises/day-1/afternoon.md:15 src/exercises/day-1/book-library.md:104 -#: src/structs.md:42 src/structs/tuple-structs.md:43 -#: src/structs/field-shorthand.md:72 src/enums.md:41 +#: src/structs.md:42 src/structs/tuple-structs.md:44 +#: src/structs/field-shorthand.md:72 src/enums.md:42 #: src/enums/variant-payloads.md:45 src/enums/sizes.md:155 src/methods.md:41 #: src/methods/receiver.md:28 src/methods/example.md:53 #: src/pattern-matching.md:35 src/pattern-matching/destructuring-enums.md:39 @@ -1362,13 +1379,15 @@ msgstr "" #: src/bare-metal/microcontrollers/debugging.md:38 #: src/bare-metal/microcontrollers/other-projects.md:26 #: src/exercises/bare-metal/morning.md:11 src/bare-metal/aps.md:15 +#: src/bare-metal/aps/entry-point.md:101 #: src/bare-metal/aps/inline-assembly.md:58 src/bare-metal/aps/mmio.md:17 #: src/bare-metal/aps/uart/traits.md:27 src/bare-metal/aps/better-uart.md:28 #: src/bare-metal/aps/better-uart/bitflags.md:40 #: src/bare-metal/aps/better-uart/registers.md:46 #: src/bare-metal/aps/better-uart/driver.md:67 #: src/bare-metal/aps/better-uart/using.md:55 src/bare-metal/aps/logging.md:52 -#: src/bare-metal/aps/logging/using.md:49 +#: src/bare-metal/aps/logging/using.md:49 src/bare-metal/aps/exceptions.md:75 +#: src/bare-metal/aps/other-projects.md:29 #: src/bare-metal/useful-crates/zerocopy.md:53 #: src/bare-metal/useful-crates/aarch64-paging.md:33 #: src/bare-metal/useful-crates/buddy_system_allocator.md:30 @@ -1376,17 +1395,18 @@ msgstr "" #: src/bare-metal/useful-crates/spin.md:30 src/bare-metal/android/vmbase.md:25 #: src/exercises/bare-metal/afternoon.md:11 src/concurrency/threads.md:45 #: src/concurrency/scoped-threads.md:40 src/concurrency/channels.md:32 -#: src/concurrency/send-sync.md:23 src/concurrency/send-sync/send.md:16 -#: src/concurrency/send-sync/sync.md:18 src/concurrency/shared_state/arc.md:38 +#: src/concurrency/channels/bounded.md:35 src/concurrency/send-sync.md:23 +#: src/concurrency/send-sync/send.md:16 src/concurrency/send-sync/sync.md:18 +#: src/concurrency/shared_state/arc.md:38 #: src/concurrency/shared_state/mutex.md:45 #: src/concurrency/shared_state/example.md:56 #: src/exercises/concurrency/morning.md:16 src/async/async-await.md:48 #: src/async/futures.md:45 src/async/runtimes.md:29 -#: src/async/runtimes/tokio.md:49 src/async/tasks.md:64 +#: src/async/runtimes/tokio.md:49 src/async/tasks.md:63 #: src/async/channels.md:49 src/async/control-flow/join.md:50 -#: src/async/control-flow/select.md:77 +#: src/async/control-flow/select.md:79 #: src/async/pitfalls/blocking-executor.md:50 src/async/pitfalls/pin.md:112 -#: src/async/pitfalls/async-traits.md:63 +#: src/async/pitfalls/async-traits.md:63 src/async/pitfalls/cancellation.md:114 #: src/exercises/concurrency/afternoon.md:17 #: src/exercises/concurrency/dining-philosophers-async.md:79 msgid "
" @@ -1752,12 +1772,13 @@ msgstr "" #: src/running-the-course/translations.md:16 msgid "" +"* [Bengali][bn] by [@raselmandol].\n" "* [French][fr] by [@KookaS] and [@vcaen].\n" "* [German][de] by [@Throvn] and [@ronaldfw].\n" "* [Japanese][ja] by [@CoinEZ-JPN] and [@momotaro1105]." msgstr "" -#: src/running-the-course/translations.md:20 +#: src/running-the-course/translations.md:21 msgid "" "If you want to help with this effort, please see [our instructions] for how " "to\n" @@ -2542,6 +2563,7 @@ msgstr "" "entrées." #: src/hello-world/small-example.md:29 +#, fuzzy msgid "" "* Explain that all variables are statically typed. Try removing `i32` to " "trigger\n" @@ -2561,7 +2583,10 @@ msgid "" "fmt`\n" " which has the rules of the formatting mini-language. It's important that " "the\n" -" students become familiar with searching in the standard library." +" students become familiar with searching in the standard library.\n" +" \n" +" * In a shell `rustup doc std::fmt` will open a browser on the local std::" +"fmt documentation" msgstr "" "* Expliquez que toutes les variables sont typées statiquement. Essayez de " "supprimer `i32` pour déclencher\n" @@ -3268,7 +3293,7 @@ msgstr "Une tranche vous donne une vue dans une plus grande collection :" msgid "" "```rust,editable\n" "fn main() {\n" -" let a: [i32; 6] = [10, 20, 30, 40, 50, 60];\n" +" let mut a: [i32; 6] = [10, 20, 30, 40, 50, 60];\n" " println!(\"a: {a:?}\");\n" "\n" " let s: &[i32] = &a[2..4];\n" @@ -4709,7 +4734,7 @@ msgstr "" #: src/memory-management/rust.md:10 #, fuzzy -msgid "It achieves this by modeling _ownership_ explicitly." +msgid "Rust achieves this by modeling _ownership_ explicitly." msgstr "Il y parvient en modélisant explicitement _ownership_." #: src/memory-management/rust.md:14 @@ -5318,7 +5343,7 @@ msgid "" "* The Rust compiler can do return value optimization (RVO).\n" "* In C++, copy elision has to be defined in the language specification " "because constructors can have side effects. In Rust, this is not an issue at " -"all. If RVO did not happen, Rust will always performs a simple and efficient " +"all. If RVO did not happen, Rust will always perform a simple and efficient " "`memcpy` copy." msgstr "" @@ -5405,7 +5430,7 @@ msgid "" " a valid solution.\n" "* Lifetimes for function arguments and return values must be fully " "specified,\n" -" but Rust allows these to be elided in most cases with [a few simple\n" +" but Rust allows lifetimes to be elided in most cases with [a few simple\n" " rules](https://doc.rust-lang.org/nomicon/lifetime-elision.html)." msgstr "" @@ -5690,13 +5715,15 @@ msgid "" "fn main() {\n" " let library = Library::new();\n" "\n" -" //println!(\"The library is empty: {}\", library.is_empty());\n" +" //println!(\"The library is empty: library.is_empty() -> {}\", 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" " //\n" -" //println!(\"The library is no longer empty: {}\", library.is_empty());\n" +" //println!(\"The library is no longer empty: library.is_empty() -> {}\", " +"library.is_empty());\n" " //\n" " //\n" " //library.print_books();\n" @@ -6029,7 +6056,7 @@ msgid "" "```" msgstr "" -#: src/structs.md:31 src/enums.md:33 src/enums/sizes.md:29 src/methods.md:30 +#: src/structs.md:31 src/enums.md:34 src/enums/sizes.md:29 src/methods.md:30 #: src/methods/example.md:46 src/pattern-matching.md:25 #: src/pattern-matching/match-guards.md:22 src/control-flow/blocks.md:42 #, fuzzy @@ -6120,7 +6147,9 @@ msgid "" "single field in the newtype.\n" " * Rust generally doesn’t like inexplicit things, like automatic " "unwrapping or for instance using booleans as integers.\n" -" * Operator overloading is discussed on Day 3 (generics). " +" * Operator overloading is discussed on Day 3 (generics).\n" +"* The example is a subtle reference to the [Mars Climate Orbiter](https://en." +"wikipedia.org/wiki/Mars_Climate_Orbiter) failure." msgstr "" "* Les nouveaux types sont un excellent moyen d'encoder des informations " "supplémentaires sur la valeur dans un type primitif, par exemple :\n" @@ -6240,6 +6269,7 @@ msgstr "" 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" @@ -6264,7 +6294,7 @@ msgid "" "```" msgstr "" -#: src/enums.md:35 +#: src/enums.md:36 #, fuzzy msgid "" "* Enumerations allow you to collect a set of values under one type\n" @@ -6471,7 +6501,7 @@ msgid "" " * `dbg_size!(Option<&i32>)`: size 8 bytes, align: 8 bytes (null pointer " "optimization, see below).\n" "\n" -" * Niche optimization: Rust will merge use unused bit patterns for the enum\n" +" * Niche optimization: Rust will merge unused bit patterns for the enum\n" " discriminant.\n" "\n" " * Null pointer optimization: For [some\n" @@ -7205,7 +7235,7 @@ msgid "" "// TODO: remove this when you're done with your implementation.\n" "#![allow(unused_variables, dead_code)]\n" "\n" -"struct User {\n" +"pub struct User {\n" " name: String,\n" " age: u32,\n" " weight: f32,\n" @@ -7628,8 +7658,8 @@ msgstr "" #: src/control-flow/if-let-expressions.md:23 msgid "" -"* `if let` can be more concise than `match`, e.g., when only one case is " -"interesting. In contrast, `match` requires all branches to be covered.\n" +"* Unlike `match`, `if let` does not have to cover all branches. This can " +"make it more concise than `match`.\n" "* A common usage is handling `Some` values when working with `Option`.\n" "* Unlike `match`, `if let` does not support guard clauses for pattern " "matching.\n" @@ -7753,7 +7783,7 @@ msgstr "## Boucles `for`" #, fuzzy msgid "" "The [`for` loop](https://doc.rust-lang.org/std/keyword.for.html) is closely\n" -"related to the [`while let` loop](while-let-expression.md). It will\n" +"related to the [`while let` loop](while-let-expressions.md). It will\n" "automatically call `into_iter()` on the expression and then iterate over it:" msgstr "" "L'expression `for` est étroitement liée à l'expression `while let`. Ce sera\n" @@ -9633,7 +9663,7 @@ msgid "" "\n" "* Move method `not_equal` to a new trait `NotEqual`.\n" "\n" -"* Make `NotEqual` a super trait for `Equal`.\n" +"* Make `Equals` a super trait for `NotEqual`.\n" " ```rust,editable,compile_fail\n" " trait NotEqual: Equals {\n" " fn not_equal(&self, other: &Self) -> bool {\n" @@ -9654,8 +9684,8 @@ msgid "" " }\n" " }\n" " ```\n" -" * With the blanket implementation, you no longer need `NotEqual` as a " -"super trait for `Equal`.\n" +" * With the blanket implementation, you no longer need `Equals` as a super " +"trait for `NotEqual`.\n" " " msgstr "" "* Les caractéristiques peuvent spécifier des méthodes pré-implémentées (par " @@ -10768,19 +10798,21 @@ msgid "" "```rust,editable\n" "use std::panic;\n" "\n" -"let result = panic::catch_unwind(|| {\n" -" println!(\"hello!\");\n" -"});\n" -"assert!(result.is_ok());\n" -"\n" -"let result = panic::catch_unwind(|| {\n" -" panic!(\"oh no!\");\n" -"});\n" -"assert!(result.is_err());\n" +"fn main() {\n" +" let result = panic::catch_unwind(|| {\n" +" println!(\"hello!\");\n" +" });\n" +" assert!(result.is_ok());\n" +" \n" +" let result = panic::catch_unwind(|| {\n" +" panic!(\"oh no!\");\n" +" });\n" +" assert!(result.is_err());\n" +"}\n" "```" msgstr "" -#: src/error-handling/panic-unwind.md:19 +#: src/error-handling/panic-unwind.md:21 #, fuzzy msgid "" "* This can be useful in servers which should keep running even if a single\n" @@ -10812,11 +10844,11 @@ msgstr "" #: src/error-handling/result.md:6 msgid "" "```rust,editable\n" -"use std::fs::File;\n" +"use std::fs;\n" "use std::io::Read;\n" "\n" "fn main() {\n" -" let file = File::open(\"diary.txt\");\n" +" let file = fs::File::open(\"diary.txt\");\n" " match file {\n" " Ok(mut file) => {\n" " let mut contents = String::new();\n" @@ -10905,8 +10937,8 @@ msgstr "" #: src/error-handling/try-operator.md:21 msgid "" "```rust,editable\n" -"use std::fs;\n" -"use std::io::{self, Read};\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" @@ -11090,7 +11122,7 @@ msgid "" "}\n" "\n" "fn read_username(path: &str) -> Result {\n" -" let mut username = String::with_capacity(100);\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" @@ -11149,7 +11181,7 @@ msgstr "" #: src/error-handling/dynamic-errors.md:6 msgid "" "```rust,editable,compile_fail\n" -"use std::fs::{self, File};\n" +"use std::fs;\n" "use std::io::Read;\n" "use thiserror::Error;\n" "use std::error::Error;\n" @@ -11159,8 +11191,8 @@ msgid "" "struct EmptyUsernameError(String);\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" +" 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" @@ -12130,7 +12162,7 @@ msgid "" "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};\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" @@ -12140,23 +12172,25 @@ msgid "" "PhantomPinned)>,\n" " }\n" "\n" -" // Layout as per readdir(3) and definitions in /usr/include/x86_64-linux-" -"gnu.\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_long,\n" -" pub d_off: c_ulong,\n" +" pub d_ino: c_ulong,\n" +" pub d_off: c_long,\n" " pub d_reclen: c_ushort,\n" -" pub d_type: c_char,\n" +" pub d_type: c_uchar,\n" " pub d_name: [c_char; 256],\n" " }\n" "\n" -" // Layout as per man entry for dirent\n" -" #[cfg(target_os = \"macos\")]\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_ino: u64,\n" +" pub d_fileno: u64,\n" " pub d_seekoff: u64,\n" " pub d_reclen: u16,\n" " pub d_namlen: u16,\n" @@ -12166,7 +12200,22 @@ msgid "" "\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" @@ -15029,6 +15078,136 @@ msgstr "" "conçue uniquement pour\n" " machines virtuelles." +#: src/bare-metal/aps/entry-point.md:1 +msgid "# Getting Ready to Rust" +msgstr "" + +#: src/bare-metal/aps/entry-point.md:3 +msgid "" +"Before we can start running Rust code, we need to do some initialisation." +msgstr "" + +#: src/bare-metal/aps/entry-point.md:5 +msgid "" +"```armasm\n" +".section .init.entry, \"ax\"\n" +".global entry\n" +"entry:\n" +" /*\n" +" * Load and apply the memory management configuration, ready to enable " +"MMU and\n" +" * caches.\n" +" */\n" +" adrp x30, idmap\n" +" msr ttbr0_el1, x30\n" +"\n" +" mov_i x30, .Lmairval\n" +" msr mair_el1, x30\n" +"\n" +" mov_i x30, .Ltcrval\n" +" /* Copy the supported PA range into TCR_EL1.IPS. */\n" +" mrs x29, id_aa64mmfr0_el1\n" +" bfi x30, x29, #32, #4\n" +"\n" +" msr tcr_el1, x30\n" +"\n" +" mov_i x30, .Lsctlrval\n" +"\n" +" /*\n" +" * Ensure everything before this point has completed, then invalidate " +"any\n" +" * potentially stale local TLB entries before they start being used.\n" +" */\n" +" isb\n" +" tlbi vmalle1\n" +" ic iallu\n" +" dsb nsh\n" +" isb\n" +"\n" +" /*\n" +" * Configure sctlr_el1 to enable MMU and cache and don't proceed until " +"this\n" +" * has completed.\n" +" */\n" +" msr sctlr_el1, x30\n" +" isb\n" +"\n" +" /* Disable trapping floating point access in EL1. */\n" +" mrs x30, cpacr_el1\n" +" orr x30, x30, #(0x3 << 20)\n" +" msr cpacr_el1, x30\n" +" isb\n" +"\n" +" /* Zero out the bss section. */\n" +" adr_l x29, bss_begin\n" +" adr_l x30, bss_end\n" +"0: cmp x29, x30\n" +" b.hs 1f\n" +" stp xzr, xzr, [x29], #16\n" +" b 0b\n" +"\n" +"1: /* Prepare the stack. */\n" +" adr_l x30, boot_stack_end\n" +" mov sp, x30\n" +"\n" +" /* Set up exception vector. */\n" +" adr x30, vector_table_el1\n" +" msr vbar_el1, x30\n" +"\n" +" /* Call into Rust code. */\n" +" bl main\n" +"\n" +" /* Loop forever waiting for interrupts. */\n" +"2: wfi\n" +" b 2b\n" +"```" +msgstr "" + +#: src/bare-metal/aps/entry-point.md:77 +msgid "" +"* This is the same as it would be for C: initialising the processor state, " +"zeroing the BSS, and\n" +" setting up the stack pointer.\n" +" * The BSS (block starting symbol, for historical reasons) is the part of " +"the object file which\n" +" containing statically allocated variables which are initialised to zero. " +"They are omitted from\n" +" the image, to avoid wasting space on zeroes. The compiler assumes that " +"the loader will take care\n" +" of zeroing them.\n" +"* The BSS may already be zeroed, depending on how memory is initialised and " +"the image is loaded, but\n" +" we zero it to be sure.\n" +"* We need to enable the MMU and cache before reading or writing any memory. " +"If we don't:\n" +" * Unaligned accesses will fault. We build the Rust code for the `aarch64-" +"unknown-none` target\n" +" which sets `+strict-align` to prevent the compiler generating unaligned " +"accesses, so it should\n" +" be fine in this case, but this is not necessarily the case in general.\n" +" * If it were running in a VM, this can lead to cache coherency issues. The " +"problem is that the VM\n" +" is accessing memory directly with the cache disabled, while the host has " +"cachable aliases to the\n" +" same memory. Even if the host doesn't explicitly access the memory, " +"speculative accesses can\n" +" lead to cache fills, and then changes from one or the other will get " +"lost when the cache is\n" +" cleaned or the VM enables the cache. (Cache is keyed by physical " +"address, not VA or IPA.)\n" +"* For simplicity, we just use a hardcoded pagetable (see `idmap.S`) which " +"identity maps the first 1\n" +" GiB of address space for devices, the next 1 GiB for DRAM, and another 1 " +"GiB higher up for more\n" +" devices. This matches the memory layout that QEMU uses.\n" +"* We also set up the exception vector (`vbar_el1`), which we'll see more " +"about later.\n" +"* All examples this afternoon assume we will be running at exception level 1 " +"(EL1). If you need to\n" +" run at a different exception level you'll need to modify `entry.S` " +"accordingly." +msgstr "" + #: src/bare-metal/aps/inline-assembly.md:1 #, fuzzy msgid "# Inline assembly" @@ -15838,6 +16017,99 @@ msgstr "" "* Exécutez l'exemple dans QEMU avec `make qemu_logger` sous `src/bare-metal/" "aps/examples`." +#: src/bare-metal/aps/exceptions.md:1 +#, fuzzy +msgid "# Exceptions" +msgstr "# Les fonctions" + +#: src/bare-metal/aps/exceptions.md:3 +msgid "" +"AArch64 defines an exception vector table with 16 entries, for 4 types of " +"exceptions (synchronous,\n" +"IRQ, FIQ, SError) from 4 states (current EL with SP0, current EL with SPx, " +"lower EL using AArch64,\n" +"lower EL using AArch32). We implement this in assembly to save volatile " +"registers to the stack\n" +"before calling into Rust code:" +msgstr "" + +#: src/bare-metal/aps/exceptions.md:8 +msgid "" +"```rust,editable,compile_fail\n" +"use log::error;\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" +" error!(\"irq_current\");\n" +" system_off::().unwrap();\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/bare-metal/aps/exceptions.md:64 +msgid "" +"* EL is exception level; all our examples this afternoon run in EL1.\n" +"* For simplicity we aren't distinguishing between SP0 and SPx for the " +"current EL exceptions, or\n" +" between AArch32 and AArch64 for the lower EL exceptions.\n" +"* For this example we just log the exception and power down, as we don't " +"expect any of them to\n" +" actually happen.\n" +"* We can think of exception handlers and our main execution context more or " +"less like different\n" +" threads. [`Send` and `Sync`][1] will control what we can share between " +"them, just like with threads.\n" +" For example, if we want to share some value between exception handlers and " +"the rest of the\n" +" program, and it's `Send` but not `Sync`, then we'll need to wrap it in " +"something like a `Mutex`\n" +" and put it in a static." +msgstr "" + #: src/bare-metal/aps/other-projects.md:3 #, fuzzy msgid "" @@ -15848,8 +16120,11 @@ msgid "" " * [Rust RaspberryPi OS tutorial](https://github.com/rust-embedded/rust-" "raspberrypi-OS-tutorials)\n" " * Initialisation, UART driver, simple bootloader, JTAG, exception levels, " -"exception handling, page tables\n" -" * Not all very well written, so beware.\n" +"exception handling,\n" +" page tables\n" +" * Some dodginess around cache maintenance and initialisation in Rust, not " +"necessarily a good\n" +" example to copy for production code.\n" " * [`cargo-call-stack`](https://crates.io/crates/cargo-call-stack)\n" " * Static analysis to determine maximum stack usage." msgstr "" @@ -15866,6 +16141,29 @@ msgstr "" " * [`pile-appel-cargo`](https://crates.io/crates/pile-appel-cargo)\n" " * Analyse statique pour déterminer l'utilisation maximale de la pile." +#: src/bare-metal/aps/other-projects.md:17 +msgid "" +"* The RaspberryPi OS tutorial runs Rust code before the MMU and caches are " +"enabled. This will read\n" +" and write memory (e.g. the stack). However:\n" +" * Without the MMU and cache, unaligned accesses will fault. It builds with " +"`aarch64-unknown-none`\n" +" which sets `+strict-align` to prevent the compiler generating unaligned " +"accesses so it should be\n" +" alright, but this is not necessarily the case in general.\n" +" * If it were running in a VM, this can lead to cache coherency issues. The " +"problem is that the VM\n" +" is accessing memory directly with the cache disabled, while the host has " +"cachable aliases to the\n" +" same memory. Even if the host doesn't explicitly access the memory, " +"speculative accesses can\n" +" lead to cache fills, and then changes from one or the other will get " +"lost. Again this is alright\n" +" in this particular case (running directly on the hardware with no " +"hypervisor), but isn't a good\n" +" pattern in general." +msgstr "" + #: src/bare-metal/useful-crates.md:1 #, fuzzy msgid "# Useful crates" @@ -17736,7 +18034,8 @@ msgstr "# Canaux limités" #: src/concurrency/channels/bounded.md:3 #, fuzzy -msgid "Bounded and synchronous channels make `send` block the current thread:" +msgid "" +"With bounded (synchronous) channels, `send` can block the current thread:" msgstr "" "Les canaux bornés et synchrones font que \"send\" bloque le thread actuel :" @@ -17767,6 +18066,19 @@ msgid "" "```" msgstr "" +#: src/concurrency/channels/bounded.md:31 +msgid "" +"* Calling `send` will block the current thread until there is space in the " +"channel for the new message. The thread can be blocked indefinitely if there " +"is nobody who reads from the channel.\n" +"* A call to `send` will abort with an error (that is why it returns " +"`Result`) if the channel is closed. A channel is closed when the receiver is " +"dropped.\n" +"* A bounded channel with a size of zero is called a \"rendezvous channel\". " +"Every send will block the current thread until another thread calls `read`.\n" +" " +msgstr "" + #: src/concurrency/send-sync.md:1 #, fuzzy msgid "# `Send` and `Sync`" @@ -18176,7 +18488,8 @@ msgid "" "* You can get an `&mut T` from an `&Mutex` by taking the lock. The " "`MutexGuard` ensures that the\n" " `&mut T` doesn't outlive the lock being held.\n" -"* `Mutex` implements both `Send` and `Sync` iff `T` implements `Send`.\n" +"* `Mutex` implements both `Send` and `Sync` iff (if and only if) `T` " +"implements `Send`.\n" "* A read-write lock counterpart - `RwLock`.\n" "* Why does `lock()` return a `Result`? \n" " * If the thread that held the `Mutex` panicked, the `Mutex` becomes " @@ -18937,12 +19250,10 @@ msgid "# Tasks" msgstr "## Tâches" #: src/async/tasks.md:3 -msgid "" -"Runtimes have the concept of a \"task\", similar to a thread but much\n" -"less resource-intensive." +msgid "Rust has a task system, which is a form of lightweight threading." msgstr "" -#: src/async/tasks.md:6 +#: src/async/tasks.md:5 msgid "" "A task has a single top-level future which the executor polls to make " "progress.\n" @@ -18953,7 +19264,7 @@ msgid "" "polling multiple child futures, such as racing a timer and an I/O operation." msgstr "" -#: src/async/tasks.md:11 +#: src/async/tasks.md:10 msgid "" "```rust,compile_fail\n" "use tokio::io::{self, AsyncReadExt, AsyncWriteExt};\n" @@ -18997,12 +19308,12 @@ msgid "" "```" msgstr "" -#: src/async/tasks.md:53 src/async/control-flow/join.md:36 +#: src/async/tasks.md:52 src/async/control-flow/join.md:36 msgid "" "Copy this example into your prepared `src/main.rs` and run it from there." msgstr "" -#: src/async/tasks.md:55 +#: src/async/tasks.md:54 msgid "" "* Ask students to visualize what the state of the example server would be " "with a\n" @@ -19023,8 +19334,7 @@ msgstr "# Chaînes" #: src/async/channels.md:3 msgid "" -"Several crates have support for `async`/`await`. For instance `tokio` " -"channels:" +"Several crates have support for asynchronous channels. For instance `tokio`:" msgstr "" #: src/async/channels.md:5 @@ -19172,14 +19482,16 @@ msgstr "" #: src/async/control-flow/select.md:8 msgid "" -"This is usually a macro, similar to match, with each arm of the form " -"`pattern =\n" -"future => statement`. When the future is ready, the statement is executed " -"with the\n" -"variable bound to the future's result." +"Similar to a match statement, the body of `select!` has a number of arms, " +"each\n" +"of the form `pattern = future => statement`. When the `future` is ready, " +"the\n" +"`statement` is executed with the variables in `pattern` bound to the " +"`future`'s\n" +"result." msgstr "" -#: src/async/control-flow/select.md:12 +#: src/async/control-flow/select.md:13 msgid "" "```rust,editable,compile_fail\n" "use tokio::sync::mpsc::{self, Receiver};\n" @@ -19229,7 +19541,7 @@ msgid "" "```" msgstr "" -#: src/async/control-flow/select.md:61 +#: src/async/control-flow/select.md:62 msgid "" "* In this example, we have a race between a cat and a dog.\n" " `first_animal_to_finish_race` listens to both channels and will pick " @@ -19245,11 +19557,14 @@ msgid "" "of\n" " futures.\n" "\n" -"* Note that `select!` moves the values it is given. It is easiest to use\n" -" when every execution of `select!` creates new futures. An alternative is " -"to\n" -" pass `&mut future` instead of the future itself, but this can lead to\n" -" issues, further discussed in the pinning slide." +"* Note that `select!` drops unmatched branches, which cancels their " +"futures.\n" +" It is easiest to use when every execution of `select!` creates new " +"futures.\n" +"\n" +" * An alternative is to pass `&mut future` instead of the future itself, " +"but\n" +" this can lead to issues, further discussed in the pinning slide." msgstr "" #: src/async/pitfalls.md:1 @@ -19268,7 +19583,8 @@ msgstr "" msgid "" "- [Blocking the Executor](pitfalls/blocking-executor.md)\n" "- [Pin](pitfalls/pin.md)\n" -"- [Async Traits](pitfall/async-traits.md)" +"- [Async Traits](pitfalls/async-traits.md)\n" +"- [Cancellation](pitfalls/cancellation.md)" msgstr "" #: src/async/pitfalls/blocking-executor.md:1 @@ -19561,6 +19877,142 @@ msgid "" " and adding it to the Vec." msgstr "" +#: src/async/pitfalls/cancellation.md:1 +#, fuzzy +msgid "# Cancellation" +msgstr "# Cancellation" + +#: src/async/pitfalls/cancellation.md:3 +msgid "" +"Dropping a future implies it can never be polled again. This is called " +"*cancellation*\n" +"and it can occur at any `await` point. Care is needed to ensure the system " +"works\n" +"correctly even when futures are cancelled. For example, it shouldn't " +"deadlock or\n" +"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" +"```" +msgstr "" + +#: src/async/pitfalls/cancellation.md:72 +msgid "" +"* The compiler doesn't help with cancellation-safety. You need to read API\n" +" documentation and consider what state your `async fn` holds.\n" +"\n" +"* Unlike `panic` and `?`, cancellation is part of normal control flow\n" +" (vs error-handling).\n" +"\n" +"* The example loses parts of the string.\n" +"\n" +" * Whenever the `tick()` branch finishes first, `next()` and its `buf` " +"are dropped.\n" +"\n" +" * `LinesReader` can be made cancellation-safe by makeing `buf` part of " +"the struct:\n" +" ```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" +" ```\n" +"\n" +"* [`Interval::tick`](https://docs.rs/tokio/latest/tokio/time/struct.Interval." +"html#method.tick)\n" +" is cancellation-safe because it keeps track of whether a tick has been " +"'delivered'.\n" +"\n" +"* [`AsyncReadExt::read`](https://docs.rs/tokio/latest/tokio/io/trait." +"AsyncReadExt.html#method.read)\n" +" is cancellation-safe because it either returns or doesn't read data.\n" +"\n" +"* [`AsyncBufReadExt::read_line`](https://docs.rs/tokio/latest/tokio/io/trait." +"AsyncBufReadExt.html#method.read_line)\n" +" is similar to the example and *isn't* cancellation-safe. See its " +"documentation\n" +" for details and alternatives." +msgstr "" + #: src/exercises/concurrency/afternoon.md:3 msgid "" "To practice your Async Rust skills, we have again two exercises for you:" @@ -19744,7 +20196,7 @@ msgid "" " Websocket Stream.\n" "- [SinkExt::send()][4] implemented by `WebsocketStream`: for asynchronously\n" " sending messages on a Websocket Stream.\n" -"- [BufReader::read_line()][5]: for asynchronously reading user messages\n" +"- [Lines::next_line()][5]: for asynchronously reading user messages\n" " from the standard input.\n" "- [Sender::subscribe()][6]: for subscribing to a broadcast channel." msgstr "" @@ -19852,7 +20304,7 @@ msgid "" " .await?;\n" "\n" " let stdin = tokio::io::stdin();\n" -" let mut stdin = BufReader::new(stdin);\n" +" let mut stdin = BufReader::new(stdin).lines();\n" "\n" "\n" " // TODO: For a hint, see the description of the task below.\n" @@ -20166,21 +20618,25 @@ msgstr "" "ressources." #: src/credits.md:7 +#, fuzzy msgid "" "The material of Comprehensive Rust is licensed under the terms of the Apache " "2.0\n" -"license, please see [`LICENSE`](../LICENSE) for details." +"license, please see\n" +"[`LICENSE`](https://github.com/google/comprehensive-rust/blob/main/LICENSE) " +"for\n" +"details." msgstr "" "Le matériel de Comprehensive Rust(le guide complet de Rust) est sous licence " "sous les termes de la licence d'Apache 2.0,\n" "veuillez consulter [`LICENSE`](../LICENSE) pour plus de détails." -#: src/credits.md:10 +#: src/credits.md:12 #, fuzzy msgid "## Rust by Example" msgstr "## Rouille par exemple" -#: src/credits.md:12 +#: src/credits.md:14 #, fuzzy msgid "" "Some examples and exercises have been copied and adapted from [Rust by\n" @@ -20194,12 +20650,12 @@ msgstr "" "licence\n" "conditions." -#: src/credits.md:17 +#: src/credits.md:19 #, fuzzy msgid "## Rust on Exercism" msgstr "## Rouille sur l'exercice" -#: src/credits.md:19 +#: src/credits.md:21 #, fuzzy msgid "" "Some exercises have been copied and adapted from [Rust on\n" @@ -20214,12 +20670,12 @@ msgstr "" "la licence\n" "conditions." -#: src/credits.md:24 +#: src/credits.md:26 #, fuzzy msgid "## CXX" msgstr "## CXX" -#: src/credits.md:26 +#: src/credits.md:28 #, fuzzy msgid "" "The [Interoperability with C++](android/interoperability/cpp.md) section " @@ -20577,13 +21033,15 @@ msgid "" "fn main() {\n" " let library = Library::new();\n" "\n" -" //println!(\"The library is empty: {}\", library.is_empty());\n" +" //println!(\"The library is empty: library.is_empty() -> {}\", 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" " //\n" -" //println!(\"The library is no longer empty: {}\", library.is_empty());\n" +" //println!(\"The library is no longer empty: library.is_empty() -> {}\", " +"library.is_empty());\n" " //\n" " //\n" " //library.print_books();\n" @@ -21038,23 +21496,30 @@ msgid "" "// ANCHOR: prefix_matches\n" "pub fn prefix_matches(prefix: &str, request_path: &str) -> bool {\n" " // ANCHOR_END: prefix_matches\n" -" let prefixes = prefix.split('/');\n" -" let request_paths = request_path\n" -" .split('/')\n" -" .map(|p| Some(p))\n" -" .chain(std::iter::once(None));\n" -"\n" -" for (prefix, request_path) in prefixes.zip(request_paths) {\n" -" match request_path {\n" -" Some(request_path) => {\n" -" if (prefix != \"*\") && (prefix != request_path) {\n" -" return false;\n" -" }\n" -" }\n" -" None => return false,\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 " +"prefix\n" +" // and request segments. The zip() iterator is finished as soon as one " +"of\n" +" // the source iterators is finished, but we need to iterate over all " +"request\n" +" // segments. A neat trick that makes zip() work is to use map() and " +"chain()\n" +" // to produce an iterator that returns Some(str) for each pattern " +"segments,\n" +" // and then returns None indefinitely.\n" "}\n" "\n" "// ANCHOR: unit-tests\n" @@ -21323,7 +21788,7 @@ msgid "" "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};\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" @@ -21333,23 +21798,25 @@ msgid "" "PhantomPinned)>,\n" " }\n" "\n" -" // Layout as per readdir(3) and definitions in /usr/include/x86_64-linux-" -"gnu.\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_long,\n" -" pub d_off: c_ulong,\n" +" pub d_ino: c_ulong,\n" +" pub d_off: c_long,\n" " pub d_reclen: c_ushort,\n" -" pub d_type: c_char,\n" +" pub d_type: c_uchar,\n" " pub d_name: [c_char; 256],\n" " }\n" "\n" -" // Layout as per man entry for dirent\n" -" #[cfg(target_os = \"macos\")]\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_ino: u64,\n" +" pub d_fileno: u64,\n" " pub d_seekoff: u64,\n" " pub d_reclen: u16,\n" " pub d_namlen: u16,\n" @@ -21359,7 +21826,22 @@ msgid "" "\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" @@ -22336,12 +22818,11 @@ msgid "" " .await?;\n" "\n" " let stdin = tokio::io::stdin();\n" -" let mut stdin = BufReader::new(stdin);\n" +" let mut stdin = BufReader::new(stdin).lines();\n" "\n" " // ANCHOR_END: setup\n" " // Continuous loop for concurrently sending and receiving messages.\n" " loop {\n" -" let mut line = String::new();\n" " tokio::select! {\n" " incoming = ws_stream.next() => {\n" " match incoming {\n" @@ -22351,10 +22832,10 @@ msgid "" " None => return Ok(()),\n" " }\n" " }\n" -" res = stdin.read_line(&mut line) => {\n" +" res = stdin.next_line() => {\n" " match res {\n" -" Ok(0) => return Ok(()),\n" -" Ok(_) => ws_stream.send(Message::text(line.trim_end()." +" 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"