Comprehensive Rust ðŠ ãžãããã
This is a free Rust course developed by the Android team at Google. The course covers the full spectrum of Rust, from basic syntax to advanced topics like generics and error handling.
ã³ãŒã¹ã®ææ°ããŒãžã§ã³ã¯ https://google.github.io/comprehensive-rust/ ã«ãããŸããä»ã®å Žæã§ãèªã¿ã®å Žåã¯ããã¡ãã§ææ°æ å ±ãã確èªãã ããã
The course is available in other languages. Select your preferred language in the top right corner of the page or check the Translations page for a list of all available translations.
The course is also available as a PDF.
æ¬è¬åº§ã®ç®çã¯ãRustãæããäºã§ããRustã«é¢ããåæç¥èã¯äžèŠãšããŠããã次ã®ç®æšãèšå®ããŠããŸãïŒ
- Rustã®åºæ¬æ§æãšèšèªã«ã€ããŠã®ç解ãæ·±ããã
- æ¢åã®ããã°ã©ã ãä¿®æ£ããããæ°èŠããã°ã©ã ãRustã§æžããããã«ããã
- äžè¬çãªRustã®ã€ãã£ãªã ã玹ä»ããã
ã³ãŒã¹ã®æåã®4æ¥éããRust ã®åºç€ããšåŒã³ãŸãã
Building on this, youâre invited to dive into one or more specialized topics:
- Android: a half-day course on using Rust for Android platform development (AOSP). This includes interoperability with C, C++, and Java.
- Chromium: a half-day course on using Rust within Chromium based browsers. This includes interoperability with C++ and how to include third-party crates in Chromium.
- Bare-metal: a whole-day class on using Rust for bare-metal (embedded) development. Both microcontrollers and application processors are covered.
- Concurrency: a whole-day class on concurrency in Rust. We cover both classical concurrency (preemptively scheduling using threads and mutexes) and async/await concurrency (cooperative multitasking using futures).
æ¬è¬åº§ã®å¯Ÿè±¡å€
Rustã¯éåžžã«æ±çšæ§ã®é«ãèšèªã§ãããæ°æ¥ã§å šãŠãç¶²çŸ ããäºã¯ã§ããŸãããæ¬è¬åº§ã®ç®æšãšããŠèšå®ãããŠããªããã®ã«ã¯ã以äžã®ãããªãã®ããããŸãïŒ
- Learning how to develop macros: please see Chapter 19.5 in the Rust Book and Rust by Example instead.
åæç¥è
The course assumes that you already know how to program. Rust is a statically-typed language and we will sometimes make comparisons with C and C++ to better explain or contrast the Rust approach.
If you know how to program in a dynamically-typed language such as Python or JavaScript, then you will be able to follow along just fine too.
Speaker Notes
ããã¯ã¹ããŒã«ãŒããŒãã®äžäŸã§ããããã䜿çšããŠã¹ã©ã€ããææããŸããè¬åž«ãã«ããŒãã¹ãèŠç¹ããææ¥ã§ããåºã質åãžã®åçãªã©ãå«ãŸããŸãã
è¬åº§ã®éå¶ã«ã€ããŠ
ãã®ããŒãžã¯è¬åž«çšã§ãã
以äžã¯ãGoogleå ã§ã®è¬åº§ã®éå¶æ¹æ³ã«é¢ããæ å ±ã§ãã
ã¯ã©ã¹ã¯éåžžåå9æããååŸ4æãŸã§ã§ãéäžã§1æéã®æŒé£äŒæ©ããããŸããã€ãŸããååã®ã¯ã©ã¹ã3æéãååŸã®ã¯ã©ã¹ã3æéãšãªããŸããã©ã¡ãã®ã»ãã·ã§ã³ã«ããäŒæ©ãšãåè¬è ãæŒç¿ã«åãçµãããã®æéãè€æ°åå«ãŸããŠããŸãã
è¬åº§éå§ãŸã§ã«ã以äžã«ãããæºåãæžãŸããŠãããšè¯ãã§ãããïŒ
-
è³æã«æ £ããŠãããŠãã ãããèŠç¹ã匷調ããããã«ã¹ããŒã«ãŒããŒããçšæãããŠããŸãïŒå 容ã®è¿œå ã«ãååãã ããïŒïŒããã¬ãŒã³æã«ã¯ãã¹ã¯ãªãŒã³ãèŠãããç¶æ ã§ä¿ã€ããã«ãã¹ããŒã«ãŒããŒãã¯ãããã¢ãããŠã£ã³ããŠã§éããŠãã ããïŒã¹ããŒã«ãŒããŒãã®æšªã«ããå°ããªç¢å°ãã¯ãªãã¯ïŒã
-
Decide on the dates. Since the course takes four days, we recommend that you schedule the days over two weeks. Course participants have said that they find it helpful to have a gap in the course since it helps them process all the information we give them.
-
ååãªåºãã®éšå±ã確ä¿ããŠãããŠãã ããã15~25åçšåºŠã®ã¯ã©ã¹ãæšå¥šããŠããŸããåè¬è ã«ãšã£ãŠè³ªåããããã人æ°ã§ããã1人ã®è¬åž«ã質åã«çããæéã確ä¿ã§ããèŠæš¡ã ããã§ãããŸããçããã¯PCã§äœæ¥ãããå¿ èŠããããããè¬åž«ãå«ãã人æ°åã®æºãçšæããŠãããŠãã ãããã©ã€ãã³ãŒãã£ã³ã°åœ¢åŒã§ã®å®æœãæ³å®ããŠãããããè¬å£ã¯äžèŠã§ãã
-
åœæ¥ã¯å°ãæ©ãã«å°çããŠæºåãããŠãã ãããèªåã®PCã§å®è¡ãã
mdbook serve
ããçŽæ¥ãã¬ãŒã³ãè¡ãäºãæšå¥šããŸãïŒã€ã³ã¹ããŒã«æé ã¯ãã¡ãïŒãããã«ãããããŒãžåãæ¿ãæã«é 延ãªãã§æé©ãªããã©ãŒãã³ã¹ãåŸãããŸãããŸããPCã䜿çšããäºã§ãåè¬è ãèªåèªèº«ãèŠã€ããã¿ã€ããã¹ãªã©ãä¿®æ£å¯èœã«ãªããŸãã -
ç·Žç¿åé¡ã¯å人ãå°ããã°ã«ãŒãã§è§£ããŠãã ãããåçãã¬ãã¥ãŒããæéãå«ããåç·Žç¿åé¡ã«30~45åãè²»ãããŸããåè¬è ãè¡ãè©°ãŸã£ãŠãããã©ãããäœã質åãããããªã©ç¢ºèªããŠãã ãããè€æ°ã®åè¬è ãåãåé¡ã§è©°ãŸã£ãŠããå Žåãã¯ã©ã¹å šäœã«å¯ŸããŠãããå ±æãã解決çãæäŸããŠãã ãããäŸãã°ãæ¢ããŠããæ å ±ãæšæºã©ã€ãã©ãªã®ã©ãã«ãããã瀺ãããªã©ã
以äžã§ããéå¶é 匵ã£ãŠãã ããïŒçããã«ãšã£ãŠã楜ããæéã«ãªããŸãããã«ïŒ
æ¬è¬åº§ã®æ¹åã«åããŠãã£ãŒãããã¯ããé¡ãããŸããããŸããã£ãç¹ãæ¹åç¹ã«ã€ããŠå¹ åºããæèŠãèãããã ãããåè¬è ããã®ãã£ãŒãããã¯ãæè¿ããŠãããŸãïŒ
è¬åº§ã®æ§æ
ãã®ããŒãžã¯è¬åž«çšã§ãã
Rust ã®åºç€
Rust ã®åºç€ ãæ§æããæåã® 4 æ¥éã§ãããŸããŸãªé ç®ãé§ã足ã§åŠã³ãŸãã
ã³ãŒã¹ã®ã¹ã±ãžã¥ãŒã«:
- Day 1 Morning (2 hours and 5 minutes, including breaks)
Segment | Duration |
---|---|
ãããã | 5 minutes |
Hello, World | 15 minutes |
åãšå€ | 40 minutes |
å¶åŸ¡ãããŒã®åºæ¬ | 40 minutes |
- Day 1 Afternoon (2 hours and 35 minutes, including breaks)
Segment | Duration |
---|---|
ã¿ãã«ãšé å | 35 minutes |
åç § | 55 minutes |
ãŠãŒã¶ãŒå®çŸ©å | 50 minutes |
- Day 2 Morning (2 hours and 10 minutes, including breaks)
Segment | Duration |
---|---|
ãããã | 3 minutes |
ãã¿ãŒã³ãããã³ã° | 1 hour |
Methods and Traits | 50 minutes |
- Day 2 Afternoon (3 hours and 15 minutes, including breaks)
Segment | Duration |
---|---|
ãžã§ããªã¯ã¹ïŒgenericsïŒ | 45 minutes |
æšæºã©ã€ãã©ãªå ã®å | 1 hour |
æšæºã©ã€ãã©ãªå ã®ãã¬ã€ã | 1 hour and 10 minutes |
- Day 3 Morning (2 hours and 20 minutes, including breaks)
Segment | Duration |
---|---|
ãããã | 3 minutes |
ã¡ã¢ãªç®¡ç | 1 hour |
ã¹ããŒããã€ã³ã¿ | 55 minutes |
- Day 3 Afternoon (1 hour and 55 minutes, including breaks)
Segment | Duration |
---|---|
åçš | 55 minutes |
ã©ã€ãã¿ã€ã | 50 minutes |
- Day 4 Morning (2 hours and 40 minutes, including breaks)
Segment | Duration |
---|---|
ãããã | 3 minutes |
ã€ãã¬ãŒã¿ | 45 minutes |
ã¢ãžã¥ãŒã« | 40 minutes |
ãã¹ã | 45 minutes |
- Day 4 Afternoon (2 hours and 20 minutes, including breaks)
Segment | Duration |
---|---|
ãšã©ãŒåŠç | 1 hour and 5 minutes |
Unsafe Rust | 1 hour and 5 minutes |
å°éçãªãããã¯
In addition to the 4-day class on Rust Fundamentals, we cover some more specialized topics:
Rust in Android
The Rust in Android deep dive is a half-day course on using Rust for Android platform development. This includes interoperability with C, C++, and Java.
AOSPã®ãã§ãã¯ã¢ãŠããå¿
èŠã§ããåã端æ«ããè¬åº§ã®ãªããžããªããã§ãã¯ã¢ãŠãããsrc/android/
ãã£ã¬ã¯ããªãAOSPãã§ãã¯ã¢ãŠãã®ã«ãŒãã«ç§»åããŠãã ãããããã«ãããAndroidãã«ãã·ã¹ãã ãsrc/android/
å
ã®Android.bp
ã確èªã§ããããã«ãªããŸãã
ãšãã¥ã¬ãŒã¿ãŸãã¯å®éã®ããã€ã¹ã§adb sync
ãæ©èœããäºã確èªããsrc/android/build_all.sh
ã䜿çšããŠå
šãŠã®Androidã®äŸãäºåã«ãã«ãããŠãã ãããã¹ã¯ãªãããèªãã§å®è¡ã³ãã³ãã確èªããæåã§å®è¡ããéã«æ£åžžã«åäœããäºã確èªããŠãã ããã
Rust in Chromium
Chromium ã§ã® Rust ã¯åæ¥ã³ãŒã¹ã§ãChromium ãã©ãŠã¶ã®äžéšãšã㊠Rust ã䜿çšããæ¹æ³ã«ã€ããŠè©³ãã説æããŸããChromium ã® gn
ãã«ãã·ã¹ãã 㧠Rust ã䜿çšããããšã§ããµãŒãããŒã㣠ã©ã€ãã©ãªïŒãã¯ã¬ãŒããïŒãããã³ C++ ãšã®çžäºéçšæ§ãå°å
¥ã§ããŸãã
åè¬è ã¯ãChromium ããã«ãã§ããå¿ èŠããããŸããæéãççž®ã§ãããããã°ã®ã³ã³ããŒãã³ã ãã«ãã æšå¥š ããŸãããã©ã®ãããªãã«ãã§ãåé¡ãããŸãããäœæãã Chromium ãã©ãŠã¶ãå®è¡ã§ããããšã確èªããŸãã
Bare-Metal Rust
The Bare-Metal Rust deep dive is a full day class on using Rust for bare-metal (embedded) development. Both microcontrollers and application processors are covered.
ãã€ã¯ãã³ã³ãããŒã©ã®ç« ã§ã¯ãäºåã«BBCmicro:bitv2éçºããŒããè³Œå ¥ããå¿ èŠããããŸãããŸããwelcomeããŒãžã§èª¬æãããŠããããã«ãè€æ°ã®ããã±ãŒãžãã€ã³ã¹ããŒã«ããå¿ èŠããããŸãã
Rustã§ã®äžŠè¡æ§
The Concurrency in Rust deep dive is a full day class on classical as well as async
/await
concurrency.
æ°èŠã¯ã¬ãŒãã®äœæãšãäŸåé¢ä¿ïŒdependenciesïŒã®ããŠã³ããŒããå¿
èŠã§ãããã®åŸãäŸãsrc/main.rs
ã«ã³ããããŠå®è¡ããäºãã§ããŸãïŒ
cargo init concurrency
cd concurrency
cargo add tokio --features full
cargo run
ã³ãŒã¹ã®ã¹ã±ãžã¥ãŒã«:
- Morning (3 hours and 20 minutes, including breaks)
Segment | Duration |
---|---|
ã¹ã¬ãã | 30 minutes |
ãã£ãã« | 20 minutes |
SendãšSync | 15 minutes |
ç¶æ å ±æ | 30 minutes |
ç·Žç¿åé¡ | 1 hour and 10 minutes |
- Afternoon (3 hours and 20 minutes, including breaks)
Segment | Duration |
---|---|
Asyncã®åºç€ | 30 minutes |
ãã£ãã«ãšå¶åŸ¡ãã㌠| 20 minutes |
èœãšãç©Ž | 55 minutes |
ç·Žç¿åé¡ | 1 hour and 10 minutes |
ãã©ãŒããã
æ¬è¬åº§ã¯ã€ã³ã¿ã©ã¯ãã£ããªåœ¢åŒã§è¡ããŸããç©æ¥µçã«è³ªåããŠãRustãžã®ç解ãæ·±ããŠãã ããïŒ
ããŒããŒã ã·ã§ãŒãã«ãã
mdBookã«ã¯ã䟿å©ãªã·ã§ãŒãã«ããããŒãããã€ãååšããŸãïŒ
- Arrow-Left: Navigate to the previous page.
- Arrow-Right: Navigate to the next page.
- Ctrl + Enter: Execute the code sample that has focus.
- s: Activate the search bar.
翻蚳
æ¬è³æã¯ããã©ã³ãã£ã¢ã«ãã£ãŠç¿»èš³ãããŠããŸãïŒ
- ãã«ãã¬ã«èªïŒãã©ãžã«ïŒ: @rastringerã@hugojacobã@joaovicmendesã@henrif75
- Chinese (Simplified) by @suetfei, @wnghl, @anlunx, @kongy, @noahdragon, @superwhd, @SketchK, and @nodmp.
- äžåœèªïŒç¹äœåïŒ: @hueichã@victorhsiehã@mingycã@kuanhungchenã@johnathan79717
- Farsi by @DannyRavi, @javad-jafari, @Alix1383, @moaminsharifi , @hamidrezakp and @mehrad77.
- Japanese by @CoinEZ-JPN, @momotaro1105, @HidenoriKobayashi and @kantasv.
- Korean by @keispace, @jiyongp, @jooyunghan, and @namhyung.
- ã¹ãã€ã³èª: @deavid
- Ukrainian by @git-user-cpp, @yaremam and @reta.
- Farsi by @DannyRavi, @javad-jafari, @Alix1383, @moaminsharifi, @hamidrezakp and @mehrad77.
ç»é¢å³äžã®èšèªåãæ¿ããã¿ã³ãããåãæ¿ããè¡ãªã£ãŠãã ããã
Incomplete Translations
é²è¡äžã®ç¿»èš³ãå€æ°ãããŸããææ°ã®ç¿»èš³ãžã®ãªã³ã¯ã以äžã«ç€ºããŸãã
- Arabic by @younies
- ãã³ã¬ã«èª: @raselmandol
- French by @KookaS, @vcaen and @AdrienBaudemont.
- ãã€ãèª: @Throvnã@ronaldfw
- Italian by @henrythebuilder and @detro.
The full list of translations with their current status is also available either as of their last update or synced to the latest version of the course.
ãã®åãçµã¿ã«ãååããã ããå Žåã¯ãour instructionsãã芧ãã ããã翻蚳ã¯issue trackerã§ç®¡çãããŠããŸãã
Cargoã®äœ¿çš
RustãåŠã³å§ãããšããŸããªãRustãšã³ã·ã¹ãã ã§åºã䜿ãããŠãããã«ãã·ã¹ãã å Œããã±ãŒãžãããŒãžã£ã§ããCargoãšããæšæºããŒã«ã«åºäŒããŸããããã§ã¯ãCargoã®æŠèŠã䜿çšæ¹æ³ããããŠæ¬è¬åº§ã«ãããéèŠæ§ã«ã€ããŠç°¡åã«èª¬æããŸãã
ã€ã³ã¹ããŒã«
https://rustup.rs/ ã®æé ã«æ²¿ã£ãŠã€ã³ã¹ããŒã«ããŠãã ããã
This will give you the Cargo build tool (cargo
) and the Rust compiler (rustc
). You will also get rustup
, a command line utility that you can use to install to different compiler versions.
Rust ãã€ã³ã¹ããŒã«ããããRust ã§åäœããããã«ãšãã£ã¿ãŸã㯠IDE ãèšå®ããå¿ èŠããããŸããã»ãšãã©ã®ãšãã£ã¿ã§ã¯ãrust-analyzer ãšéä¿¡ããããšã§ãããè¡ããŸããrust-analyzer ã¯ãVS CodeãEmacsãVim / Neovim ãªã©ãå€ãã®ãšãã£ã¿åãã«ãªãŒãã³ã³ããªãŒãæ©èœãšãå®çŸ©ã«ç§»åãæ©èœãæäŸããŸããRustRover ãšããå¥ã® IDE ãçšæãããŠããŸãã
Speaker Notes
-
On Debian/Ubuntu, you can also install Cargo, the Rust source and the Rust formatter via
apt
. However, this gets you an outdated Rust version and may lead to unexpected behavior. The command would be:sudo apt install cargo rust-src rustfmt
-
On macOS, you can use Homebrew to install Rust, but this may provide an outdated version. Therefore, it is recommended to install Rust from the official site.
Rust ãšã³ã·ã¹ãã
Rustãšã³ã·ã¹ãã ã®äž»èŠããŒã«ã¯ä»¥äžã®éãã§ãïŒ
-
rustc
ïŒ Rustã®ã³ã³ãã€ã©ã§ãã.rs
ãã¡ã€ã«ããã€ããªãä»ã®äžé圢åŒã«å€æããŸãã -
cargo
: the Rust dependency manager and build tool. Cargo knows how to download dependencies, usually hosted on https://crates.io, and it will pass them torustc
when building your project. Cargo also comes with a built-in test runner which is used to execute unit tests. -
rustup
: the Rust toolchain installer and updater. This tool is used to install and updaterustc
andcargo
when new versions of Rust are released. In addition,rustup
can also download documentation for the standard library. You can have multiple versions of Rust installed at once andrustup
will let you switch between them as needed.
Speaker Notes
èŠç¹ïŒ
-
Rustèšèªãšã³ã³ãã€ã©ã¯ã6é±éã®ãªãªãŒã¹ãµã€ã¯ã«ãæ¡çšããŠããŸããæ°ãããªãªãŒã¹ã¯ãå€ããªãªãŒã¹ãšã®åŸæ¹äºææ§ãç¶æããªãããæ°æ©èœãæäŸããŸãã
-
ãªãªãŒã¹ãã£ãã«ã¯3ã€ãããŸãïŒãstableããbetaããnightlyãã
-
æ°æ©èœã¯ãnightlyãã§ãã¹ãããããbetaãã6é±éæ¯ã«ãstableããšãªããŸãã
-
äŸåé¢ä¿ã¯ã代æ¿ã® ã¬ãžã¹ããªãgitããã©ã«ããªã©ãã解決ããããšãã§ããŸãã
-
Rustã«ã¯editionsïŒãšãã£ã·ã§ã³ïŒããããŸãïŒçŸåšã®ãšãã£ã·ã§ã³ã¯Rust2021ã§ãã以åã¯Rust2015ãšRust2018ã§ããã
-
ãšãã£ã·ã§ã³ã§ã¯ãåŸæ¹éäºæãªå€æŽãå ããäºãã§ããŸãã
-
ã³ãŒãã®ç Žæãé²ãããã«ããšãã£ã·ã§ã³ã¯ãªããã€ã³æ¹åŒã§ãïŒ
Cargo.toml
ã§ãã¯ã¬ãŒãã«å¯ŸããŠé©çšããããšãã£ã·ã§ã³ãéžæããŸãã -
ãšã³ã·ã¹ãã ã®åæãé¿ããããã«ãã³ã³ãã€ã©ã¯ç°ãªããšãã£ã·ã§ã³ã®ã³ãŒããæ··åšãããäºãã§ããŸãã
-
ã³ã³ãã€ã©ãçŽæ¥äœ¿çšããäºã¯éåžžã«çšã§ãããåºæ¬çã«ã¯
cargo
ãä»ããŸãã -
It might be worth alluding that Cargo itself is an extremely powerful and comprehensive tool. It is capable of many advanced features including but not limited to:
- ãããžã§ã¯ãã»ããã±ãŒãžã®æ§é 管ç
- workspacesïŒã¯ãŒã¯ã¹ããŒã¹ïŒ
- éçºçšãšã©ã³ã¿ã€ã çšã®äŸåé¢ä¿ç®¡çã»ãã£ãã·ã¥
- build scriptingïŒãã«ãã¹ã¯ãªããïŒ
- global installation
- cargo clippyãªã©ã®ãµãã³ãã³ããã©ã°ã€ã³ã«ããæ¡åŒµ
-
詳现ã¯official Cargo Bookãåç §ããŠãã ããã
-
è¬åº§ã®ãµã³ãã«ã³ãŒã
æ¬è¬åº§ã¯ãäž»ã«ãã©ãŠã¶å ã§å®è¡å¯èœãªäŸã䜿ããŸããããããäºã§ãã»ããã¢ããã容æã«ãªããäžè²«ããéçºç°å¢ã®æäŸãå¯èœãšãªããŸãã
ãã ããã§ããã°Cargoãã€ã³ã¹ããŒã«ããŠãã ããïŒ ç·Žç¿åé¡ã§äœ¿ãããšäŸ¿å©ã§ãããŸãæçµæ¥ã«äŸåé¢ä¿ãæ±ã課é¡ãæ±ããŸãããããã§ã¯Cargoãå¿ èŠã«ãªããŸãã
è¬åº§ã®ã³ãŒããããã¯ã¯ã€ã³ã¿ã©ã¯ãã£ãã§ãïŒ
You can use Ctrl + Enter to execute the code when focus is in the text box.
Speaker Notes
ã»ãšãã©ã®ãµã³ãã«ã³ãŒãã¯äžèšã®ããã«ç·šéå¯èœã§ãããäžéšã ã以äžã®ãããªçç±ããç·šéäžå¯ãšãªã£ãŠããŸãïŒ
-
è¬åº§ã®ããŒãžå ã«åã蟌ãŸãããã¬ã€ã°ã©ãŠã³ãã§ãŠããããã¹ãã¯å®è¡ã§ããŸãããã³ãŒããå®éã®ãã¬ã€ã°ã©ãŠã³ãã§éãããã¢ã³ã¹ãã¬ãŒã·ã§ã³ãè¡ãå¿ èŠããããŸãã
-
è¬åº§ã®ããŒãžå ã«åã蟌ãŸãããã¬ã€ã°ã©ãŠã³ãã§ã¯ãããŒãžç§»åãããšç¶æ ã倱ãããŸãïŒæ ã«ãåè¬çã¯ããŒã«ã«ç°å¢ãå®éã®ãã¬ã€ã°ã©ãŠã³ãã䜿çšããŠåé¡ã解ãå¿ èŠããããŸãã
Cargoã䜿ã£ãŠããŒã«ã«ã§å®è¡
ã³ãŒããããŒã«ã«ã§è©Šãããå ŽåãRust Bookã®æé ã«åŸã£ãŠRustãã€ã³ã¹ããŒã«ããŠãã ãããæ£åžžã«ã€ã³ã¹ããŒã«ãããããrustc
ãšcargo
ã䜿ããããã«ãªããŸããææ°ã®stableãªãªãŒã¹ã®ããŒãžã§ã³ã¯ä»¥äžã®éãã§ãïŒ
% rustc --version
rustc 1.69.0 (84c898d65 2023-04-16)
% cargo --version
cargo 1.69.0 (6e9a83356 2023-04-12)
Rust ã¯äžäœäºææ§ãç¶æããŠãããããæ°ããããŒãžã§ã³ã䜿çšããããšãã§ããŸãã
With this in place, follow these steps to build a Rust binary from one of the examples in this training:
-
ãCopy to clipboardãã§ã³ãŒããã³ããŒã
-
cargo new exercise
ã§exercise/
ãã£ã¬ã¯ããªãäœæïŒ$ cargo new exercise Created binary (application) `exercise` package
-
exercise/
ãã£ã¬ã¯ããªã«ç§»åããcargo run
ã§ãã€ããªããã«ãããŠå®è¡ïŒ$ cd exercise $ cargo run Compiling exercise v0.1.0 (/home/mgeisler/tmp/exercise) Finished dev [unoptimized + debuginfo] target(s) in 0.75s Running `target/debug/exercise` Hello, world!
-
src/main.rs
ã®ãã€ã©ãŒãã¬ãŒãã³ãŒãããã³ããŒããã³ãŒãã§çœ®ãæããŠãã ãããäŸãã°ãåã®ããŒãžã®äŸã䜿ã£ãå Žåãsrc/main.rs
ã¯ä»¥äžã®ããã«ãªããŸããfn main() { println!("Edit me!"); }
-
cargo run
ã§æŽæ°ããããã€ããªããã«ãããŠå®è¡ïŒ$ cargo run Compiling exercise v0.1.0 (/home/mgeisler/tmp/exercise) Finished dev [unoptimized + debuginfo] target(s) in 0.24s Running `target/debug/exercise` Edit me!
-
cargo check
ã§ãããžã§ã¯ãã®ãšã©ãŒãã§ãã¯ãè¡ããcargo build
ã§ã³ã³ãã€ã«ã ãïŒå®è¡ã¯ããïŒãè¡ããŸããéåžžã®ãããã°ãã«ãã§ã¯ãçæããããã¡ã€ã«ã¯target/debug/
ã«æ ŒçŽãããŸããæé©åããããªãªãŒã¹ãã«ãã«ã¯cargo build ârelease
ã䜿ãããã¡ã€ã«ã¯target/release/
ã«æ ŒçŽãããŸãã -
ãããžã§ã¯ãã«äŸåé¢ä¿ãè¿œå ããã«ã¯ã
Cargo.toml
ãç·šéããŸãããã®åŸãcargo
ã³ãã³ããå®è¡ãããšãèªåçã«äžè¶³ããŠããäŸåé¢ä¿ãããŠã³ããŒããããŠã³ã³ãã€ã«ãããŸãã
Speaker Notes
åè¬è ã«Cargoã®ã€ã³ã¹ããŒã«ãšããŒã«ã«ãšãã£ã¿ã®äœ¿çšãå§ããŠãã ãããéåžžã®éçºç°å¢ãæã€äºã§ãäœæ¥ãã¹ã ãŒãºã«ãªããŸãã
Day 1ãžãããã
This is the first day of Rust Fundamentals. We will cover a lot of ground today:
- Rustã®åºæ¬çãªæ§æïŒ å€æ°ãã¹ã«ã©ãŒåãšè€ååãåæåãæ§é äœãåç §ãé¢æ°ãã¡ãœããã
- Types and type inference.
- å¶åŸ¡ãããŒã®æ§é : ã«ãŒããæ¡ä»¶ãªã©ã
- ãŠãŒã¶ãŒå®çŸ©å: æ§é äœãšåæåã
- ãã¿ãŒã³ ãããã³ã°: åæåãæ§é äœãé åã®å解ã
ã¹ã±ãžã¥ãŒã«
Including 10 minute breaks, this session should take about 2 hours and 5 minutes. It contains:
Segment | Duration |
---|---|
ãããã | 5 minutes |
Hello, World | 15 minutes |
åãšå€ | 40 minutes |
å¶åŸ¡ãããŒã®åºæ¬ | 40 minutes |
Speaker Notes
This slide should take about 5 minutes.
åè¬çã«äŒããŠãã ããïŒ
- They should ask questions when they get them, donât save them to the end.
- The class is meant to be interactive and discussions are very much encouraged!
- As an instructor, you should try to keep the discussions relevant, i.e., keep the discussions related to how Rust does things vs some other language. It can be hard to find the right balance, but err on the side of allowing discussions since they engage people much more than one-way communication.
- The questions will likely mean that we talk about things ahead of the slides.
- This is perfectly okay! Repetition is an important part of learning. Remember that the slides are just a support and you are free to skip them as you like.
1 æ¥ç®ã¯ãä»ã®èšèªã«ãå ±éãã Rust ã®ãåºæ¬çãªãäºé ã瀺ããŸããRust ã®ããé«åºŠãªéšåã«ã€ããŠã¯ãåŸæ¥èª¬æããŸãã
æ宀ã§æããå Žåã¯ãããã§ã¹ã±ãžã¥ãŒã«ã確èªããããšãããããããŸããåã»ã°ã¡ã³ãã®çµããã«æŒç¿ãè¡ããäŒæ©ãæãã§ããçãåãããããŠãã ãããäžèšã®æéé åã¯ããããŸã§ã³ãŒã¹ãäºå®ã©ããã«é²ããããã®ç®å®ã§ãã®ã§ãå¿ èŠã«å¿ããŠæè»ã«èª¿æŽããŠãã ããã
Hello, World
This segment should take about 15 minutes. It contains:
Slide | Duration |
---|---|
Rustãšã¯ïŒ | 10 minutes |
Rustã®ã¡ãªãã | 3 minutes |
ãã¬ã€ã°ã©ãŠã³ã | 2 minutes |
Rustãšã¯ïŒ
Rustã¯2015幎ã«1.0çããªãªãŒã¹ãããæ°ããããã°ã©ãã³ã°èšèªã§ãïŒ
- Rustã¯C++ãšåæ§ã«ãéçã«ã³ã³ãã€ã«ãããèšèªã§ã
rustc
ã¯ããã¯ãšã³ãã«LLVMã䜿çšããŠããŸãã
- Rustã¯å€ãã®ãã©ãããã©ãŒã ãšã¢ãŒããã¯ãã£ããµããŒãããŠããŸãïŒ
- x86, ARM, WebAssembly, âŠ
- Linux, Mac, Windows, âŠ
- Rustã¯æ§ã
ãªããã€ã¹ã§äœ¿çšãããŠããŸãïŒ
- ãã¡ãŒã ãŠã§ã¢ãããŒãããŒãã
- ã¹ããŒããã£ã¹ãã¬ã€ã
- æºåž¯é»è©±ã
- ãã¹ã¯ãããã
- ãµãŒãã
Speaker Notes
This slide should take about 10 minutes.
RustãšC++ã䌌ãŠãããšãã:
- é«ãæè»æ§ã
- é«åºŠãªå¶åŸ¡æ§ã
- Can be scaled down to very constrained devices such as microcontrollers.
- ã©ã³ã¿ã€ã ãã¬ããŒãžã³ã¬ã¯ã·ã§ã³ããªãã
- ããã©ãŒãã³ã¹ãç ç²ã«ãããä¿¡é Œæ§ãšå®å šæ§ã«çŠç¹ãåœãŠãŠããã
Rustã®ã¡ãªãã
Rustã®ãŠããŒã¯ãªã»ãŒã«ã¹ãã€ã³ããããã€ã玹ä»ããŸãïŒ
-
ã³ã³ãã€ã«æã®ã¡ã¢ãªå®å šæ§ - ã¯ã©ã¹å šäœã®ã¡ã¢ãªã®ãã°ãã³ã³ãã€ã«æã«é²æ¢ããŸãã
- æªåæåã®å€æ°ããªãã
- äºé解æŸãèµ·ããªãã
- 解æŸæžã¿ã¡ã¢ãªäœ¿çšïŒuse-after-freeïŒããªãã
NULL
ïŒãã«ïŒãã€ã³ã¿ããªãã- ãã¥ãŒããã¯ã¹ïŒmutexïŒã®ããã¯ã®è§£é€å¿ãããªãã
- ã¹ã¬ããéã§ããŒã¿ç«¶åããªãã
- ã€ãã¬ãŒã¿ãç¡å¹åãããªãã
-
æªå®çŸ©ã®ã©ã³ã¿ã€ã åäœããªã - Rust ã¹ããŒãã¡ã³ãã§è¡ãããåŠçãæªèŠå®ã®ãŸãŸæ®ãããšã¯ãããŸããã
- é åãžã®ã¢ã¯ã»ã¹ã«ã¯å¢çãã§ãã¯ãè¡ãããã
- Integer overflow is defined (panic or wrap-around).
-
ææ°ã®èšèªæ©èœ - é«æ°Žæºèšèªã«å¹æµããè¡šçŸåãããã人éã䜿ããããæ©èœãåããŠããŸãã
- åæåãšãã¿ãŒã³ãããã³ã°
- ãžã§ããªã¯ã¹
- ãªãŒããŒãããã®ãªãFFI
- ãŒãã³ã¹ãæœè±¡å
- åªç§ãªã³ã³ãã€ã«ãšã©ãŒã
- çµã¿èŸŒã¿ã®äŸåé¢ä¿ãããŒãžã£ã
- çµã¿èŸŒã¿ã®ãã¹ããµããŒãã
- Language Server ProtocolïŒLSPïŒã®ãµããŒãã
Speaker Notes
This slide should take about 3 minutes.
ããã«ã¯ããŸãæéããããªãã§ãã ããããããã®ãã€ã³ãã«ã€ããŠã¯ãåŸã»ã©è©³ãã説æããŸãã
åè¬è ã«ã©ã®èšèªã®çµéšãããããå°ããŠãã ãããåçã«å¿ããŠãRustã®ããŸããŸãªç¹åŸŽã匷調ããããšãã§ããŸãïŒ
-
CãŸãã¯C++ã®çµéšãããå ŽåïŒ Rustã¯åçšãã§ãã«ãŒãä»ããŠå®è¡æãšã©ãŒã®äžéšãæé€ããŠãããŸããããã«å ããCãC++ãšåçã®ããã©ãŒãã³ã¹ãåŸãããšãã§ããã¡ã¢ãªå®å šæ§ã®åé¡ã¯ãããŸãããããã«ããã¿ãŒã³ãããã³ã°ãçµã¿èŸŒã¿ã®äŸåé¢ä¿ç®¡çãªã©ã®æ§é èŠçŽ ãå«ãçŸä»£çãªèšèªã§ãã
-
Experience with Java, Go, Python, JavaScriptâŠ: You get the same memory safety as in those languages, plus a similar high-level language feeling. In addition you get fast and predictable performance like C and C++ (no garbage collector) as well as access to low-level hardware (should you need it).
ãã¬ã€ã°ã©ãŠã³ã
ãã®ã³ãŒã¹ã®äŸãæŒç¿ã«ã¯ãçã Rust ããã°ã©ã ãç°¡åã«å®è¡ã§ãã Rust ãã¬ã€ã°ã©ãŠã³ã ã䜿çšããŸããæåã®ãhello-worldãããã°ã©ã ãå®è¡ããŠã¿ãŸãããã次ã®ãããªäŸ¿å©ãªæ©èœããããŸãã
-
ãToolsã ã«ãã
rustfmt
ãªãã·ã§ã³ã䜿çšããŠãã³ãŒãããstandardãã®åœ¢åŒã§ãã©ãŒãããããŸãã -
Rust ã«ã¯ãã³ãŒããçæããããã®äž»èŠãªããããã¡ã€ã«ãã 2 ã€ãããŸãã1 ã€ã¯ DebugïŒè¿œå ã®ã©ã³ã¿ã€ã ãã§ãã¯ããããæé©åãå°ãªãïŒã§ããã 1 ã€ã¯ ReleaseïŒã©ã³ã¿ã€ã ãã§ãã¯ãå°ãªããæé©åãå€ãïŒã§ãããããã¯äžéšã® [Debug] ããã¢ã¯ã»ã¹ã§ããŸãã
-
èå³ãããå Žåã¯ããâŠã ã®äžã«ãã ãASMã ã䜿çšãããšãçæãããã¢ã»ã³ã㪠ã³ãŒãã確èªã§ããŸãã
Speaker Notes
This slide should take about 2 minutes.
åè¬è ãäŒæ©ã«å ¥ã£ããããã¬ã€ã°ã©ãŠã³ããéããŠããããè©ŠããŠã¿ãããä¿ããŸããã¿ããéãããŸãŸã«ããŠãã³ãŒã¹ã®æ®ãã®éšåã§åŠç¿ããããšãè©ŠãããããããŸããããããã¯ãRust ã®æé©åãçæãããã¢ã»ã³ããªã«ã€ããŠè©³ããç¥ãããåè¬è ã«ç¹ã«åœ¹ç«ã¡ãŸãã
åãšå€
This segment should take about 40 minutes. It contains:
Slide | Duration |
---|---|
Hello, World | 5 minutes |
å€æ° | 5 minutes |
å€ | 5 minutes |
ç®è¡ | 3 minutes |
åæšè« | 3 minutes |
æŒç¿: ãã£ãããã | 15 minutes |
Hello, World
ãã£ããäžçªã·ã³ãã«ãªããã°ã©ã ã§ããå®çªã®Hello Worldããã¿ãŠã¿ãŸãããïŒ
ããã°ã©ã ã®äžèº«ïŒ
- é¢æ°ã¯
fn
ã§å°å ¥ãããŸãã - CãC++ãšåæ§ã«ããããã¯ã¯æ³¢æ¬åŒ§ã§å²ã¿ãŸãã
main
é¢æ°ã¯ããã°ã©ã ã®ãšã³ããªãŒãã€ã³ãã«ãªããŸãã- Rustã«ã¯è¡ççãªãã¯ããããã
println!
ã¯ãã®äžäŸã§ãã - Rustã®æååã¯UTF-8ã§ãšã³ã³ãŒããããã©ããªUnicodeæåã§ãå«ãäºãã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
This slide tries to make the students comfortable with Rust code. They will see a ton of it over the next four days so we start small with something familiar.
èŠç¹ïŒ
-
Rust is very much like other languages in the C/C++/Java tradition. It is imperative and it doesnât try to reinvent things unless absolutely necessary.
-
Rust is modern with full support for things like Unicode.
-
Rust uses macros for situations where you want to have a variable number of arguments (no function overloading).
-
Macros being âhygienicâ means they donât accidentally capture identifiers from the scope they are used in. Rust macros are actually only partially hygienic.
-
Rust ã¯ãã«ããã©ãã€ã ã§ããããšãã°ã匷å㪠ãªããžã§ã¯ãæåããã°ã©ãã³ã°æ©èœ ãåããŠããäžæ¹ãéé¢æ°åèšèªã§ããã«ãããããããããŸããŸãª é¢æ°çæŠå¿µ ãå å ããŠããŸãã
å€æ°
Rust ã¯éçåä»ãã«ãã£ãŠåå®å
šæ§ãæäŸããŸããå€æ°ã®ãã€ã³ãã£ã³ã°ã¯ let
ã䜿çšããŠè¡ããŸãã
Speaker Notes
This slide should take about 5 minutes.
-
x = 20
ã®ã³ã¡ã³ãåã解é€ããŠãå€æ°ãããã©ã«ãã§äžå€ã§ããããšã瀺ããŸããå€æŽãèš±å¯ããã«ã¯ãmut
ããŒã¯ãŒããè¿œå ããŸãã -
ããã§ã®
i32
ã¯å€æ°ã®åã§ããããã¯ã³ã³ãã€ã«æã«æå®ããå¿ èŠããããŸãããå€ãã®å Žåãããã°ã©ããŒã¯åæšè«ïŒåŸè¿°ïŒã䜿çšããããšã§ãããçç¥ã§ããŸãã
å€
åºæ¬çãªçµã¿èŸŒã¿åãšãååã®ãªãã©ã«å€ã®æ§æã以äžã«ç€ºããŸãã
å | ãªãã©ã« | |
---|---|---|
笊å·ä»ãæŽæ° | i8 ãi16 ãi32 ãi64 ãi128 ãisize | -10 ã0 ã1_000 ã123_i64 |
笊å·ãªãæŽæ° | u8 ãu16 ãu32 ãu64 ãu128 ãusize | 0 ã123 ã10_u16 |
æµ®åå°æ°ç¹æ° | f32 ãf64 | 3.14 ã-10.0e20 ã2_f32 |
Unicode ã¹ã«ã©ãŒå€ | char | 'a' ã'α' ã'â' |
ããŒã«å€ | bool | true ãfalse |
ååã®å¹ ã¯æ¬¡ã®ãšããã§ãã
iN
ãuN
ãfN
㯠N ãããå¹ ã§ããisize
ãšusize
ã¯ãã€ã³ã¿ã®å¹ ã§ããchar
㯠32 ãããå¹ ã§ããbool
㯠8 ãããå¹ ã§ãã
Speaker Notes
This slide should take about 5 minutes.
äžèšã«ã¯ç€ºãããŠããªãæ§æããããŸãã
- æ°åã®ã¢ã³ããŒã¹ã³ã¢ã¯ãã¹ãŠçç¥ã§ããŸããã¢ã³ããŒã¹ã³ã¢ã¯èªã¿ãããããããã«ã®ã¿äœ¿çšããŸãããã®ããã
1_000
ã¯1000
ïŒãŸãã¯10_00
ïŒã123_i64
ã¯123i64
ãšèšè¿°ã§ããŸãã
ç®è¡
Speaker Notes
This slide should take about 3 minutes.
main
以å€ã®é¢æ°ãåºãŠããã®ã¯ä»åãåããŠã§ããããã®æå³ã¯æ確ã§ããã€ãŸãã3 ã€ã®æŽæ°ãåãã1 ã€ã®æŽæ°ãè¿ããŸããé¢æ°ã«ã€ããŠã¯ãåŸã§è©³ãã説æããŸãã
ç®è¡ã¯ä»ã®èšèªãšãã䌌ãŠãããåªå é äœãé¡äŒŒããŠããŸãã
What about integer overflow? In C and C++ overflow of signed integers is actually undefined, and might do unknown things at runtime. In Rust, itâs defined.
i32
ã i16
ã«å€æŽããŠãæŽæ°ãªãŒããŒãããŒã確èªããŸããããã¯ããããã°ãã«ãã§ã¯ãããã¯ã«ãªãïŒãã§ãã¯ããïŒããªãªãŒã¹ãã«ãã§ã¯ã©ãããããŸãããªãŒããŒãããŒã飜åããã£ãªãŒãªã©ã®ãªãã·ã§ã³ããããã¡ãœããæ§æã䜿çšããŠãããã®ãªãã·ã§ã³ã«ã¢ã¯ã»ã¹ããŸãïŒäŸ: (a * b).saturating_add(b * c).saturating_add(c * a)
ïŒã
å®éã«ã¯ãã³ã³ãã€ã©ã¯å®æ°åŒã®ãªãŒããŒãããŒãæ€åºããŸãããã®äŸã§å¥ã®é¢æ°ãå¿ èŠã«ãªãã®ã¯ãã®ããã§ãã
åæšè«
Rust ã¯ãã©ã®ããã«å€æ°ã 䜿çšãããŠããã ã確èªããããšã§ãåãå€å¥ããŸãã
Speaker Notes
This slide should take about 3 minutes.
ãã®ã¹ã©ã€ãã¯ãå€æ°ã®å®£èšãšäœ¿çšæ¹æ³ã«ããå¶çŽã«åºã¥ããŠãRust ã³ã³ãã€ã©ãåãæšæž¬ããä»çµã¿ã瀺ããŠããŸãã
ãã®ããã«å®£èšãããå€æ°ã¯ãã©ã®ãããªããŒã¿ãä¿æã§ããåçãªãä»»æã®åãã§ã¯ãªãããšããç¹ã匷調ããããšãéåžžã«éèŠã§ãããã®ãããªå®£èšã«ãã£ãŠçæããããã·ã³ã³ãŒãã¯ãåã®æ瀺çãªå®£èšãšåäžã§ããã³ã³ãã€ã©ã代ããã«äœæ¥ãè¡ããããç°¡æœãªã³ãŒãã®äœæãæ¯æŽããŸãã
æŽæ°ãªãã©ã«ã®åã«å¶çŽããªãå ŽåãRust ã¯ããã©ã«ã㧠i32
ã䜿çšããŸããããã¯ããšã©ãŒ ã¡ãã»ãŒãžã« {integer}
ãšããŠè¡šç€ºãããããšããããŸããåæ§ã«ãæµ®åå°æ°ç¹ãªãã©ã«ã¯ããã©ã«ã㧠f64
ã«ãªããŸãã
fn main() {
let x = 3.14;
let y = 20;
assert_eq!(x, y);
// ãšã©ãŒ: `{float} == {integer}` ã®å®è£
ããããŸãã
}
æŒç¿: ãã£ãããã
The Fibonacci sequence begins with [0,1]
. For n>1, the nâth Fibonacci number is calculated recursively as the sum of the n-1âth and n-2âth Fibonacci numbers.
n çªç®ã®ãã£ããããæ°ãèšç®ããé¢æ° fib(n)
ãèšè¿°ããŸãããã®é¢æ°ã¯ãã€ãããã¯ããã§ããããã
解ç
å¶åŸ¡ãããŒã®åºæ¬
This segment should take about 40 minutes. It contains:
Slide | Duration |
---|---|
if åŒ | 4 minutes |
ã«ãŒã | 5 minutes |
break ãš continue | 4 minutes |
ãããã¯ãšã¹ã³ãŒã | 5 minutes |
é¢æ° | 3 minutes |
ãã¯ã | 2 minutes |
æŒç¿: ã³ã©ããæ°å | 15 minutes |
if
åŒ
Rust ã® if
åŒ ã¯ãä»ã®èšèªã«ããã if
æãšå
šãåãããã«äœ¿ããŸãã
ããã«ãif
ãåŒãšããŠãçšããããšãã§ããŸããããããã®ãããã¯ã«ããæåŸã®åŒããif
åŒã®å€ãšãªããŸãã
Speaker Notes
This slide should take about 4 minutes.
Because if
is an expression and must have a particular type, both of its branch blocks must have the same type. Show what happens if you add ;
after "small"
in the second example.
An if
expression should be used in the same way as the other expressions. For example, when it is used in a let
statement, the statement must be terminated with a ;
as well. Remove the ;
before println!
to see the compiler error.
ã«ãŒã
Rust ã«ã¯ãwhile
ãloop
ãfor
ã® 3 ã€ã®ã«ãŒã ããŒã¯ãŒãããããŸãã
while
while
ããŒã¯ãŒã ã¯ãä»ã®èšèªã«ããã while
ãšéåžžã«ãã䌌ãåããããŸãã
for
The for
loop iterates over ranges of values or the items in a collection:
Speaker Notes
- Under the hood
for
loops use a concept called âiteratorsâ to handle iterating over different kinds of ranges/collections. Iterators will be discussed in more detail later. - Note that the first
for
loop only iterates to4
. Show the1..=5
syntax for an inclusive range.
loop
loop
ã¹ããŒãã¡ã³ã ã¯ãbreak
ãŸã§æ°žä¹
ã«ã«ãŒãããã ãã§ãã
break
ãš continue
次ã®ã€ãã¬ãŒã·ã§ã³ãããããŸéå§ãããå Žå㯠continue
ã䜿çšããŠãã ããã
If you want to exit any kind of loop early, use break
. With loop
, this can take an optional expression that becomes the value of the loop
expression.
Speaker Notes
This slide and its sub-slides should take about 4 minutes.
Note that loop
is the only looping construct which can return a non-trivial value. This is because itâs guaranteed to only return at a break
statement (unlike while
and for
loops, which can also return when the condition fails).
Labels
continue
ãš break
ã¯ãªãã·ã§ã³ã§ã©ãã«åŒæ°ãåãããšãã§ããŸããã©ãã«ã¯ãã¹ãããã«ãŒãããæãåºãããã«äœ¿ãããŸãã
Speaker Notes
- Labeled break also works on arbitrary blocks, e.g.
ãããã¯ãšã¹ã³ãŒã
ã³ãŒããããã¯
A block in Rust contains a sequence of expressions, enclosed by braces {}
. Each block has a value and a type, which are those of the last expression of the block:
æåŸã®åŒã ;
ã§çµäºããå Žåããããã¯å
šäœã®å€ãšå㯠()
ã«ãªããŸãã
Speaker Notes
This slide and its sub-slides should take about 5 minutes.
- ãããã¯å
ã«ããæåŸã®è¡ãå€æŽããããšã«ãã£ãŠããããã¯å
šäœã®å€ãå€ããããšãåãããŸããäŸãã°ãè¡æ«ã®ã»ãã³ãã³ãè¿œå /åé€ãããã
return
ã䜿çšãããããããšã§ããããã¯ã®å€ã¯å€åããŸãã
ã¹ã³ãŒããšã·ã£ããŒã€ã³ã°
å€æ°ã®ã¹ã³ãŒãã¯ãå²ãŸãããããã¯å ã«éå®ãããŸãã
å€åŽã®ã¹ã³ãŒãã®å€æ°ãšãåãã¹ã³ãŒãã®å€æ°ã®äž¡æ¹ãã·ã£ããŒã€ã³ã°ã§ããŸãã
Speaker Notes
- æåŸã®äŸã®å
åŽã®ãããã¯ã«
b
ãè¿œå ãããã®ãããã¯ã®å€åŽã§ã¢ã¯ã»ã¹ãè©Šã¿ãããšã§ãå€æ°ã®ã¹ã³ãŒããå¶éãããŠããããšã瀺ããŸãã - Shadowing is different from mutation, because after shadowing both variablesâ memory locations exist at the same time. Both are available under the same name, depending where you use it in the code.
- ã·ã£ããŒã€ã³ã°å€æ°ã®åã¯ããŸããŸã§ãã
- ã·ã£ããŒã€ã³ã°ã¯äžèŠãããã«ããããã«èŠããŸããã
.unwrap()
ã®åŸã®å€ãä¿æããå Žåã«äŸ¿å©ã§ãã
é¢æ°
Speaker Notes
This slide should take about 3 minutes.
- 宣èšãã©ã¡ãŒã¿ã®åŸã«ã¯åïŒäžéšã®ããã°ã©ãã³ã°èšèªãšéïŒãæ»ãå€ã®åãç¶ããŸãã
- é¢æ°æ¬äœïŒãŸãã¯ä»»æã®ãããã¯ïŒå
ã®æåŸã®åŒãæ»ãå€ã«ãªããŸããåŒã®æ«å°Ÿã®
;
ãçç¥ããŸããreturn
ããŒã¯ãŒãã¯æ©æãªã¿ãŒã³ã«äœ¿çšã§ããŸãããé¢æ°ã®æåŸã¯ã裞ã®å€ãã®åœ¢åŒã«ããã®ãæ £çšçã§ãïŒreturn
ã䜿çšããã«ã¯gcd
ããªãã¡ã¯ã¿ãªã³ã°ããŸãïŒã - Some functions have no return value, and return the âunit typeâ,
()
. The compiler will infer this if the return type is omitted. - ãªãŒããŒããŒãã¯ãµããŒããããŠããŸãããåé¢æ°ã®å®è£
㯠1 ã€ã§ãã
- åžžã«åºå®æ°ã®ãã©ã¡ãŒã¿ãåãåããŸããããã©ã«ãã®åŒæ°ã¯ãµããŒããããŠããŸããããã¯ãã䜿çšããŠå¯å€é¢æ°ããµããŒãã§ããŸãã
- åžžã« 1 ã€ã®ãã©ã¡ãŒã¿åã»ãããåãåããŸãããããã®åã¯æ±çšã«ããããšãã§ããŸãããããã«ã€ããŠã¯åŸã§èª¬æããŸãã
ãã¯ã
ãã¯ãã¯ã³ã³ãã€ã«æã« Rust ã³ãŒãã«å±éãããå¯å€é·åŒæ°ãåãããšãã§ããŸãããããã¯æ«å°Ÿã® !
ã§åºå¥ãããŸããRust æšæºã©ã€ãã©ãªã«ã¯ãåçš®ã®äŸ¿å©ãªãã¯ããå«ãŸããŠããŸãã
println!(format, ..)
:std::fmt
ã§èª¬æãããŠããæžåŒãé©çšããŠã1 è¡ãæšæºåºåã«åºåããŸããformat!(format, ..)
:println!
ãšåæ§ã«æ©èœããŸãããçµæãæååãšããŠè¿ããŸããdbg!(expression)
: åŒã®å€ããã°ã«èšé²ããŠè¿ããŸããtodo!()
: äžéšã®ã³ãŒãã«æªå®è£ ã®ããŒã¯ãä»ããŸããå®è¡ãããšãããã¯ãçºçããŸããunreachable!()
: ã³ãŒãã®äžéšãã¢ã¯ã»ã¹äžèœãšããŠããŒã¯ããŸããå®è¡ãããšãããã¯ãçºçããŸãã
Speaker Notes
This slide should take about 2 minutes.
ãã®ã»ã¯ã·ã§ã³ã®èŠç¹ã¯ããã¯ãã®äžè¬çãªå©äŸ¿æ§ãšããã®äœ¿çšæ¹æ³ã瀺ãããšã«ãããŸãããã¯ããšããŠå®çŸ©ãããŠããçç±ãšãå±éå ã¯ç¹ã«éèŠã§ã¯ãããŸããã
ãã¯ãã®å®çŸ©ã«ã€ããŠã¯ã³ãŒã¹ã§ã¯èª¬æããŸããããåŸã®ã»ã¯ã·ã§ã³ã§å°åºãã¯ãã®äœ¿çšã«ã€ããŠèª¬æããŸãã
æŒç¿: ã³ã©ããæ°å
The Collatz Sequence is defined as follows, for an arbitrary n1 greater than zero:
- If ni is 1, then the sequence terminates at ni.
- If ni is even, then ni+1 = ni / 2.
- If ni is odd, then ni+1 = 3 * ni + 1.
For example, beginning with n1 = 3:
- 3 is odd, so n2 = 3 * 3 + 1 = 10;
- 10 is even, so n3 = 10 / 2 = 5;
- 5 is odd, so n4 = 3 * 5 + 1 = 16;
- 16 is even, so n5 = 16 / 2 = 8;
- 8 is even, so n6 = 8 / 2 = 4;
- 4 is even, so n7 = 4 / 2 = 2;
- 2 is even, so n8 = 1; and
- æ°åã¯çµäºããŸãã
ä»»æã®åæå€ n
ã«å¯Ÿããã³ã©ããæ°åã®é·ããèšç®ããé¢æ°ãäœæããŸãã
解ç
ãããã
Including 10 minute breaks, this session should take about 2 hours and 35 minutes. It contains:
Segment | Duration |
---|---|
ã¿ãã«ãšé å | 35 minutes |
åç § | 55 minutes |
ãŠãŒã¶ãŒå®çŸ©å | 50 minutes |
ã¿ãã«ãšé å
This segment should take about 35 minutes. It contains:
Slide | Duration |
---|---|
é å | 5 minutes |
ã¿ãã« | 5 minutes |
é åã®ã€ãã¬ãŒã | 3 minutes |
ãã¿ãŒã³ãšãã¹ãã©ã¯ã | 5 minutes |
æŒç¿: ãã¹ããããé å | 15 minutes |
é å
Speaker Notes
This slide should take about 5 minutes.
-
é åå
[T; N]
ã«ã¯ãåãåT
ã®N
ïŒã³ã³ãã€ã«æå®æ°ïŒåã®èŠçŽ ãä¿æãããŸãããªããé åã®é·ãã¯ãã®åã®äžéšåã§ããã€ãŸãã[u8; 3]
ãš[u8; 4]
㯠2 ã€ã®ç°ãªãåãšã¿ãªãããŸããã¹ã©ã€ã¹ïŒãµã€ãºãå®è¡æã«æ±ºå®ãããïŒã«ã€ããŠã¯åŸã§èª¬æããŸãã -
å¢çå€ã®é åèŠçŽ ã«ã¢ã¯ã»ã¹ããŠã¿ãŠãã ãããé åã¢ã¯ã»ã¹ã¯å®è¡æã«ãã§ãã¯ãããŸããRust ã§ã¯éåžžããããã®ãã§ãã¯ãæé©åã«ããé€å»ã§ããŸãïŒUnsafe Rust ã䜿çšããããšã§åé¿ã§ããŸãïŒã
-
ãªãã©ã«ã䜿çšããŠé åã«å€ãä»£å ¥ããããšãã§ããŸãã
-
println!
ãã¯ãã¯ã?
圢åŒã®ãã©ã¡ãŒã¿ã䜿çšããŠãããã°å®è£ ãèŠæ±ããŸããã€ãŸãã{}
ã¯ããã©ã«ãã®åºåãã{:?}
ã¯ãããã°åºåãæäŸããŸããæŽæ°ãæååãªã©ã®åã¯ããã©ã«ãã®åºåãå®è£ ããŸãããé åã¯ãããã°åºåã®ã¿ãå®è£ ããŸãããã®ãããããã§ã¯ãããã°åºåã䜿çšããå¿ èŠããããŸãã -
#
ãè¿œå ãããšïŒäŸ:{a:#?}
ïŒãèªã¿ããããããªã㣠ããªã³ãã圢åŒãåŒã³åºãããŸãã
ã¿ãã«
Speaker Notes
This slide should take about 5 minutes.
-
é åãšåæ§ã«ãã¿ãã«ã®é·ãã¯åºå®ãããŠããŸãã
-
ã¿ãã«ã¯ãç°ãªãåã®å€ãè€ååã«ã°ã«ãŒãåããŸãã
-
ã¿ãã«ã®ãã£ãŒã«ãã«ã¯ãããªãªããšå€ã®ã€ã³ããã¯ã¹ïŒäŸ:
t.0
ãt.1
ïŒã§ã¢ã¯ã»ã¹ã§ããŸãã -
The empty tuple
()
is referred to as the âunit typeâ and signifies absence of a return value, akin tovoid
in other languages.
é åã®ã€ãã¬ãŒã
for ã¹ããŒãã¡ã³ãã§ã¯ãé åã®å埩åŠçããµããŒããããŠããŸãïŒã¿ãã«ã¯ãµããŒããããŠããŸããïŒã
Speaker Notes
This slide should take about 3 minutes.
ãã®æ©èœã¯ IntoIterator
ãã¬ã€ãã䜿çšããŸãããããã¯ãŸã 説æããŠããŸããã
The assert_ne!
macro is new here. There are also assert_eq!
and assert!
macros. These are always checked, while debug-only variants like debug_assert!
compile to nothing in release builds.
ãã¿ãŒã³ãšãã¹ãã©ã¯ã
When working with tuples and other structured values itâs common to want to extract the inner values into local variables. This can be done manually by directly accessing the inner values:
However, Rust also supports using pattern matching to destructure a larger value into its constituent parts:
Speaker Notes
This slide should take about 5 minutes.
- The patterns used here are âirrefutableâ, meaning that the compiler can statically verify that the value on the right of
=
has the same structure as the pattern. - A variable name is an irrefutable pattern that always matches any value, hence why we can also use
let
to declare a single variable. - Rust also supports using patterns in conditionals, allowing for equality comparison and destructuring to happen at the same time. This form of pattern matching will be discussed in more detail later.
- Edit the examples above to show the compiler error when the pattern doesnât match the value being matched on.
æŒç¿: ãã¹ããããé å
é åã«ã¯ä»ã®é åãå«ããããšãã§ããŸãã
What is the type of this variable?
äžèšã®ãããªé
åã䜿çšããŠãè¡åã転眮ïŒè¡ãåã«å€æïŒãã transpose
é¢æ°ãèšè¿°ããŸãã
Copy the code below to https://play.rust-lang.org/ and implement the function. This function only operates on 3x3 matrices.
// TODO: å®è£
ãå®äºãããããããåé€ããŸãã
#![allow(unused_variables, dead_code)]
fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
unimplemented!()
}
#[test]
fn test_transpose() {
let matrix = [
[101, 102, 103], //
[201, 202, 203],
[301, 302, 303],
];
let transposed = transpose(matrix);
assert_eq!(
transposed,
[
[101, 201, 301], //
[102, 202, 302],
[103, 203, 303],
]
);
}
fn main() {
let matrix = [
[101, 102, 103], // <-- ãã®ã³ã¡ã³ãã«ãã rustfmt ã§æ¹è¡ãè¿œå
[201, 202, 203],
[301, 302, 303],
];
println!("matrix: {:#?}", matrix);
let transposed = transpose(matrix);
println!("transposed: {:#?}", transposed);
}
解ç
åç §
This segment should take about 55 minutes. It contains:
Slide | Duration |
---|---|
å ±æåç § | 10 minutes |
æä»åç § | 10 minutes |
Slices | 10 minutes |
æåå | 10 minutes |
æŒç¿: ãžãªã¡ã㪠| 15 minutes |
å ±æåç §
A reference provides a way to access another value without taking ownership of the value, and is also called âborrowingâ. Shared references are read-only, and the referenced data cannot change.
å T
ãžã®å
񑆇
§ã®å㯠&T
ã§ããåç
§å€ã¯ &
æŒç®åã§äœæãããŸãã*
æŒç®åã¯åç
§ããéåç
§ããããã®å€ãçæããŸãã
Rust ã¯ãã³ã°ãªã³ã°åç §ãéçã«çŠæ¢ããŸãã
Speaker Notes
This slide should take about 10 minutes.
-
References can never be null in Rust, so null checking is not necessary.
-
åç §ãšã¯ãåç §ããå€ããåçšãããããšã ãšèšãããŠããŸãããããã¯ãã€ã³ã¿ã«æ £ããŠããªãåè¬è ã«ãšã£ãŠç解ãããã説æã§ããã³ãŒãã§ã¯åç §ã䜿çšããŠå€ã«ã¢ã¯ã»ã¹ã§ããŸããããã®å€ã¯å ã®å€æ°ã«ãã£ãŠãææãããããŸãŸãšãªããŸããææã«ã€ããŠã¯ãã³ãŒã¹ã® 3 æ¥ç®ã§è©³ãã説æããŸãã
-
åç §ã¯ãã€ã³ã¿ãšããŠå®è£ ãããŸããäž»ãªå©ç¹ã¯ãåç §å ãããã¯ããã«å°ããã§ããããšã§ããC ãŸã㯠C++ ã«ç²ŸéããŠããåè¬è ã¯ãåç §ããã€ã³ã¿ãšããŠèªèã§ããŸãããã®ã³ãŒã¹ã®åŸåã§ãæªå å·¥ãã€ã³ã¿ã®äœ¿çšã«ããã¡ã¢ãªå®å šæ§ã®ãã°ã Rust ã§é²æ¢ããæ¹æ³ã«ã€ããŠèª¬æããŸãã
-
Rust ã¯åç §ãèªåçã«äœæããªããããåžžã«
&
ãä»ããå¿ èŠããããŸãã -
Rust will auto-dereference in some cases, in particular when invoking methods (try
r.is_ascii()
). There is no need for an->
operator like in C++. -
ãã®äŸã§ã¯ã
r
ã¯å¯å€ã§ãããããåä»£å ¥ãå¯èœã§ãïŒr = &b
ïŒãããã«ããr
ãåãã€ã³ããããä»ã®å€ãåç §ããããã«ãªããŸããããã¯ãåç §ã«ä»£å ¥ãããšåç §å ã®å€ãå€æŽããã C++ ãšã¯ç°ãªããŸãã -
å ±æåç §ã§ã¯ãå€ãå¯å€ã§ãã£ãŠããåç §å ã®å€ã¯å€æŽã§ããŸããã
*r = 'X'
ãšæå®ããŠã¿ãŠãã ããã -
Rust ã¯ããã¹ãŠã®åç §ã®ã©ã€ãã¿ã€ã ã远跡ããŠãååãªåç¶æéã確ä¿ããŠããŸããå®å šãª Rust ã§ã¯ããã³ã°ãªã³ã°åç §ãçºçããããšã¯ãããŸããã
x_axis
ã¯point
ãžã®åç §ãè¿ããŸãããé¢æ°ãæ»ããšpoint
ã®å²ãåœãŠã解é€ããããããã³ã³ãã€ã«ãããŸããã -
åçšã«ã€ããŠã¯æææš©ã®ãšããã§è©³ãã説æããŸãã
æä»åç §
æä»åç
§ã¯å¯å€åç
§ãšãåŒã°ããåç
§å
ã®å€ãå€æŽã§ããŸããå㯠&mut T
ã§ãã
Speaker Notes
This slide should take about 10 minutes.
èŠç¹ïŒ
-
ãæä»ããšã¯ããã®åç §ã®ã¿ã䜿çšããŠå€ã«ã¢ã¯ã»ã¹ã§ããããšãæå³ããŸããä»ã®åç §ïŒå ±æãŸãã¯æä»ïŒãåæã«ååšããããšã¯ã§ãããæä»åç §ãååšããéã¯åç §å ã®å€ã«ã¢ã¯ã»ã¹ã§ããŸããã
x_coord
ãæå¹ãªç¶æ ã§&point.0
ãäœæããããpoint.0
ãå€æŽããŠã¿ãŠãã ããã -
let mut x_coord: &i32
ãšlet x_coord: &mut i32
ã®éãã«æ³šæããŠãã ãããåè ã¯ç°ãªãå€ã«ãã€ã³ãã§ããå ±æåç §ãè¡šãã®ã«å¯ŸããåŸè ã¯å¯å€ã®å€ãžã®æä»åç §ãè¡šããŸãã
Slices
ã¹ã©ã€ã¹ã¯ããã倧ããªã³ã¬ã¯ã·ã§ã³ã«å¯Ÿãããã¥ãŒãæäŸããŸãã
- ã¹ã©ã€ã¹ã¯ãã¹ã©ã€ã¹ãããåããããŒã¿ãåçšããŸãã
Speaker Notes
This slide should take about 10 minutes.
-
ã¹ã©ã€ã¹ãäœæããã«ã¯ã
a
ãåçšããéå§ã€ã³ããã¯ã¹ãšçµäºã€ã³ããã¯ã¹ãè§ãã£ãã§å²ãã§æå®ããŸãã -
ã¹ã©ã€ã¹ãã€ã³ããã¯ã¹ 0 ããå§ãŸãå ŽåãRust ã®ç¯å²æ§æã«ããéå§ã€ã³ããã¯ã¹ãçç¥ã§ããŸããã€ãŸãã
&a[0..a.len()]
ãš&a[..a.len()]
ã¯åãã§ãã -
æåŸã®ã€ã³ããã¯ã¹ã«ã€ããŠãåãããšãèšããã®ã§ã
&a[2..a.len()]
ãš&a[2..]
ã¯åãã§ãã -
é åå šäœã®ã¹ã©ã€ã¹ãç°¡åã«äœæããã«ã¯ã
&a[..]
ãšæžãããšãåºæ¥ãŸãã -
s
㯠i32 ã®ã¹ã©ã€ã¹ãžã®åç §ã§ããs
ã®åïŒ&[i32]
ïŒã«é åã®é·ããå«ãŸããªããªã£ãããšã«æ³šç®ããŠãã ãããããã«ãããããŸããŸãªãµã€ãºã®ã¹ã©ã€ã¹ã«å¯ŸããŠèšç®ãå®è¡ã§ããŸãã -
ã¹ã©ã€ã¹ã¯åžžã«å¥ã®ãªããžã§ã¯ãããåçšããŸãããã®äŸã§ã¯ã
a
ã¯å°ãªããšãã¹ã©ã€ã¹ãååšããéã¯ãåç¶ã ããŠããïŒã¹ã³ãŒãå ã«ãã)å¿ èŠããããŸãã
æåå
We can now understand the two string types in Rust:
&str
is a slice of UTF-8 encoded bytes, similar to&[u8]
.String
is an owned buffer of UTF-8 encoded bytes, similar toVec<T>
.
Speaker Notes
This slide should take about 10 minutes.
-
&str
introduces a string slice, which is an immutable reference to UTF-8 encoded string data stored in a block of memory. String literals ("Hello"
), are stored in the programâs binary. -
Rustâs
String
type is a wrapper around a vector of bytes. As with aVec<T>
, it is owned. -
ä»ã®å€ãã®åãšåæ§ã«ã
String::from()
ã¯æååãªãã©ã«ããæååãäœæããŸããString::new()
ã¯æ°ãã空ã®æååãäœæããŸããpush()
ã¡ãœãããšpush_str()
ã¡ãœããã䜿çšããŠãããã«æååããŒã¿ãè¿œå ã§ããŸãã -
format!()
ãã¯ãã䜿çšãããšãåçãªå€ããæææååãç°¡åã«çæã§ããŸãããã㯠println!() ãšåã圢åŒæå®ãåãå ¥ããŸãã -
&
ã䜿çšããŠString
ãã&str
ã¹ã©ã€ã¹ãåçšããå¿ èŠã«å¿ããŠç¯å²ãéžæã§ããŸããæåå¢çã«æããããŠããªããã€ãç¯å²ãéžæãããšããã®åŒã§ãããã¯ãèµ·ãããŸããchars
ã€ãã¬ãŒã¿ã¯æååäœã§åŠçãããããæ£ããæåå¢çãååŸããããšããããšãããããã®ã€ãã¬ãŒã¿ã䜿çšããã»ããæãŸããã§ãã -
C++ ããã°ã©ããŒåãã®èª¬æïŒ
&str
ã¯åžžã«ã¡ã¢ãªäžã®æå¹ãªæååãæããŠãããããªC++ ã® std::string_view ãšèããããŸããRust ã®String
ã¯ãC++ ã®std::string
ãšããããåçã§ãïŒäž»ãªéãã¯ãUTF-8 ã§ãšã³ã³ãŒãããããã€ãã®ã¿ãå«ããããšãã§ããçãæååã«å¯Ÿããæé©åãè¡ãããªãããšã§ãïŒã -
ãã€ãæååãªãã©ã«ã䜿çšãããšã
&[u8]
å€ãçŽæ¥äœæã§ããŸãã -
æªå å·¥ã®æååã䜿çšãããšããšã¹ã±ãŒããç¡å¹ã«ããŠ
&str
å€ãäœæã§ããŸãïŒr"\n" == "\\n"
ïŒãäºéåŒçšç¬Šãåã蟌ãã«ã¯ãåŒçšç¬Šã®äž¡åŽã«åéã®#
ã䜿çšããŸãã
æŒç¿: ãžãªã¡ããª
ããã§ã¯ãç¹ã [f64;3]
ãšããŠè¡šçŸãã 3 次å
ãžãªã¡ããªã®ãŠãŒãã£ãªãã£é¢æ°ãããã€ãäœæããŸããé¢æ°ã·ã°ããã£ã¯ä»»æã§æå®ããŠãã ããã
// 座æšã®äºä¹ãåèšããŠå¹³æ¹æ ¹ãåãã
// ãã¯ã¿ãŒã®å€§ãããèšç®ããŸãã`sqrt()` ã¡ãœããã䜿çšããŠã`v.sqrt()` ãšåæ§ã«
// å¹³æ¹æ ¹ãèšç®ããŸãã
fn magnitude(...) -> f64 {
todo!()
}
// 倧ãããèšç®ãããã¹ãŠã®åº§æšããã®å€§ããã§å²ãããšã§
// ãã¯ã¿ãŒãæ£èŠåããŸãã
fn normalize(...) {
todo!()
}
// 次㮠`main` ã䜿çšããŠåŠçããã¹ãããŸãã
fn main() {
println!("Magnitude of a unit vector: {}", magnitude(&[0.0, 1.0, 0.0]));
let mut v = [1.0, 2.0, 9.0];
println!("Magnitude of {v:?}: {}", magnitude(&v));
normalize(&mut v);
println!("Magnitude of {v:?} after normalization: {}", magnitude(&v));
}
解ç
ãŠãŒã¶ãŒå®çŸ©å
This segment should take about 50 minutes. It contains:
Slide | Duration |
---|---|
ååä»ãæ§é äœ | 10 minutes |
ã¿ãã«æ§é äœ | 10 minutes |
åæåïŒenumsïŒ | 5 minutes |
éç | 5 minutes |
åãšã€ãªã¢ã¹ | 2 minutes |
æŒç¿: ãšã¬ããŒã¿ãŒã§ã®ã€ãã³ã | 15 minutes |
ååä»ãæ§é äœ
C ã C++ ãšåæ§ã«ãRust ã¯ã«ã¹ã¿ã æ§é äœããµããŒãããŠããŸãã
Speaker Notes
This slide should take about 10 minutes.
ããŒãã€ã³ã:
- æ§é äœã¯ãC ã C++ ã«ãããŠãšåãããã«æ©èœããŸãã
- C++ ãšåæ§ã«ããŸã C ãšã¯ç°ãªããåãå®çŸ©ããã®ã« typedef ã¯å¿ èŠãããŸããã
- C++ ãšã¯ç°ãªããæ§é äœéã«ç¶æ¿ã¯ãããŸããã
- ããã§ãæ§é äœã«ã¯ããŸããŸãªåãããããšã説æããŸãããã
- ãµã€ãºããŒãã®æ§é äœïŒäŸ:
struct Foo;
ïŒã¯ãããåã«ãã¬ã€ããå®è£ ããŠãããã®ã®ãå€èªäœã«æ ŒçŽããããŒã¿ããªãå Žåã«äœ¿çšã§ããŸãã - 次ã®ã¹ã©ã€ãã§ã¯ããã£ãŒã«ãåãéèŠã§ãªãå Žåã«äœ¿çšãããã¿ãã«æ§é äœã玹ä»ããŸãã
- ãµã€ãºããŒãã®æ§é äœïŒäŸ:
- é©åãªååã®å€æ°ããã§ã«ããå Žåã¯ãçç¥åœ¢ã䜿çšããŠæ§é äœãäœæã§ããŸãã
- æ§æ
..avery
ã䜿çšãããšãæ瀺çã«ãã¹ãŠã®ãã£ãŒã«ããå ¥åããªããŠããå€ãæ§é äœã®ãã£ãŒã«ãã®å€§éšåãã³ããŒã§ããŸãããã®æ§æã¯ãåžžã«æåŸã®èŠçŽ ã«ããå¿ èŠããããŸãã
ã¿ãã«æ§é äœ
ãã£ãŒã«ãåãéèŠã§ãªãå Žåã¯ãã¿ãã«æ§é äœã䜿çšã§ããŸãã
ããã¯å€ãã®å Žåãåäžãã£ãŒã«ã ã©ãããŒïŒãã¥ãŒã¿ã€ããšåŒã°ããŸãïŒã«äœ¿çšãããŸãã
Speaker Notes
This slide should take about 10 minutes.
- ãã¥ãŒã¿ã€ãã¯ãããªããã£ãåã®å€ã«é¢ããè¿œå æ
å ±ããšã³ã³ãŒãããåªããæ¹æ³ã§ãã次ã«äŸã瀺ããŸãã
- æ°å€ã¯ããã€ãã®åäœã§æž¬å®ãããŸãïŒäžèšã®äŸã§ã¯
Newtons
ïŒã - ãã®å€ã¯äœææã«æ€èšŒã«åæ Œããããã
PhoneNumber(String)
ãŸãã¯OddNumber(u32)
ã䜿çšãããã³ã«åæ€èšŒããå¿ èŠã¯ãããŸããã
- æ°å€ã¯ããã€ãã®åäœã§æž¬å®ãããŸãïŒäžèšã®äŸã§ã¯
- ãã¥ãŒã¿ã€ãã® 1 ã€ã®ãã£ãŒã«ãã«ã¢ã¯ã»ã¹ããŠã
Newtons
åã«f64
ã®å€ãè¿œå ããæ¹æ³ã瀺ããŸãã- Rust ã§ã¯éåžžãäžæçãªããšïŒèªåã©ãã解é€ããæŽæ°ãšããŠã®ããŒã«å€ã®äœ¿çšãªã©ïŒã¯å¥œãŸããŸããã
- æŒç®åã®ãªãŒããŒããŒãã«ã€ããŠã¯ã3 æ¥ç®ïŒãžã§ããªã¯ã¹ïŒã§èª¬æããŸãã
- ãã®äŸã¯ãããŒãº ã¯ã©ã€ã¡ã€ã ãªãŒãã¿ãŒã®å€±æãåèã«ããŠããŸãã
åæåïŒenumsïŒ
enum
ããŒã¯ãŒãã䜿çšãããšãããã€ãã®ç°ãªãããªã¢ã³ããæã€åãäœæã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
ããŒãã€ã³ã:
- åæåã䜿çšãããšã1 ã€ã®åã§äžé£ã®å€ãåéã§ããŸãã
Direction
ã¯ããªã¢ã³ããæã€åã§ããDirection
ã«ã¯ãDirection::Left
ãšDirection::Right
ã® 2 ã€ã®å€ããããŸããPlayerMove
ã¯ã3 ã€ã®ããªã¢ã³ããæã€åã§ããRust ã¯ãã€ããŒãã«å ããŠå€å¥åŒãæ ŒçŽããããšã§ãå®è¡æã«ã©ã®ããªã¢ã³ããPlayerMove
å€ã«å«ãŸããŠããããææ¡ã§ããããã«ããŸãã- ããã§æ§é äœãšåæåãæ¯èŒããããšãããããããŸãã
- ã©ã¡ãã§ãããã£ãŒã«ãã®ãªãã·ã³ãã«ãªããŒãžã§ã³ïŒåäœæ§é äœïŒããããŸããŸãªãã£ãŒã«ããããããŒãžã§ã³ïŒããªã¢ã³ã ãã€ããŒãïŒã䜿çšã§ããŸãã
- åå¥ã®æ§é äœã䜿çšããŠãåæåã®ããŸããŸãªããªã¢ã³ããå®è£ ããããšãã§ããŸããããã®å Žåããããããã¹ãŠåæåã§å®çŸ©ãããŠããå Žåãšåãåã«ã¯ãªããŸããã
- Rust ã¯å€å¥åŒãä¿åããããã«æå°éã®ã¹ããŒã¹ã䜿çšããŸãã
-
å¿ èŠã«å¿ããŠãå¿ èŠæå°éã®ãµã€ãºã®æŽæ°ãæ ŒçŽããŸãã
-
èš±å¯ãããããªã¢ã³ãå€ããã¹ãŠã®ããããã¿ãŒã³ãã«ããŒããŠããªãå Žåãç¡å¹ãªããããã¿ãŒã³ã䜿çšããŠå€å¥åŒããšã³ã³ãŒãããŸãïŒããããã®æé©åãïŒãããšãã°ã
Option<&u8>
ã«ã¯None
ããªã¢ã³ãã«å¯ŸããæŽæ°ãžã®ãã€ã³ã¿ãŸãã¯NULL
ãæ ŒçŽãããŸãã -
å¿ èŠã«å¿ããŠïŒããšãã° C ãšã®äºææ§ã確ä¿ããããã«ïŒå€å¥åŒãå¶åŸ¡ã§ããŸãã
repr
ããªãå Žåã10001 㯠2 ãã€ãã«åãŸããããå€å¥åŒã®åã«ã¯ 2 ãã€ãã䜿çšãããŸãã
-
ãã®ä»
Rust ã«ã¯ãåæåãå ããã¹ããŒã¹ãå°ãªãããããã«äœ¿çšã§ããæé©åãããã€ããããŸãã
-
null ãã€ã³ã¿ã®æé©å: äžéšã®åã§ãRust ã¯
size_of::<T>()
ãsize_of::<Option<T>>()
ãšçããããšãä¿èšŒããŸãã以äžã®ãµã³ãã«ã³ãŒãã¯ããããåäœã®è¡šçŸãå®éã«ã©ã®ããã«ãªããã瀺ããŠããŸããã³ã³ãã€ã©ã¯ãã®è¡šçŸã«é¢ããŠä¿èšŒããªãã®ã§ãããã¯ãŸã£ããå®å šã§ã¯ãªãããšã«æ³šæããŠãã ããã
const
Constants are evaluated at compile time and their values are inlined wherever they are used:
Rust RFC Book ã«ãããšãå®æ°å€æ°ã¯äœ¿çšæã«ã€ã³ã©ã€ã³åãããŸãã
ã³ã³ãã€ã«æã« const
å€ãçæããããã«åŒã³åºããã®ã¯ãconst
ãšããŒã¯ãããé¢æ°ã®ã¿ã§ãããã ããconst
é¢æ°ã¯å®è¡æã«åŒã³åºãããšãã§ããŸãã
Speaker Notes
- Mention that
const
behaves semantically similar to C++âsconstexpr
- å®è¡æã«è©äŸ¡ãããå®æ°ãå¿ èŠã«ãªãããšã¯ããŸããããŸããããéçå€æ°ã䜿çšããããã䟿å©ã§å®å šã§ãã
static
éçå€æ°ã¯ããã°ã©ã ã®å®è¡å šäœãéããŠåç¶ããããã移åããŸããã
Rust RFC Book ã§èª¬æãããŠããããã«ãéçå€æ°ã¯äœ¿çšæã«ã€ã³ã©ã€ã³åããããå®éã®é¢é£ããã¡ã¢ãªäœçœ®ã«ååšããŸããããã¯å®å
šã§ãªãã³ãŒããåã蟌ã¿ã³ãŒãã«æçšã§ãããå€æ°ã¯ããã°ã©ã ã®å®è¡å
šäœãéããŠåç¶ããŸããã°ããŒãã« ã¹ã³ãŒãã®å€ã«ãªããžã§ã¯ã ID ãå¿
èŠãªãå Žåã¯ãäžè¬çã« const
ã䜿çšãããŸãã
Speaker Notes
This slide should take about 5 minutes.
static
is similar to mutable global variables in C++.static
ã¯ãªããžã§ã¯ã IDïŒã¡ã¢ãªå ã®ã¢ãã¬ã¹ïŒãšãå éšå¯å€æ§ãæã€åã«å¿ èŠãªç¶æ ïŒMutex<T>
ãªã©ïŒãæäŸããŸãã
ãã®ä»
static
å€æ°ã¯ã©ã®ã¹ã¬ããããã§ãã¢ã¯ã»ã¹ã§ãããããSync
ã§ããå¿
èŠããããŸããå
éšã®å¯å€æ§ã¯ãMutex
ãã¢ãããã¯ãªã©ã®æ¹æ³ã§å®çŸã§ããŸãã
ãã¯ã std::thread_local
ã䜿çšããŠãã¹ã¬ãã ããŒã«ã«ã®ããŒã¿ãäœæã§ããŸãã
åãšã€ãªã¢ã¹
åãšã€ãªã¢ã¹ã¯ãå¥ã®åã®ååãäœæããŸãããã® 2 ã€ã®åã¯åãæå³ã§äœ¿çšã§ããŸãã
Speaker Notes
This slide should take about 2 minutes.
C ããã°ã©ããŒã¯ãããã typedef
ãšåæ§ã®ãã®ãšèããã§ãããã
æŒç¿: ãšã¬ããŒã¿ãŒã§ã®ã€ãã³ã
ãšã¬ããŒã¿ãŒå¶åŸ¡ã·ã¹ãã ã§ã€ãã³ããè¡šãããŒã¿æ§é ãäœæããŸããããŸããŸãªã€ãã³ããæ§ç¯ããããã®åãšé¢æ°ãèªç±ã«å®çŸ©ããŠæ§ããŸããã#[derive(Debug)]
ã䜿çšããŠãåã {:?}
ã§ãã©ãŒãããã§ããããã«ããŸãã
ãã®æŒç¿ã«å¿
èŠãªã®ã¯ãmain
ããšã©ãŒãªãã§å®è¡ãããããã«ãããŒã¿æ§é ãäœæããŠå
¥åããããšã ãã§ãããã®ã³ãŒã¹ã®æ¬¡ã®ããŒãã§ã¯ããããã®æ§é ããããŒã¿ãååŸããæ¹æ³ã説æããŸãã
解ç
2æ¥ç®ã®è¬åº§ãžãããã
Rust ã«ã€ããŠããªãå€ãã®ããšãåŠãã§ããŸããããä»æ¥ã¯ Rust ã®åã·ã¹ãã ã«çŠç¹ãåœãŠãŸãã
- ãã¿ãŒã³ ãããã³ã°: æ§é ããã®ããŒã¿ã®æœåºã
- ã¡ãœãã: é¢æ°ãšåã®é¢é£ä»ãã
- ãã¬ã€ã: è€æ°ã®åã§å ±æãããæåã
- ãžã§ããªã¯ã¹: ä»ã®åã§ã®åã®ãã©ã¡ãŒã¿åã
- æšæºã©ã€ãã©ãªã®åãšãã¬ã€ã: Rust ã®è±å¯ãªæšæºã©ã€ãã©ãªã®çŽ¹ä»ã
ã¹ã±ãžã¥ãŒã«
Including 10 minute breaks, this session should take about 2 hours and 10 minutes. It contains:
Segment | Duration |
---|---|
ãããã | 3 minutes |
ãã¿ãŒã³ãããã³ã° | 1 hour |
Methods and Traits | 50 minutes |
ãã¿ãŒã³ãããã³ã°
This segment should take about 1 hour. It contains:
Slide | Duration |
---|---|
Matching Values | 10 minutes |
æ§é äœã®ãã¹ãã©ã¯ã | 4 minutes |
åæåã®ãã¹ãã©ã¯ã | 4 minutes |
Letå¶åŸ¡ãã㌠| 10 minutes |
æŒç¿: åŒã®è©äŸ¡ | 30 minutes |
Matching Values
match
ããŒã¯ãŒãã䜿çšãããšã1 ã€ä»¥äžã®ãã¿ãŒã³ã«å¯ŸããŠå€ãç
§åã§ããŸããäžããé ã«ç
§åãè¡ãããæåã«äžèŽãããã¿ãŒã³ã®ã¿ãå®è¡ãããŸãã
C ã C++ ã® switch
ãšåæ§ã«ããã¿ãŒã³ã«ã¯åçŽãªå€ãæå®ã§ããŸãã
The _
pattern is a wildcard pattern which matches any value. The expressions must be exhaustive, meaning that it covers every possibility, so _
is often used as the final catch-all case.
äžèŽãåŒãšããŠäœ¿çšã§ããŸããif
ãšåæ§ã«ãåãããã¢ãŒã ã¯åãåã«ããå¿
èŠããããŸããåã¯ããããã¯ã®æåŸã®åŒã§ãïŒååšããå ŽåïŒãäžèšã®äŸã§ã¯ãå㯠()
ã§ãã
ãã¿ãŒã³ã®å€æ°ïŒãã®äŸã§ã¯ key
ïŒã«ããããããã¢ãŒã å
ã§äœ¿çšã§ãããã€ã³ãã£ã³ã°ãäœæãããŸãã
ãããã¬ãŒãã«ãããæ¡ä»¶ã true ã®å Žåã«ã®ã¿ã¢ãŒã ãäžèŽããŸãã
Speaker Notes
This slide should take about 10 minutes.
ããŒãã€ã³ã:
-
ç¹å®ã®æåããã¿ãŒã³ã§ã©ã®ããã«äœ¿çšããããã説æããŸãã
|
ãor
ãšããŠæå®ãã..
ã¯å¿ èŠã«å¿ããŠå±éã§ãã1..=5
㯠5 ãå«ãç¯å²ãè¡šã_
ã¯ã¯ã€ã«ãã«ãŒããè¡šã
-
ãã¿ãŒã³ã®ã¿ã§ã¯è¡šçŸã§ããªãè€éãªæŠå¿µãç°¡æœã«è¡šçŸãããå Žåãç¬ç«ããæ§ææ©èœã§ãããããã¬ãŒãã¯éèŠãã€å¿ èŠã§ãã
-
ãããã¬ãŒãã¯ããããã¢ãŒã å ã®åå¥ã®
if
åŒãšã¯ç°ãªããŸããåå²ãããã¯å ïŒ=>
ã®åŸïŒã®if
åŒã¯ããããã¢ãŒã ãéžæãããåŸã«å®è¡ãããŸãããã®ãããã¯å ã§if
æ¡ä»¶ãæºããããªãã£ãå Žåãå ã®match
åŒã®ä»ã®ã¢ãŒã ã¯èæ ®ãããŸããã -
ã¬ãŒãã§å®çŸ©ãããæ¡ä»¶ã¯ã
|
ãä»ãããã¿ãŒã³å ã®ãã¹ãŠã®åŒã«é©çšãããŸãã
More To Explore
-
Another piece of pattern syntax you can show students is the
@
syntax which binds a part of a pattern to a variable. For example:In this example
inner
has the value 123 which it pulled from theOption
via destructuring,outer
captures the entireSome(inner)
expression, so it contains the fullOption::Some(123)
. This is rarely used but can be useful in more complex patterns.
æ§é äœïŒstructsïŒ
Like tuples, Struct can also be destructured by matching:
Speaker Notes
This slide should take about 4 minutes.
foo
ã®ãªãã©ã«å€ãä»ã®ãã¿ãŒã³ãšäžèŽããããã«å€æŽããŸããFoo
ã«æ°ãããã£ãŒã«ããè¿œå ããå¿ èŠã«å¿ããŠãã¿ãŒã³ã«å€æŽãå ããŸãã- ãã£ããã£ãšå®æ°åŒãåºå¥ãã¥ããå ŽåããããŸãã2 ã€ç®ã®ã¢ãŒã ã®
2
ãå€æ°ã«å€æŽããŠã¿ãŠãããŸãæ©èœããªãããšã確èªããŸãããããconst
ã«å€æŽããŠãåã³åäœããããšã確èªããŸãã
åæåïŒenumsïŒ
Like tuples, enums can also be destructured by matching:
ãã¿ãŒã³ã¯ãå€æ°ãå€ã®äžéšã«ãã€ã³ãããããã«ã䜿çšã§ããŸãã以äžã®ããã«ããŠãåã®æ§é ã調ã¹ãããšãã§ããŸããåçŽãª enum
ããå§ããŸãããã
ããã§ã¯ãã¢ãŒã ïŒarm, ãã¿ãŒã³ã䞊ã¹ããã®ïŒã䜿çšã㊠Result
å€ã®å解ãè¡ã£ãŠããŸããæåã®ã¢ãŒã ã§ã¯ãhalf
㯠Ok
ããªã¢ã³ãå
ã®å€ã«ãã€ã³ããããŸãã2 ã€ç®ã®ã¢ãŒã ã§ã¯ msg
ããšã©ãŒ ã¡ãã»ãŒãžã«ãã€ã³ããããŸãã
Speaker Notes
This slide should take about 4 minutes.
if
/else
åŒã¯ãåŸã§match
ã§ã¢ã³ããã¯ãããåæåãè¿ããŠããŸãã- åæåã®å®çŸ©ã« 3 ã€ç®ã®ããªã¢ã³ãïŒåæåã®èŠçŽ ã®ããšïŒãè¿œå ããã³ãŒãå®è¡æã«ãšã©ãŒã衚瀺ããŠã¿ãŸããããã³ãŒããç¶²çŸ ãããŠããªãç®æã瀺ããã³ã³ãã€ã©ãã©ã®ããã«ãã³ããæäŸããããšããŠãããã説æããŸãã
- åæåããªã¢ã³ãã®å€ã«ã¯ããã¿ãŒã³ãäžèŽããå Žåã«ã®ã¿ã¢ã¯ã»ã¹ã§ããŸãã
- æ€çŽ¢ãç¶²çŸ çã§ãªãå Žåã«ã©ããªããã瀺ããŸãããã¹ãŠã®ã±ãŒã¹ãåŠçãããã¿ã€ãã³ã°ã確èªããããšã§ãRust ã³ã³ãã€ã©ã®å©ç¹ã匷調ããŸãã
Letå¶åŸ¡ãããŒ
Rust ã«ã¯ãä»ã®èšèªãšã¯ç°ãªãå¶åŸ¡ãããŒæ§é ãããã€ããããŸãããããã¯ãã¿ãŒã³ ãããã³ã°ã«äœ¿çšãããŸãã
if let
åŒlet else
åŒwhile let
åŒ
if let
åŒ
if let
åŒ ã䜿çšãããšãå€ããã¿ãŒã³ã«äžèŽãããã©ããã«å¿ããŠç°ãªãã³ãŒããå®è¡ã§ããŸãã
let else
åŒ
ãã¿ãŒã³ããããããŠé¢æ°ããæ»ããšããäžè¬çãªã±ãŒã¹ã§ã¯ãlet else
ã䜿çšããŸãããelseãã±ãŒã¹ã¯çºæ£ããå¿
èŠããããŸãïŒreturn
ãbreak
ããããã¯ãªã©ããããã¯ããæãããã®ä»¥å€ã®ãã¹ãŠïŒã
if let
ã«äŒŒã while let
掟çç©ããããŸããããã¯ããã¿ãŒã³ã«ç
§ãããŠå€ããã¹ãããŸãã
ãã㧠String::pop
ã¯ãæååã空ã«ãªããŸã§ Some(c)
ãè¿ãããã®åŸ None
ãè¿ããŸããwhile let
ã䜿çšãããšããã¹ãŠã®ã¢ã€ãã ã«å¯ŸããŠå埩åŠçãç¶è¡ã§ããŸãã
Speaker Notes
This slide should take about 10 minutes.
if-let
match
ãšã¯ç°ãªããif let
ã§ã¯ãã¹ãŠã®åå²ãç¶²çŸ ããå¿ èŠã¯ãªããããmatch
ãããç°¡æœã«ãªããŸãã- äžè¬çãªäœ¿çšæ¹æ³ã¯ã
Option
ãæäœãããšãã«Some
å€ãåŠçããããšã§ãã match
ãšã¯ç°ãªããif let
ã¯ãã¿ãŒã³ ãããã³ã°ã§ã¬ãŒãç¯ããµããŒãããŠããŸããã
let-else
次ã«ç€ºãããã«ãif let
ã¯ç©ã¿éãªã£ãŠããŸãããšããããŸããlet-else
ã®æ§æã¯ããã®ãã¹ããããã³ãŒããå¹³åŠã«ããå©ããšãªããŸããèªã¿ã¥ããããŒãžã§ã³ãåè¬è
åãã«æžãçŽããŠãåè¬è
ãå€åã確èªã§ããããã«ããŸãã
æžãæããããŒãžã§ã³ã¯æ¬¡ã®ãšããã§ãã
while-let
- å€ããã¿ãŒã³ã«äžèŽããéãã
while let
ã«ãŒããç¹°ãè¿ãããããšã説æããŸãã name.pop()
ã§unwrapããå€ããªãå Žåã«äžæãã if ã¹ããŒãã¡ã³ãã䜿çšããŠãwhile let
ã«ãŒããç¡éã«ãŒãã«æžãæããããšãã§ããŸããwhile let
ã¯ãäžèšã®ã·ããªãªã®ç³è¡£æ§æãšããŠäœ¿çšã§ããŸãã
æŒç¿: åŒã®è©äŸ¡
æŒç®åŒçšã®ç°¡åãªååž°ãšããªã¥ãšãŒã¿ãäœæããŠã¿ãŸãããã
An example of a small arithmetic expression could be 10 + 20
, which evaluates to 30
. We can represent the expression as a tree:
A bigger and more complex expression would be (10 * 9) + ((3 - 4) * 5)
, which evaluate to 85
. We represent this as a much bigger tree:
In code, we will represent the tree with two types:
ããã§ã® Box
åã¯ã¹ããŒã ãã€ã³ã¿ã§ãã詳现ã¯ãã®è¬åº§ã§åŸã»ã©èª¬æããŸãããã¹ãã§èŠãããããã«ãåŒã¯ Box::new
ã§ãããã¯ã¹åãã§ããŸããããã¯ã¹åãããåŒãè©äŸ¡ããã«ã¯ãéåç
§æŒç®åïŒ*
ïŒã䜿çšããŠãããã¯ã¹å解é€ãããŸãïŒeval(*boxed_expr)
ïŒã
äžéšã®åŒã¯è©äŸ¡ã§ããããšã©ãŒãè¿ãããŸããæšæºã® Result<Value, String>
åã¯ãæåããå€ïŒOk(Value)
ïŒãŸãã¯ãšã©ãŒïŒErr(String)
ïŒã®ãããããè¡šãåæåã§ãããã®åã«ã€ããŠã¯ãåŸã»ã©è©³ãã説æããŸãã
ã³ãŒããã³ããŒã㊠Rust ãã¬ã€ã°ã©ãŠã³ãã«è²Œãä»ããeval
ã®å®è£
ãéå§ããŸããå®æãããšããªã¥ãšãŒã¿ã¯ãã¹ãã«åæ Œããå¿
èŠããããŸããtodo!()
ã䜿çšããŠããã¹ãã 1 ã€ãã€å®æœããããšãããããããŸãã#[ignore]
ã䜿çšããŠããã¹ããäžæçã«ã¹ãããããããšãã§ããŸãã
#[test]
#[ignore]
fn test_value() { .. }
解ç
Methods and Traits
This segment should take about 50 minutes. It contains:
Slide | Duration |
---|---|
ã¡ãœãã | 10 minutes |
ãã¬ã€ãïŒtraitïŒ | 15 minutes |
å°åº | 3 minutes |
æŒç¿: ãžã§ããªãã¯ãªãã¬ãŒ | 20 minutes |
ã¡ãœãã
Rust ã䜿çšãããšãé¢æ°ãæ°ããåã«é¢é£ä»ããããšãã§ããŸãããã㯠impl
ãããã¯ã§å®è¡ããŸãã
self
åŒæ°ã¯ããã¬ã·ãŒãããã€ãŸãã¡ãœãããæäœãããªããžã§ã¯ããæå®ããŸããã¡ãœããã®äžè¬çãªã¬ã·ãŒãã¯æ¬¡ã®ãšããã§ãã
&self
: å ±æã®äžå€åç §ã䜿çšããŠãåŒã³åºãå ãããªããžã§ã¯ããåçšããŸãããã®ãªããžã§ã¯ãã¯åŸã§åã³äœ¿çšã§ããŸãã&mut self
: äžæã®å¯å€åç §ã䜿çšããŠãåŒã³åºãå ãããªããžã§ã¯ããåçšããŸãããã®ãªããžã§ã¯ãã¯åŸã§åã³äœ¿çšã§ããŸããself
: ãªããžã§ã¯ãã®æææš©ãååŸããåŒã³åºãå ããé ãããŸããã¡ãœããããªããžã§ã¯ãã®ææè ã«ãªããŸããæææš©ãæ瀺çã«éä¿¡ãããªãéããã¡ãœãããæ»ããšããªããžã§ã¯ãã¯ç Žæ£ïŒãã¢ãã±ãŒãïŒãããŸããå®å šãªæææš©ã¯ãå¿ ãããå¯å€æ§ãæå³ããããã§ã¯ãããŸãããmut self
: äžèšãšåãã§ãããã¡ãœããã¯ãªããžã§ã¯ããå€æŽã§ããŸãã- ã¬ã·ãŒããªã: æ§é äœã®éçã¡ãœããã«ãªããŸããéåžžã¯ã
new
ãšåŒã°ããã³ã³ã¹ãã©ã¯ã¿ãäœæããããã«äœ¿çšãããŸãã
Speaker Notes
This slide should take about 8 minutes.
ããŒãã€ã³ã:
- ã¡ãœãããé¢æ°ãšæ¯èŒããŠçŽ¹ä»ãããšããã§ãããã
- ã¡ãœããã¯åïŒæ§é äœãåæåãªã©ïŒã®ã€ã³ã¹ã¿ã³ã¹ã§åŒã³åºãããŸããæåã®ãã©ã¡ãŒã¿ã¯ã€ã³ã¹ã¿ã³ã¹ã
self
ãšããŠè¡šããŸãã - ããããããŒã¯ãã¡ãœãã ã¬ã·ãŒãæ§æã§ã³ãŒããæŽçããç®çã§ãã¡ãœããã䜿çšããããšãã§ããŸããã¡ãœããã䜿çšããããšã§ããã¹ãŠã®å®è£ ã³ãŒãã 1 ã€ã®äºæž¬å¯èœãªå Žæã«ãŸãšããããšãã§ããŸãã
- ã¡ãœããã¯åïŒæ§é äœãåæåãªã©ïŒã®ã€ã³ã¹ã¿ã³ã¹ã§åŒã³åºãããŸããæåã®ãã©ã¡ãŒã¿ã¯ã€ã³ã¹ã¿ã³ã¹ã
- ã¡ãœãã ã¬ã·ãŒãã§ãã
self
ãšããããŒã¯ãŒãã®äœ¿çšã«ã€ããŠèª¬æããŸããself: Self
ã®ç¥èªã§ããããšã瀺ããæ§é äœåã®äœ¿çšæ¹æ³ã«ã€ããŠã説æããããšãããããããŸããSelf
ã¯impl
ãããã¯ãååšããåã®åãšã€ãªã¢ã¹ã§ããããããã¯å ã®ä»ã®å Žæã§äœ¿çšã§ããããšã説æããŸããself
ã¯ä»ã®æ§é äœãšåæ§ã«äœ¿çšããããããè¡šèšã䜿çšããŠåã ã®ãã£ãŒã«ããåç §ã§ããããšã説æããŸãã- ããã§
finish
ã 2 åå®è¡ããŠã&self
ãšself
ã®éãã瀺ãããšãããããããŸãã self
ã®ããªã¢ã³ã以å€ã«ããã¬ã·ãŒãåãšããŠèš±å¯ãããŠãã ç¹å¥ãªã©ãããŒåïŒBox<Self>
ãªã©ïŒããããŸãã
ãã¬ã€ãïŒtraitïŒ
Rustã§ã¯ãåã«é¢ããŠã®æœè±¡åããã¬ã€ããçšããŠè¡ãããšãã§ããŸãããã¬ã€ãã¯ã€ã³ã¿ãŒãã§ãŒã¹ã«äŒŒãŠããŸãïŒ
Speaker Notes
This slide and its sub-slides should take about 15 minutes.
-
ãã¬ã€ãã¯ããã®ãã¬ã€ããå®è£ ããããã«ååã«å¿ èŠãªå€æ°ã®ã¡ãœãããå®çŸ©ããŸãã
-
In the âGenericsâ segment, next, we will see how to build functionality that is generic over all types implementing a trait.
ãã¬ã€ãã®å®è£
Speaker Notes
-
To implement
Trait
forType
, you use animpl Trait for Type { .. }
block. -
Unlike Go interfaces, just having matching methods is not enough: a
Cat
type with atalk()
method would not automatically satisfyPet
unless it is in animpl Pet
block. -
Traits may provide default implementations of some methods. Default implementations can rely on all the methods of the trait. In this case,
greet
is provided, and relies ontalk
.
ã¹ãŒããŒãã¬ã€ã
A trait can require that types implementing it also implement other traits, called supertraits. Here, any type implementing Pet
must implement Animal
.
Speaker Notes
This is sometimes called âtrait inheritanceâ but students should not expect this to behave like OO inheritance. It just specifies an additional requirement on implementations of a trait.
é¢é£å
Associated types are placeholder types which are supplied by the trait implementation.
Speaker Notes
-
Associated types are sometimes also called âoutput typesâ. The key observation is that the implementer, not the caller, chooses this type.
-
Many standard library traits have associated types, including arithmetic operators and
Iterator
.
å°åº
ãµããŒããããŠãããã¬ã€ãã¯ã次ã®ããã«ã«ã¹ã¿ã åã«èªåçã«å®è£ ã§ããŸãã
Speaker Notes
This slide should take about 3 minutes.
å°åºã¯ãã¯ãã§å®è£
ãããå€ãã®ã¯ã¬ãŒãã«ã¯æçšãªæ©èœãè¿œå ããããã®äŸ¿å©ãªå°åºãã¯ããçšæãããŠããŸããããšãã°ãserde
㯠#[derive(Serialize)]
ã䜿çšããŠãæ§é äœã®ã·ãªã¢ã«åã®ãµããŒããå°åºã§ããŸãã
Exercise: Logger Trait
ãã¬ã€ã Logger
ãš log
ã¡ãœããã䜿çšããŠãã·ã³ãã«ãªãã®ã³ã°ãŠãŒãã£ãªãã£ãèšèšããŠã¿ãŸããããé²è¡ç¶æ³ããã°ã«èšé²ããã³ãŒãã¯ããã®åŸã« &impl Logger
ãåãåãããšãã§ããŸãããã®å Žåããã¹ãã§ã¯ãã¹ããã°ãã¡ã€ã«ã«ã¡ãã»ãŒãžãæžã蟌ãŸããŸãããæ¬çªç°å¢ãã«ãã§ã¯ãã°ãµãŒããŒã«ã¡ãã»ãŒãžãéä¿¡ãããŸãã
However, the StdoutLogger
given below logs all messages, regardless of verbosity. Your task is to write a VerbosityFilter
type that will ignore messages above a maximum verbosity.
ããã¯äžè¬çãªãã¿ãŒã³ã§ããã€ãŸãããã¬ã€ãå®è£ ãã©ããããŠåããã¬ã€ããå®è£ ãããã®éçšã§æåãè¿œå ããŠããæ§é äœã§ãããã®ã³ã°ãŠãŒãã£ãªãã£ã§ã¯ä»ã«ã©ã®ãããªçš®é¡ã®ã©ãããŒã圹ç«ã€ã§ããããã
pub trait Logger {
/// æå®ããã詳现床ã¬ãã«ã§ã¡ãã»ãŒãžããã°ã«èšé²ããŸãã
fn log(&self, verbosity: u8, message: &str);
}
struct StdoutLogger;
impl Logger for StdoutLogger {
fn log(&self, verbosity: u8, message: &str) {
println!("verbosity={verbosity}: {message}");
}
}
// TODO: `VerbosityFilter` ãå®çŸ©ããŠå®è£
ããŸãã
fn main() {
let logger = VerbosityFilter { max_verbosity: 3, inner: StdoutLogger };
logger.log(5, "FYI");
logger.log(2, "Uhoh");
}
解ç
ãããã
Including 10 minute breaks, this session should take about 3 hours and 15 minutes. It contains:
Segment | Duration |
---|---|
ãžã§ããªã¯ã¹ïŒgenericsïŒ | 45 minutes |
æšæºã©ã€ãã©ãªå ã®å | 1 hour |
æšæºã©ã€ãã©ãªå ã®ãã¬ã€ã | 1 hour and 10 minutes |
ãžã§ããªã¯ã¹ïŒgenericsïŒ
This segment should take about 45 minutes. It contains:
Slide | Duration |
---|---|
ãžã§ããªãã¯é¢æ° | 5 minutes |
ãžã§ããªãã¯ããŒã¿å | 10 minutes |
ãã¬ã€ãå¶çŽ | 10 minutes |
impl Trait | 5 minutes |
dyn Trait | 5 minutes |
æŒç¿: ãžã§ããªãã¯ãª min | 10 minutes |
ãžã§ããªãã¯é¢æ°
Rust supports generics, which lets you abstract algorithms or data structures (such as sorting or a binary tree) over the types used or stored.
Speaker Notes
This slide should take about 5 minutes.
-
Rust ã¯åŒæ°ãšæ»ãå€ã®åã«åºã¥ã㊠T ã®åãæšæž¬ããŸãã
-
In this example we only use the primitive types
i32
and&str
forT
, but we can use any type here, including user-defined types:struct Foo { val: u8, } pick(123, Foo { val: 7 }, Foo { val: 456 });
-
ãã㯠C++ ãã³ãã¬ãŒãã«äŒŒãŠããŸãããRust ã¯ãžã§ããªãã¯é¢æ°ãéšåçã«ããã«ã³ã³ãã€ã«ããããããã®é¢æ°ã¯å¶çŽã«äžèŽãããã¹ãŠã®åã«å¯ŸããŠæå¹ã§ããå¿ èŠããããŸããããšãã°ã
n == 0
ã®å Žåã¯even + odd
ãè¿ãããã«pick
ãå€æŽããŠã¿ãŠãã ãããæŽæ°ã䜿çšããpick
ã€ã³ã¹ã¿ã³ã¹åã®ã¿ã䜿çšãããŠããå Žåã§ããRust ã¯ãããç¡å¹ãšã¿ãªããŸããC++ ã§ã¯ãããè¡ãããšãã§ããŸãã -
Generic code is turned into non-generic code based on the call sites. This is a zero-cost abstraction: you get exactly the same result as if you had hand-coded the data structures without the abstraction.
ãžã§ããªãã¯ããŒã¿å
ãžã§ããªã¯ã¹ã䜿ã£ãŠãå ·äœçãªãã£ãŒã«ãã®åãæœè±¡åããããšãã§ããŸãïŒ
Speaker Notes
This slide should take about 10 minutes.
-
Q: ãªã
T
ã¯ïŒåãimpl<T> Point<T> {}
ã«ãããŠæå®ãããã®ã§ããããïŒåé·ã§ã¯ãããŸãããïŒ- ãªããªããããã¯ãžã§ããªã¯ã¹ã«å¯ŸããŠã®ãžã§ããªãã¯ãªå®è£ ã®ç®æã ããã§ãããããã¯ç¬ç«ããŠãžã§ããªãã¯ã§ãã
- ã€ãŸãããã®ãããªã¡ãœããã¯ä»»æã®
T
ã«å¯ŸããŠå®çŸ©ããããšããããšã§ãã - It is possible to write
impl Point<u32> { .. }
.Point
ã¯ããã§ããªããžã§ããªãã¯ã§ãããPoint<f64>
ã䜿ãããšãã§ããŸãããããããã®ãããã¯ã§ã®ã¡ãœããã¯Point<u32>
ã«å¯ŸããŠã®ã¿å©çšå¯èœãšãªããŸãã
-
æ°ããå€æ°
let p = Point { x: 5, y: 10.0 };
ã宣èšããŠã¿ãŠãã ããã2 ã€ã®å€æ°ïŒT
ãšU
ãªã©ïŒã䜿çšããŠãç°ãªãåã®èŠçŽ ãæã€ãã€ã³ããèš±å¯ããããã«ã³ãŒããæŽæ°ããŸãã
ãžã§ããªãã¯ãã¬ã€ã
Traits can also be generic, just like types and functions. A traitâs parameters get concrete types when it is used.
Speaker Notes
-
The
From
trait will be covered later in the course, but its definition in thestd
docs is simple. -
Implementations of the trait do not need to cover all possible type parameters. Here,
Foo::from("hello")
would not compile because there is noFrom<&str>
implementation forFoo
. -
Generic traits take types as âinputâ, while associated types are a kind of âoutputâ type. A trait can have multiple implementations for different input types.
-
In fact, Rust requires that at most one implementation of a trait match for any type T. Unlike some other languages, Rust has no heuristic for choosing the âmost specificâ match. There is work on adding this support, called specialization.
ãã¬ã€ãå¶çŽ
ãžã§ããªã¯ã¹ãçšãããšãããããã¬ã€ãã®ã¡ãœãããåŒã³åºããããã«ãåããã®ãã¬ã€ããå®è£ ããŠããããšãèŠæ±ãããããšããããããŸããïŒè泚ïŒæ¬ææã§ã¯âTrait boundsâãããã¬ã€ãå¶çŽããšç¿»èš³ããŸããããRustã®æ¥æ¬èªç¿»èš³ã³ãã¥ããã£ã§ã¯ããã¬ã€ãå¢çããšåŒã¶æµæŽŸããããã©ã¡ãã®ç¿»èš³ãæ¡çšãããã«ã€ããŠã¯è°è«ããªãããŠããŸããïŒ
You can do this with T: Trait
:
Speaker Notes
This slide should take about 8 minutes.
-
Try making a
NonCloneable
and passing it toduplicate
. -
è€æ°ã®ãã¬ã€ããå¿ èŠãªå Žåã¯ã
+
ã䜿ã£ãŠçµåããŸãã -
where
ç¯ã®äœ¿ãæ¹ã瀺ããŸããããåè¬çã¯ã³ãŒããèªãã§ãããšãã«ããã®where
ç¯ã«ééããŸããfn duplicate<T>(a: T) -> (T, T) where T: Clone, { (a.clone(), a.clone()) }
- ããããã®ãã©ã¡ã¿ãããå Žåã«ã
where
ç¯ã¯é¢æ°ã®ã·ã°ããã£ãæŽçæŽé ããŠãããŸãã where
ç¯ã«ã¯æŽã«åŒ·åãªæ©èœããããŸãã- 誰ãã«èãããå Žåã§è¯ãã§ããããã®æ©èœãšããã®ã¯ãâ:â ã®å·ŠåŽã«ã¯
Option<T>
ã®ããã«ä»»æã®åãè¡šçŸã§ãããšãããã®ã§ãã
- 誰ãã«èãããå Žåã§è¯ãã§ããããã®æ©èœãšããã®ã¯ãâ:â ã®å·ŠåŽã«ã¯
- ããããã®ãã©ã¡ã¿ãããå Žåã«ã
-
ãªããRust ã¯ãŸã ç¹å(specialization)ããµããŒãããŠããŸãããããšãã°ãå ã®
duplicate
ãããå Žåã¯ãç¹åãããduplicate(a: u32)
ãè¿œå ããããšã¯ã§ããŸããã
impl Trait
ãã¬ã€ãå¢çãšäŒŒãããã«ãæ§æ impl Trait
ã¯é¢æ°ã®åŒæ°ãšè¿ãå€ã«ãããŠã®ã¿å©çšå¯èœã§ãïŒ
Speaker Notes
This slide should take about 5 minutes.
impl Trait
allows you to work with types which you cannot name. The meaning of impl Trait
is a bit different in the different positions.
-
ãã©ã¡ã¿ã«å¯ŸããŠã¯ã
impl Trait
ã¯ããã¬ã€ãå¢çãæã€å¿åã®ãžã§ããªãã¯ãã©ã¡ã¿ã®ãããªãã®ã§ãã -
è¿ãå€ã®åã«çšããå Žåã¯ãç¹å®ã®ãã¬ã€ããå®è£ ããäœããã®å ·è±¡åãè¿ãããå ·äœçãªååã¯æ瀺ããªããšããããšãæå³ããŸãããã®ããšã¯å ¬éãããAPIã«å ·è±¡åãæããããªãå Žåã«äŸ¿å©ã§ãã
è¿ãå€ã®äœçœ®ã«ãããåæšè«ã¯å°é£ã§ãã
impl Foo
ãè¿ãé¢æ°ã¯ããããè¿ãå ·è±¡åã¯ãœãŒã¹ã³ãŒãã«æžãããããšãªããŸãŸãå ·è±¡åãéžã³ãŸããcollect<B>() -> B
ã®ãããªãžã§ããªãã¯åãè¿ãé¢æ°ã¯ãB
ãæºããã©ã®ãããªåã§ãè¿ãããšããããŸãã ãŸããé¢æ°ã®åŒã³åºãå ã¯ãã®ãããªåãäžã€ãéžã¶å¿ èŠããããããããŸããã ããã¯ãlet x: Vec<_> = foo.collect()
ãšããããturbofishãçšããŠfoo.collect::<Vec<_>>()
ãšããããšã§è¡ããŸãã
debuggable
ã®åã¯äœã§ãããããlet debuggable: () = ..
ãè©ŠããŠããšã©ãŒ ã¡ãã»ãŒãžã®å
容ã確èªããŠãã ããã
dyn Trait
In addition to using traits for static dispatch via generics, Rust also supports using them for type-erased, dynamic dispatch via trait objects:
Speaker Notes
This slide should take about 5 minutes.
-
Generics, including
impl Trait
, use monomorphization to create a specialized instance of the function for each different type that the generic is instantiated with. This means that calling a trait method from within a generic function still uses static dispatch, as the compiler has full type information and can resolve which typeâs trait implementation to use. -
When using
dyn Trait
, it instead uses dynamic dispatch through a virtual method table (vtable). This means that thereâs a single version offn dynamic
that is used regardless of what type ofPet
is passed in. -
When using
dyn Trait
, the trait object needs to be behind some kind of indirection. In this case itâs a reference, though smart pointer types likeBox
can also be used (this will be demonstrated on day 3). -
At runtime, a
&dyn Pet
is represented as a âfat pointerâ, i.e. a pair of two pointers: One pointer points to the concrete object that implementsPet
, and the other points to the vtable for the trait implementation for that type. When calling thetalk
method on&dyn Pet
the compiler looks up the function pointer fortalk
in the vtable and then invokes the function, passing the pointer to theDog
orCat
into that function. The compiler doesnât need to know the concrete type of thePet
in order to do this. -
A
dyn Trait
is considered to be âtype-erasedâ, because we no longer have compile-time knowledge of what the concrete type is.
æŒç¿: ãžã§ããªãã¯ãª min
In this short exercise, you will implement a generic min
function that determines the minimum of two values, using the Ord
trait.
use std::cmp::Ordering;
// TODO: `main` ã§äœ¿çšãã `min` é¢æ°ãå®è£
ããŸãã
fn main() {
assert_eq!(min(0, 10), 0);
assert_eq!(min(500, 123), 123);
assert_eq!(min('a', 'z'), 'a');
assert_eq!(min('7', '1'), '1');
assert_eq!(min("hello", "goodbye"), "goodbye");
assert_eq!(min("bat", "armadillo"), "armadillo");
}
Speaker Notes
This slide and its sub-slides should take about 10 minutes.
解ç
æšæºã©ã€ãã©ãªå ã®å
This segment should take about 1 hour. It contains:
Slide | Duration |
---|---|
æšæºã©ã€ãã©ãª | 3 minutes |
ããã¥ã¡ã³ã | 5 minutes |
Option | 10 minutes |
Result | 5 minutes |
String | 5 minutes |
Vec | 5 minutes |
HashMap | 5 minutes |
æŒç¿: ã«ãŠã³ã¿ãŒ | 20 minutes |
Speaker Notes
ãã®ã»ã¯ã·ã§ã³ã®åã¹ã©ã€ãã§ã¯ãæéããããŠããã¥ã¡ã³ã ããŒãžã確èªããããäžè¬çãªã¡ãœãããããã€ãåãäžããŠãã ããã
æšæºã©ã€ãã©ãª
Rust ã«ã¯ãRust ã®ã©ã€ãã©ãªãšããã°ã©ã ã§äœ¿çšãããäžè¬çãªåã®ã»ããã確ç«ããã®ã«åœ¹ç«ã€æšæºã©ã€ãã©ãªãä»å±ããŠããŸãã2 ã€ã®ã©ã€ãã©ãªãã¹ã ãŒãºã«é£æºãããããšãã§ããã®ã¯ããã®ããã«äž¡æ¹ãšãåã String
åã䜿çšããŠããããã§ãã
å®éãRust ã«ã¯æšæºã©ã€ãã©ãªïŒcore
ãalloc
ãstd
ïŒã®è€æ°ã®ã¬ã€ã€ãå«ãŸããŠããŸãã
core
ã«ã¯ãlibc
ãã¢ãã±ãŒã¿ãããã«ã¯ãªãã¬ãŒãã£ã³ã° ã·ã¹ãã ã®ååšã«ãäŸåããªããæãåºæ¬çãªåãšé¢æ°ãå«ãŸããŸããalloc
ã«ã¯ãVec
ãBox
ãArc
ãªã©ãã°ããŒãã«ããŒãã¢ãã±ãŒã¿ãå¿ èŠãšããåãå«ãŸããŸãã- å€ãã®å Žåãåã蟌ã¿ã® Rust ã¢ããªã¯
core
ã®ã¿ã䜿çšããå Žåã«ãã£ãŠã¯alloc
ã䜿çšããŸãã
ããã¥ã¡ã³ã
Rust ã«ã¯è©³çŽ°ãªããã¥ã¡ã³ããçšæãããŠããŸãã次ã«äŸã瀺ããŸãã
- All of the details about loops.
u8
ã®ãããªããªããã£ãåãOption
ãBinaryHeap
ãªã©ã®æšæºã©ã€ãã©ãªåã
Use rustup doc --std
or https://std.rs to view the documentation.
å®éãç¬èªã®ã³ãŒãã«ããã¥ã¡ã³ããã€ããããšãã§ããŸãã
ã³ã³ãã³ãã¯ããŒã¯ããŠã³ãšããŠæ±ãããŸããå
¬éããããã¹ãŠã® Rust ã©ã€ãã©ãª ã¯ã¬ãŒãã¯ãrustdoc ããŒã«ã䜿çšããŠãdocs.rs
ã§èªåçã«ããã¥ã¡ã³ãããŸãšããããŸãããã®ãã¿ãŒã³ã䜿çšããŠããã¹ãŠã®å
¬éã¢ã€ãã ã API ã§ããã¥ã¡ã³ãåããã®ãæ
£çšçã§ãã
ã¢ã€ãã å
ïŒã¢ãžã¥ãŒã«å
ãªã©ïŒããã¢ã€ãã ãããã¥ã¡ã³ãåããã«ã¯ããå
éšããã¥ã¡ã³ãã®ã³ã¡ã³ãããšåŒã°ãã //!
ãŸã㯠/*! .. */
ã䜿çšããŸãã
Speaker Notes
This slide should take about 5 minutes.
- https://docs.rs/rand ã§
rand
ã¯ã¬ãŒãçšã«çæãããããã¥ã¡ã³ããåè¬è ã«ç€ºããŸãã
Option
Option<T>
ã®äœ¿çšæ¹æ³ã«ã€ããŠã¯ãã§ã«ããã€ãèŠãŠããŸããããããã¯å T
ã®å€ãæ ŒçŽããããäœãæ ŒçŽããŸãããããšãã°ãString::find
㯠Option<usize>
ãè¿ããŸãã
Speaker Notes
This slide should take about 10 minutes.
-
Option
is widely used, not just in the standard library. -
unwrap
ã¯Option
å ã®å€ãè¿ããããããã¯ã«ãªããŸããexpect
ãåæ§ã§ããããšã©ãŒã¡ãã»ãŒãžãåãåããŸãã- None ã§ãããã¯ã«ãªãå ŽåããããŸãããã誀ã£ãŠãNone ã®ãã§ãã¯ãå¿ããããšã¯ãããŸããã
- äœããäžç·ã«ãããã³ã°ããå Žåã¯ããã¡ãã¡ã§
unwrap
/expect
ãè¡ãã®ãäžè¬çã§ãããæ¬çªç°å¢ã®ã³ãŒãã¯éåžžãNone
ãããé©åã«åŠçããŸãã
-
The âniche optimizationâ means that
Option<T>
often has the same size in memory asT
, if there is some representation that is not a valid value of T. For example, a reference cannot be NULL, soOption<&T>
automatically uses NULL to represent theNone
variant, and thus can be stored in the same memory as&T
.
Result
Result
is similar to Option
, but indicates the success or failure of an operation, each with a different enum variant. It is generic: Result<T, E>
where T
is used in the Ok
variant and E
appears in the Err
variant.
Speaker Notes
This slide should take about 5 minutes.
Option
ãšåæ§ã«ãæåããå€ã¯Result
ã®å éšã«ãããããããããŒã¯ãããæ瀺çã«æœåºããå¿ èŠããããŸããããã«ããããšã©ãŒãã§ãã¯ãä¿é²ãããŸãããšã©ãŒãçºçããŠã¯ãªããªãå Žåã¯ãunwrap()
ãŸãã¯expect()
ãåŒã³åºãããšãã§ããŸãããããããããããŒã®ã€ã³ãã³ãã®ã·ã°ãã«ã§ããResult
ã®ããã¥ã¡ã³ããèªãããšãããããŸãããããã®è¬åº§ã§ã¯åãäžããŸããããèšåãã䟡å€ããããŸãããã®ããã¥ã¡ã³ãã«ã¯ãé¢æ°åããã°ã©ãã³ã°ã«åœ¹ç«ã€äŸ¿å©ãªã¡ãœãããé¢æ°ãå€æ°å«ãŸããŠããŸããResult
is the standard type to implement error handling as we will see on Day 4.
String
String
is a growable UTF-8 encoded string:
String
㯠Deref<Target = str>
ãå®è£
ããŸããã€ãŸããString
ã®ãã¹ãŠã® str
ã¡ãœãããåŒã³åºãããšãã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
String::new
ã¯æ°ãã空ã®æååãè¿ããŸããæååã«ããã·ã¥ããããŒã¿ã®éãããã£ãŠããå Žåã¯String::with_capacity
ã䜿çšããŸããString::len
ã¯ãString
ã®ãµã€ãºããã€ãåäœã§è¿ããŸãïŒæåæ°ãšã¯ç°ãªãå ŽåããããŸãïŒãString::chars
ã¯ãå®éã®æåã®ã€ãã¬ãŒã¿ãè¿ããŸããæžèšçŽ ã¯ã©ã¹ã¿ã«ãããchar
ã¯äººéããæåããšèŠãªããã®ãšã¯ç°ãªãå ŽåããããŸãã- 人ã
ãæååã«ã€ããŠèšåããå Žåãåã«
&str
ãŸãã¯String
ã®ããšã話ããŠããå¯èœæ§ããããŸãã - åã
Deref<Target = T>
ãå®è£ ããŠããå Žåãã³ã³ãã€ã©ã«ããT
ããã¡ãœãããééçã«åŒã³åºããããã«ãªããŸããDeref
ãã¬ã€ãã«ã€ããŠã¯ãŸã 説æããŠããªããããçŸæç¹ã§ã¯äž»ã«ããã¥ã¡ã³ãã®ãµã€ãããŒã®æ§é ã«ã€ããŠèª¬æããŠããŸããString
ã¯Deref<Target = str>
ãå®è£ ããstr
ã®ã¡ãœãããžã®ã¢ã¯ã»ã¹ãééçã«èš±å¯ããŸããlet s3 = s1.deref();
ãšlet s3 = &*s1;
ãèšè¿°ããŠæ¯èŒããŸãã
String
ã¯ãã€ãã®ãã¯ã¿ãŒã®ã©ãããŒãšããŠå®è£ ãããŸãããã¯ã¿ãŒã§ãµããŒããããŠãããªãã¬ãŒã·ã§ã³ã®å€ãã¯String
ã§ããµããŒããããŠããŸãããããã€ãã®ä¿èšŒãè¿œå ãããŠããŸããString
ã«ã€ã³ããã¯ã¹ãä»ããããŸããŸãªæ¹æ³ãæ¯èŒããŸãã- æåã«ã¯
s3.chars().nth(i).unwrap()
ã䜿çšããŸããããã§i
ã¯å¢çå ã®å Žåãå¢çå€ã®å Žåãè¡šããŸãã - éšåæååã«ã¯
s3[0..4]
ã䜿çšããŸãããã®ã¹ã©ã€ã¹ã¯ãæåå¢çã«ããå Žåãšãªãå ŽåããããŸãã
- æåã«ã¯
- Many types can be converted to a string with the
to_string
method. This trait is automatically implemented for all types that implementDisplay
, so anything that can be formatted can also be converted to a string.
Vec
Vec
ã¯ããµã€ãºå€æŽå¯èœãªæšæºã®ããŒãå²ãåœãŠãããã¡ã§ãã
Vec
㯠Deref<Target = [T]>
ãå®è£
ããŠãããããVec
ã§ã¹ã©ã€ã¹ ã¡ãœãããåŒã³åºãããšãã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
Vec
ã¯ãString
ããã³HashMap
ãšãšãã«ã³ã¬ã¯ã·ã§ã³ã®äžçš®ã§ããå«ãŸããŠããããŒã¿ã¯ããŒãã«æ ŒçŽããããããã³ã³ãã€ã«æã«ããŒã¿éãææ¡ããå¿ èŠã¯ãããŸãããããŒã¿éã¯å®è¡æã«å¢å ãŸãã¯æžå°ããå ŽåããããŸããVec<T>
ããžã§ããªãã¯åã§ãããT
ãæ瀺çã«æå®ããå¿ èŠã¯ãããŸãããRust ã®åæšè«ã§ãã€ãè¡ãããããã«ãæåã®push
åŒã³åºãã§T
ã確ç«ãããŠããŸããvec![...]
ã¯Vec::new()
ã®ä»£ããã«äœ¿çšããæ£èŠã®ãã¯ãã§ããã¯ã¿ãŒãžã®åæèŠçŽ ã®è¿œå ããµããŒãããŠããŸãã- ãã¯ã¿ãŒã«ã€ã³ããã¯ã¹ãä»ããã«ã¯
[
]
ã䜿çšããŸãããå¢çå€ã®å Žåã¯ãããã¯ãçºçããŸãããŸãã¯ãget
ã䜿çšãããšOption
ãè¿ãããŸããpop
é¢æ°ã¯æåŸã®èŠçŽ ãåé€ããŸãã - ã¹ã©ã€ã¹ã«ã€ããŠã¯ 3 æ¥ç®ã«èª¬æããŸããåè¬è
ã¯çŸæç¹ã§ã¯ãå
Vec
ã®å€ã«ãããããã¥ã¡ã³ãã«èšããããã¹ãŠã®ã¹ã©ã€ã¹ã¡ãœããã«ã¢ã¯ã»ã¹ã§ããããšã ããç¥ã£ãŠããã°ååã§ãã
HashMap
HashDoS æ»æããä¿è·ããæšæºã®ããã·ã¥ããã:
Speaker Notes
This slide should take about 5 minutes.
-
HashMap
ã¯ãã¬ãªã¥ãŒãã§å®çŸ©ãããŠããªããããã¹ã³ãŒãã«å«ããå¿ èŠããããŸãã -
次ã®ã³ãŒãè¡ãè©ŠããŸããæåã®è¡ã§ãæžç±ãããã·ã¥ãããã«ãããã©ããã確èªãããªãå Žåã¯ä»£æ¿å€ãè¿ããŸããæžç±ãèŠã€ãããªãã£ãå Žåã2 è¡ç®ã§ããã·ã¥ãããã«ä»£æ¿å€ãæ¿å ¥ããŸãã
let pc1 = page_counts .get("Harry Potter and the Sorcerer's Stone") .unwrap_or(&336); let pc2 = page_counts .entry("The Hunger Games") .or_insert(374);
-
vec!
ãšã¯ç°ãªããæšæºã®hashmap!
ãã¯ãã¯ãããŸããã-
ããããRust 1.56 以éã§ã¯ãHashMap ã¯
From<[(K, V); N]>
ãå®è£ ããŠããŸããããã«ããããªãã©ã«é åããããã·ã¥ããããç°¡åã«åæåã§ããŸããlet page_counts = HashMap::from([ ("Harry Potter and the Sorcerer's Stone".to_string(), 336), ("The Hunger Games".to_string(), 374), ]);
-
-
å¥ã®æ¹æ³ãšããŠãHashMap ã¯ãKey-Value ã¿ãã«ãçæããä»»æã®
Iterator
ããäœæããããšãã§ããŸãã -
ãã®åã«ã¯ã
std::collections::hash_map::Keys
ãªã©ã®ãã¡ãœããåºæã®ãæ»ãå€ã®åãããã€ããããŸãããããã®åã¯ãRust ããã¥ã¡ã³ãã®æ€çŽ¢ã§ãã䜿çšãããŸãããã®åã®ããã¥ã¡ã³ããšãkeys
ã¡ãœããã«æ»ãã®ã«åœ¹ç«ã€ãªã³ã¯ãåè¬è ã«ç€ºããŸãã
æŒç¿: ã«ãŠã³ã¿ãŒ
ãã®æŒç¿ã§ã¯ãéåžžã«ã·ã³ãã«ãªããŒã¿æ§é ãæ±çšçãªãã®ã«ããŸããstd::collections::HashMap
ã䜿çšããŠãã©ã®å€ã確èªãããåå€ãäœååºçŸãããã远跡ããŸãã
Counter
ã®åæããŒãžã§ã³ã¯ãu32
ã®å€ã§ã®ã¿æ©èœããããã«ããŒãã³ãŒããããŠããŸãã远跡ããå€ã®åã«å¯ŸããŠæ§é äœãšãã®ã¡ãœããããžã§ããªãã¯åããŸããããã«ãããCounter
ã§ããããåã®å€ã远跡ã§ããŸãã
æ©ãã«çµãã£ãå Žåã¯ãentry
ã¡ãœããã䜿çšããŠãcount
ã¡ãœããã®å®è£
ã«å¿
èŠãªããã·ã¥ ã«ãã¯ã¢ããã®åæ°ãååã«ããŠã¿ãŸãããã
解ç
æšæºã©ã€ãã©ãªå ã®ãã¬ã€ã
This segment should take about 1 hour and 10 minutes. It contains:
Slide | Duration |
---|---|
ä»ã®èšèªãšã®æ¯èŒ | 5 minutes |
æŒç®å | 5 minutes |
From ãš Into | 5 minutes |
ãã£ã¹ã | 5 minutes |
Read ãš Write | 5 minutes |
Defaultãæ§é äœæŽæ°èšæ³ | 5 minutes |
ã¯ããŒãžã£ | 10 minutes |
æŒç¿: ROT13æå· | 30 minutes |
Speaker Notes
æšæºã©ã€ãã©ãªåãšåæ§ã«ãæéããããŠåãã¬ã€ãã®ããã¥ã¡ã³ãã確èªããŸãã
ãã®ã»ã¯ã·ã§ã³ã¯é·ããããéäžã§äŒæ©ãåã£ãŠãã ããã
ä»ã®èšèªãšã®æ¯èŒ
ãããã®ãã¬ã€ãã¯å€ã®æ¯èŒããµããŒãããŸãããã¹ãŠã®ãã¬ã€ãã¯ããããã®ãã¬ã€ããå®è£ ãããã£ãŒã«ããå«ãåçšã«å°åºã§ããŸãã
PartialEq
ãš Eq
PartialEq
ã¯ãå¿
é ã®ã¡ãœãã eq
ãšæå®ãããã¡ãœãã ne
ãæã€éšåçãªç䟡é¢ä¿ã§ãã==
æŒç®åãš !=
æŒç®åã¯ããããã®ã¡ãœãããåŒã³åºããŸãã
Eq
ã¯å®å
šãªç䟡é¢ä¿ïŒåå°çã察称çãæšç§»çïŒã§ãããPartialEq
ãæå³ããŸããå®å
šãªç䟡é¢ä¿ãå¿
èŠãšããé¢æ°ã¯ããã¬ã€ãå¢çãšã㊠Eq
ã䜿çšããŸãã
PartialOrd
ãš Ord
PartialOrd
㯠partial_cmp
ã¡ãœããã䜿ã£ãŠéšåçãªé åºãå®çŸ©ããŸããããã¯ã<
ã<=
ã>=
ã>
æŒç®åãå®è£
ããããã«äœ¿çšãããŸãã
Ord
ã¯å
šé åºã瀺ããcmp
㯠Ordering
ãè¿ããŸãã
Speaker Notes
This slide should take about 5 minutes.
PartialEq
ã¯ç°ãªãåã®éã§å®è£
ã§ããŸãããEq
ã¯åå°çã§ãããããå®è£
ã§ããŸããã
å®éã«ã¯ããããã®ãã¬ã€ããå°åºããããšã¯äžè¬çã§ãããå®è£ ããã®ã¯äžè¬çã§ã¯ãããŸããã
æŒç®å
æŒç®åã®ãªãŒããŒããŒãã¯ãstd::ops
å
ã®ãã¬ã€ããä»ããŠå®è£
ãããŸãã
Speaker Notes
This slide should take about 5 minutes.
è°è«ã®ãã€ã³ã:
&Point
ã«Add
ãå®è£ ã§ããŸããããã¯ã©ã®ãããªç¶æ³ã§åœ¹ã«ç«ã¡ãŸããïŒ- åç:
Add:add
ã¯self
ã䜿çšããŸããæŒç®åããªãŒããŒããŒãããåT
ãCopy
ã§ãªãå Žåã¯ã&T
ã®æŒç®åããªãŒããŒããŒãããããšãæ€èšããå¿ èŠããããŸããããã«ãããåŒã³åºãç®æã§ã®äžèŠãªã¯ããŒã³äœæãåé¿ã§ããŸãã
- åç:
Output
ãé¢é£åã§ããã®ã¯ãªãã§ããïŒãããã¡ãœããã®åãã©ã¡ãŒã¿ã«ã§ããã§ããããïŒ- çãåç: é¢æ°åã®ãã©ã¡ãŒã¿ã¯åŒã³åºãå
ã«ãã£ãŠå¶åŸ¡ãããŸãããé¢é£åïŒ
Output
ãªã©ïŒã¯ãã¬ã€ãã®å®è£ è ã«ãã£ãŠå¶åŸ¡ãããŸãã
- çãåç: é¢æ°åã®ãã©ã¡ãŒã¿ã¯åŒã³åºãå
ã«ãã£ãŠå¶åŸ¡ãããŸãããé¢é£åïŒ
- 2 çš®é¡ã®åã«å¯ŸããŠ
Add
ãå®è£ ã§ããŸããããšãã°ãimpl Add<(i32, i32)> for Point
ã¯Point
ã«ã¿ãã«ãè¿œå ããŸãã
The Not
trait (!
operator) is notable because it does not âboolifyâ like the same operator in C-family languages; instead, for integer types it negates each bit of the number, which arithmetically is equivalent to subtracting it from -1: !5 == -6
.
From
ãš Into
Types implement From
and Into
to facilitate type conversions. Unlike as
, these traits correspond to lossless, infallible conversions.
From
ãå®è£
ããããšãInto
ãèªåçã«å®è£
ãããŸãã
Speaker Notes
This slide should take about 5 minutes.
- ãã®ããã«
Into
ãå®è£ ããããããåã«ã¯From
ã®ã¿ãå®è£ ããã®ãäžè¬çã§ãã - ã
String
ã«å€æã§ãããã¹ãŠãã®ãããªé¢æ°åŒæ°ã®å ¥ååã宣èšããå Žåããã®ã«ãŒã«ã¯éãšãªããInto
ã䜿çšããå¿ èŠããããŸããé¢æ°ã¯ãFrom
ãå®è£ ããåãšãInto
ã®ã¿ ãå®è£ ããåãåãå ¥ããŸãã
ãã£ã¹ã
Rust ã«ã¯ æé»ç ãªåå€æã¯ãããŸããããas
ã«ããæ瀺çãªãã£ã¹ãã¯ãµããŒããããŠããŸãããããã®ãã£ã¹ãã¯éåžžãããããå®çŸ©ãããŠãã C ã»ãã³ãã£ã¯ã¹ã«åŸããŸãã
as
ã®çµæ㯠Rust 㧠垞㫠å®çŸ©ããããã©ãããã©ãŒã éã§äžè²«ããŠããŸããããã¯ãæ£è² ã®ç¬Šå·ãå€ããããããå°ããªåã«ãã£ã¹ããããããéã«åŸãããçŽæã«åããŠãããããããŸãããããã¥ã¡ã³ãã確èªããæ確ã«ããããã«ã³ã¡ã³ããèšè¿°ããŠãã ããã
as
ã䜿çšãããã£ã¹ãã¯æ¯èŒçæ±ãã«ããã誀ã£ãŠäœ¿çšããããšãå°ãªããããŸããããŸããå°æ¥ã®ã¡ã³ããã³ã¹äœæ¥ã§ã䜿çšãããåãåã®å€ã®ç¯å²ãå€æŽãããéã«ããããã«ãããã°ãçºçããå¯èœæ§ããããŸãããã£ã¹ãã¯ãç¡æ¡ä»¶ã®åãæšãŠã瀺ãããšãç®çãšããŠããå Žåã«ã®ã¿ãæé©ã«äœ¿çšãããŸãïŒããšãã°ãäžäœãããã®å
容ã«é¢ä¿ãªããas u32
㧠u64
ã®äžäœ 32 ããããéžæããå ŽåïŒã
絶察ã«æ£ãããã£ã¹ãïŒäŸ: u32
ãã u64
ãžã®ãã£ã¹ãïŒã§ã¯ããã£ã¹ããå®éã«å®ç§ã§ããããšã確èªããããã«ãas
ã§ã¯ãªã From
ãŸã㯠Into
ã䜿çšããããšãããããããŸããæ£ãããªãå¯èœæ§ããããã£ã¹ãã«ã€ããŠã¯ã絶察ã«æ£ãããã£ã¹ããšã¯ç°ãªãæ¹æ³ã§ããããåŠçãããå Žåã«ãTryFrom
ãš TryInto
ã䜿çšã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
ãã®ã¹ã©ã€ãã®åŸã§äŒæ©ãåãããšãæ€èšããŠãã ããã
as
㯠C++ ã®éçãã£ã¹ãã«äŒŒãŠããŸããããŒã¿ã倱ãããå¯èœæ§ãããç¶æ³ã§ as
ã䜿çšããããšã¯ãäžè¬çã«æšå¥šãããŸããã䜿çšããå Žåã¯ãå°ãªããšã説æã®ã³ã¡ã³ããèšè¿°ããããšãããããããŸãã
ããã¯ãæŽæ°ãusize
ã«ãã£ã¹ãããŠã€ã³ããã¯ã¹ãšããŠäœ¿çšããå Žåã«äžè¬çã§ãã
Read
ãš Write
Read
ãš BufRead
ã䜿çšããããšã§ãu8
ãœãŒã¹ãæœè±¡åã§ããŸãã
åæ§ã«ãWrite
ã䜿çšãããšãu8
ã·ã³ã¯ãæœè±¡åã§ããŸãã
Default
ãã¬ã€ã
Default
ãã¬ã€ãã¯ãåã®ããã©ã«ãå€ãçæããŸãã
Speaker Notes
This slide should take about 5 minutes.
- çŽæ¥å®è£
ããããšãã
#[derive(Default)]
ã§å°åºããããšãã§ããŸãã - å°åºã«ããå®è£
ã§ã¯ããã¹ãŠã®ãã£ãŒã«ããããã©ã«ãå€ã«èšå®ãããå€ãçæãããŸãã
- ã€ãŸããæ§é äœå
ã®ãã¹ãŠã®åã«ã
Default
ãå®è£ ããå¿ èŠããããŸãã
- ã€ãŸããæ§é äœå
ã®ãã¹ãŠã®åã«ã
- æšæºã® Rust åã¯å€ãã®å Žåã劥åœãªå€ïŒ
0
ã""
ãªã©ïŒã®Default
ãå®è£ ããŸãã - éšåçãªæ§é äœã®åæåã¯ãããã©ã«ãã§é©åã«æ©èœããŸãã
- Rust æšæºã©ã€ãã©ãªã¯ãåã
Default
ãå®è£ ã§ããããšãèªèããŠãããããã䜿çšããã³ã³ãããšã³ã¹ ã¡ãœãããæäŸããŠããŸãã ..
æ§æã¯ãæ§é äœæŽæ°èšæ³ãšåŒã°ããŠããŸãã
ã¯ããŒãžã£
ã¯ããŒãžã£ãã©ã ãåŒã«ã¯ãååãä»ããããšãã§ããªãåããããŸãããã ãããããã¯ç¹å¥ãª Fn
ãFnMut
ãFnOnce
ãã¬ã€ããåããŠããŸãã
Speaker Notes
This slide should take about 10 minutes.
An Fn
(e.g. add_3
) neither consumes nor mutates captured values. It can be called needing only a shared reference to the closure, which means the closure can be executed repeatedly and even concurrently.
An FnMut
(e.g. accumulate
) might mutate captured values. The closure object is accessed via exclusive reference, so it can be called repeatedly but not concurrently.
If you have an FnOnce
(e.g. multiply_sum
), you may only call it once. Doing so consumes the closure and any values captured by move.
FnMut
㯠FnOnce
ã®ãµãã¿ã€ãã§ãFn
㯠FnMut
ãš FnOnce
ã®ãµãã¿ã€ãã§ããã€ãŸããFnOnce
ãåŒã³åºãããå Žåã¯åžžã« FnMut
ã䜿çšã§ããFnMut
ãŸã㯠FnOnce
ãåŒã³åºãããå Žåã¯åžžã« Fn
ã䜿çšã§ããŸãã
ã¯ããŒãžã£ãåãåãé¢æ°ãå®çŸ©ããå Žåãå¯èœã§ããã°ïŒ1 åã ãåŒã³åºãïŒFnOnce
ã䜿çšãã次㫠FnMut
ãæåŸã« Fn
ã䜿çšããããã«ããŸããããã«ãããåŒã³åºãå
ã«æãæè»ã«å¯Ÿå¿ã§ããŸãã
In contrast, when you have a closure, the most flexible you can have is Fn
(which can be passed to a consumer of any of the 3 closure traits), then FnMut
, and lastly FnOnce
.
The compiler also infers Copy
(e.g. for add_3
) and Clone
(e.g. multiply_sum
), depending on what the closure captures. Function pointers (references to fn
items) implement Copy
and Fn
.
By default, closures will capture each variable from an outer scope by the least demanding form of access they can (by shared reference if possible, then exclusive reference, then by move). The move
keyword forces capture by value.
æŒç¿: ROT13æå·
ãã®äŸã§ã¯ãå€å žç㪠ãROT13ãæå·ãå®è£ ããŸãããã®ã³ãŒãããã¬ã€ã°ã©ãŠã³ãã«ã³ããŒããæ¬ èœããŠããããããå®è£ ããŠãã ãããçµæãæå¹ãª UTF-8 ã®ãŸãŸã«ãªãããã«ãASCII ã¢ã«ãã¡ãããæåã®ã¿ãããŒããŒã·ã§ã³ããŸãã
use std::io::Read;
struct RotDecoder<R: Read> {
input: R,
rot: u8,
}
// `RotDecoder` ã® `Read` ãã¬ã€ããå®è£
ããŸãã
fn main() {
let mut rot =
RotDecoder { input: "Gb trg gb gur bgure fvqr!".as_bytes(), rot: 13 };
let mut result = String::new();
rot.read_to_string(&mut result).unwrap();
println!("{}", result);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn joke() {
let mut rot =
RotDecoder { input: "Gb trg gb gur bgure fvqr!".as_bytes(), rot: 13 };
let mut result = String::new();
rot.read_to_string(&mut result).unwrap();
assert_eq!(&result, "To get to the other side!");
}
#[test]
fn binary() {
let input: Vec<u8> = (0..=255u8).collect();
let mut rot = RotDecoder::<&[u8]> { input: input.as_ref(), rot: 13 };
let mut buf = [0u8; 256];
assert_eq!(rot.read(&mut buf).unwrap(), 256);
for i in 0..=255 {
if input[i] != buf[i] {
assert!(input[i].is_ascii_alphabetic());
assert!(buf[i].is_ascii_alphabetic());
}
}
}
}
ããããã 13 æåãã€ããŒããŒã·ã§ã³ããã 2 ã€ã® RotDecoder
ã€ã³ã¹ã¿ã³ã¹ãé£çµãããšã©ããªãã§ããããã
解ç
3 æ¥ç®ã®ãã¬ãŒãã³ã°ã«ãããã
æ¬æ¥ã®å 容:
- ã¡ã¢ãªç®¡çãã©ã€ãã¿ã€ã ãåçšãã§ãã«ãŒ: Rust ãã¡ã¢ãªã®å®å šæ§ã確ä¿ããä»çµã¿ã
- ã¹ããŒããã€ã³ã¿: æšæºã©ã€ãã©ãªã®ãã€ã³ã¿åã
ã¹ã±ãžã¥ãŒã«
Including 10 minute breaks, this session should take about 2 hours and 20 minutes. It contains:
Segment | Duration |
---|---|
ãããã | 3 minutes |
ã¡ã¢ãªç®¡ç | 1 hour |
ã¹ããŒããã€ã³ã¿ | 55 minutes |
ã¡ã¢ãªç®¡ç
This segment should take about 1 hour. It contains:
Slide | Duration |
---|---|
ããã°ã©ã ã¡ã¢ãªã®èŠçŽã | 5 minutes |
ã¡ã¢ãªç®¡çã®ã¢ãããŒã | 10 minutes |
æææš© | 5 minutes |
ã ãŒãã»ãã³ãã£ã¯ã¹ | 5 minutes |
Clone | 2 minutes |
Copy å | 5 minutes |
Drop | 10 minutes |
æŒç¿: ãã«ããŒå | 20 minutes |
ããã°ã©ã ã¡ã¢ãªã®èŠçŽã
ããã°ã©ã ã¯ã次㮠2 ã€ã®æ¹æ³ã§ã¡ã¢ãªãå²ãåœãŠãŸãã
-
ã¹ã¿ãã¯: ããŒã«ã«å€æ°çšã®é£ç¶ããã¡ã¢ãªé åã
- å€ã®ãµã€ãºã¯åºå®ãããŠãããã³ã³ãã€ã«æã«å€æããŠããŸãã
- éåžžã«é«é: ã¹ã¿ã㯠ãã€ã³ã¿ã移åããã ãã§ãã
- é¢æ°åŒã³åºãã«ãã£ãŠè¡ãããããã管çã容æã§ãã
- ã¡ã¢ãªå±ææ§ã«åªããŠããŸãã
-
ããŒã: é¢æ°åŒã³åºãã«äŸåããªãå€ã®ä¿æé åã
- å€ã®ãµã€ãºã¯åçã§ãå®è¡æã«æ±ºå®ãããŸãã
- ã¹ã¿ãã¯ããããäœéã§ãäœããã®ã®ããã¯ããŒãã³ã°ãå¿ èŠã§ãã
- ã¡ã¢ãªã®å±ææ§ãä¿èšŒãããŸããã
äŸ
String
ãäœæãããšãã¹ã¿ãã¯ã«ã¯åºå®ãµã€ãºã®ã¡ã¿ããŒã¿ãé
眮ãããããŒãã«ã¯ãµã€ãºãåçã«æ±ºå®ãããããŒã¿ïŒå®éã®æååïŒãé
眮ãããŸãã
Speaker Notes
This slide should take about 5 minutes.
-
String
ã¯Vec
ã«ããå®çŸãããŠããããã容éãšé·ãããããå¯å€ã§ããã°ããŒãäžã®åå²ãåœãŠã«ãã£ãŠæ¡åŒµã§ããããšã説æããŸãã -
åè¬è ããå°ããããå Žåã¯ãã·ã¹ãã ã¢ãã±ãŒã¿ã䜿çšããŠã¡ã¢ãªé åãããŒãããå²ãåœãŠãããããšãAllocator API ã䜿çšããŠã«ã¹ã¿ã ã¢ãã±ãŒã¿ãå®è£ ã§ããããšã説æããŠãã ããã
ãã®ä»
unsafe
Rust ã䜿çšããŠã¡ã¢ãª ã¬ã€ã¢ãŠãã調ã¹ãããšãåºæ¥ãŸãããã ããããã¯åœç¶ãªããå®å
šã§ãªãããšãææããå¿
èŠããããŸãã
ã¡ã¢ãªç®¡çã®ã¢ãããŒã
äŒçµ±çã«ãèšèªã¯å€§ãã 2 ã€ã®ã«ããŽãªã«åé¡ãããŸãã
- æåã§ã®ã¡ã¢ãªç®¡çã«ããå®å
šãªå¶åŸ¡: CãC++ãPascal ãªã©
- ããã°ã©ããŒãããŒãã¡ã¢ãªãå²ãåœãŠãŸãã¯è§£æŸããã¿ã€ãã³ã°ã決å®ããŸãã
- ããã°ã©ããŒã¯ããã€ã³ã¿ããŸã æå¹ãªã¡ã¢ãªãæããŠãããã©ãããå€æããå¿ èŠããããŸãã
- 調æ»ã«ãããšãããã°ã©ããŒã¯å€æã誀ãããšããããŸãã
- å®è¡æã®èªåã¡ã¢ãªç®¡çã«ããå®å
šãªå®å
šæ§: JavaãPythonãGoãHaskell ãªã©
- ã©ã³ã¿ã€ã ã·ã¹ãã ã«ãããã¡ã¢ãªã¯åç §ã§ããªããªããŸã§è§£æŸãããŸããã
- Typically implemented with reference counting or garbage collection.
Rust ã§ã¯ãã® 2 ã€ãèåããããšã§ãæ°ãã«ä»¥äžã®ç¹åŸŽãæäŸããŸãã
ã³ã³ãã€ã«æã®é©åãªã¡ã¢ãªç®¡çã®é©çšã«ãããå®å šãªå¶åŸ¡ãšå®å šæ§ã
ããã¯ãæ瀺çãªæææš©ã®æŠå¿µã«ãã£ãŠå®çŸãããŸãã
Speaker Notes
This slide should take about 10 minutes.
ãã®ã¹ã©ã€ãã¯ãä»ã®èšèªãç¿åŸæžã¿ã®åè¬è ã«ããã®æèã®äžã§ Rust ãç解ããŠãããããšãç®çãšããŠããŸãã
-
C ã§ã¯ã
malloc
ãšfree
ã䜿çšããŠããŒããæåã§ç®¡çããå¿ èŠããããŸãããããããšã©ãŒãšããŠã¯ãfree
ã®åŒã³åºããå¿ãããåããã€ã³ã¿ã«å¯ŸããŠè€æ°ååŒã³åºãããã€ã³ãããŠããã¡ã¢ãªã解æŸãããåŸã«ãã€ã³ã¿ãéåç §ããããªã©ããããŸãã -
C++ ã«ã¯ã¹ããŒã ãã€ã³ã¿ïŒ
unique_ptr
ãshared_ptr
ãªã©ïŒã®ããŒã«ãããããã¹ãã©ã¯ã¿ã®åŒã³åºãã«é¢ããèšèªä¿èšŒãå©çšããŠãé¢æ°ãæ»ã£ããšãã«ã¡ã¢ãªã解æŸãããããã«ããŸãããããã®ããŒã«ã誀çšã㊠C ãšåæ§ã®ãã°ãäœæããããšããããããŸãã -
JavaãGoãPythonã§ã¯ãã¢ã¯ã»ã¹ã§ããªããªã£ãã¡ã¢ãªã®ç¹å®ãšç Žæ£ãã¬ãŒããžã³ã¬ã¯ã¿ã«äŸåããŸããããã«ããããããããã€ã³ã¿ã®éåç §ãå¯èœã«ãªãã解æŸåŸã®äœ¿çšãªã©ã®ãã°ããªããªããŸãããã ããGC (ã¬ãŒããžã³ã¬ã¯ã·ã§ã³) ã«ã¯ã©ã³ã¿ã€ã ã³ã¹ããããããé©åãªãã¥ãŒãã³ã°ãå°é£ã§ãã
Rust ã®æææš©ãšåçšã¢ãã«ã¯ãå€ãã®å Žåãå²ãåœãŠãªãã¬ãŒã·ã§ã³ãšè§£æŸãªãã¬ãŒã·ã§ã³ãæ£ç¢ºã«å¿ èŠãªå Žæã§è¡ãããšã«ããããŒãã³ã¹ã㧠C ã®ããã©ãŒãã³ã¹ãå®çŸã§ããŸãããŸããC++ ã®ã¹ããŒããã€ã³ã¿ã«äŒŒãããŒã«ãçšæãããŠããŸããå¿ èŠã«å¿ããŠãåç §ã«ãŠã³ããªã©ã®ä»ã®ãªãã·ã§ã³ãå©çšã§ããŸãããŸããã©ã³ã¿ã€ã ã¬ããŒãžã³ã¬ã¯ã·ã§ã³ããµããŒãããããã®ãµãŒãããŒãã£ã®ã¯ã¬ãŒãã䜿çšã§ããŸãïŒãã®ã¯ã©ã¹ã§ã¯æ±ããŸããïŒã
æææš©
ãã¹ãŠã®å€æ°ãã€ã³ãã£ã³ã°ã«ã¯æå¹ãªã¹ã³ãŒãããããã¹ã³ãŒãå€ã§å€æ°ã䜿çšãããšãšã©ãŒã«ãªããŸãã
ããããå€æ°ãå€ã ææ ããŠãããšè¡šçŸããŸãããã¹ãŠã® Rustã®å€ææè ã¯åžžã« 1 人ã§ãã
ã¹ã³ãŒãããå€ãããšå€æ°ãç Žæ£ (drop) ãããããŒã¿ã解æŸãããŸããããã§ãã¹ãã©ã¯ã¿ãå®è¡ããŠãªãœãŒã¹ã解æŸã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
ã¬ããŒãž ã³ã¬ã¯ã·ã§ã³ã®å®è£ ã«ç²ŸéããŠããåè¬è ã¯ãã¬ããŒãž ã³ã¬ã¯ã¿ãäžé£ã®ãã«ãŒããããéå§ããŠå°éå¯èœãªãã¹ãŠã®ã¡ã¢ãªãèŠã€ããããšãç¥ã£ãŠããŸããRust ã®ãåäžãªãŒããŒãã®ååããåæ§ã®èãæ¹ã«åºã¥ããŠããŸãã
ã ãŒãã»ãã³ãã£ã¯ã¹
ä»£å ¥ãããšãå€æ°é㧠æææš© ã移åããŸãã
s1
ãs2
ã«ä»£å ¥ãããšãæææš©ã移åããŸããs1
ãã¹ã³ãŒãå€ã«ãªããšãäœãææããŠãªãããã§ãïŒäœãææããŸããïŒãs2
ãã¹ã³ãŒãå€ã«ãªããšãæååããŒã¿ã¯è§£æŸãããŸãã
s2
ã«ç§»åããå:
s2
ã«ç§»åããåŸ:
次ã®äŸã®ããã«ãé¢æ°ã«å€ãæž¡ããšããã®å€ã¯é¢æ°ãã©ã¡ãŒã¿ã«ä»£å ¥ãããŸããããã«ãããæææš©ã移åããŸãã
Speaker Notes
This slide should take about 5 minutes.
-
ããã¯ã
std::move
ã䜿çšããªãéãïŒãã€ã ãŒã ã³ã³ã¹ãã©ã¯ã¿ãå®çŸ©ãããŠããªãéãïŒå€ãã³ããŒãããC++ ã®ããã©ã«ããšã¯éã§ããããšã説æããŸãã -
移åããã®ã¯æææš©ã®ã¿ã§ããããŒã¿èªäœãæäœããããã«ãã·ã³ã³ãŒããçæããããã©ããã¯æé©åã®åé¡ã§ããããã®ãããªã³ããŒã®ããã®ãã·ã³ã³ãŒãã¯ç©æ¥µçã«æé©åãããŠãªããªããŸãã
-
åçŽãªå€ïŒæŽæ°ãªã©ïŒã«ã¯
Copy
ã®ããŒã¯ãä»ããããšãã§ããŸãïŒåŸã®ã¹ã©ã€ããåç §ïŒã -
Rust ã§ã¯ãã¯ããŒã³ã¯æ瀺çã«
clone
ã䜿çšããŠè¡ãããŸãã
say_hello
ã®äŸã®å
容ã¯æ¬¡ã®ãšããã§ãã
say_hello
ã®æåã®åŒã³åºãã§ãmain
ã¯name
ã®æææš©ãæŸæ£ããŸãããã®åŸã¯main
å ã§name
ã䜿çšã§ããªããªããŸããname
ã«å²ãåœãŠãããããŒãã¡ã¢ãªã¯ãsay_hello
é¢æ°ã®æåŸã§è§£æŸãããŸããmain
ãname
ãåç §ãšããŠæž¡ãïŒ&name
ïŒãsay_hello
ããã©ã¡ãŒã¿ãšããŠåç §ãåãå ¥ããå Žåãmain
ã¯æææš©ãä¿æã§ããŸãã- ãŸãã¯ã
main
ãæåã®åŒã³åºãã§name
ã®ã¯ããŒã³ïŒname.clone()
ïŒãæž¡ãããšãã§ããŸãã - Rust ã§ã¯ãã ãŒã ã»ãã³ãã£ã¯ã¹ãããã©ã«ãã«ããã¯ããŒã³ãããã°ã©ãã«æ瀺çã«è¡ãããŠããŸããããã«ãããC++ ã«æ¯ã¹ãŠæå³ããã³ããŒãäœæãããªã¹ã¯ãäœæžãããŠããŸãã
ãã®ä»
Defensive Copies in Modern C++
ææ°ã® C++ ã§ã¯ããã®åé¡ãå¥ã®æ¹æ³ã§è§£æ±ºããŸãã
std::string s1 = "Cpp";
std::string s2 = s1; // s1 ã«ããŒã¿ãè€è£œããŸãã
s1
ããã®ããŒãããŒã¿ãè€è£œãããs2
ã¯èªèº«ã®ç¬ç«ããã³ããŒãååŸããŸããs1
ãšs2
ãã¹ã³ãŒãå€ã«ãªããšãããããèªèº«ã®ã¡ã¢ãªã解æŸããŸãã
ã³ããŒä»£å ¥å:
ã³ããŒä»£å ¥åŸ:
èŠç¹ïŒ
-
C++ ã®ã¢ãããŒãã¯ãRust ãšã¯è¥å¹²ç°ãªããŸãã
=
ã䜿çšãããšããŒã¿ãã³ããŒããããããæååããŒã¿ã®ã¯ããŒã³ãäœæããå¿ èŠãããããã§ããããããªããšãããããã®æååãã¹ã³ãŒãå€ã«ãªã£ããšãã«äºé解æŸãçºçããŸãã -
C++ ã«ã¯
std::move
ããããŸãããããã¯å€ãã ãŒãã§ããã¿ã€ãã³ã°ã瀺ãããã«äœ¿çšãããŸãããã®äŸã§s2 = std::move(s1)
ãšãªã£ãŠããå Žåã¯ãããŒãå²ãåœãŠã¯è¡ãããŸãããã ãŒãåŸãs1
ã¯æå¹ã§ãããã®ã®ãæªæå®ã®ç¶æ ã«ãªããŸããRust ãšã¯ç°ãªããããã°ã©ããŒã¯s1
ãåŒãç¶ã䜿çšã§ããŸãã -
Rust ãšã¯ç°ãªããC++ ã®
=
ã¯ãã³ããŒãŸãã¯ç§»åãããåã«ãã£ãŠæ±ºå®ãããä»»æã®ã³ãŒããå®è¡ã§ããŸãã
Clone
å€ã®ã³ããŒãäœæãããå Žåã¯ãClone
ãã¬ã€ãã䜿çšã§ããŸãã
Speaker Notes
This slide should take about 2 minutes.
-
The idea of
Clone
is to make it easy to spot where heap allocations are occurring. Look for.clone()
and a few others likevec!
orBox::new
. -
åçšãã§ãã«ãŒãéããªãå Žåã«ããšããããã¯ããŒã³ãäœæããŠåãæããŠãããŠããããšããã¯ããŒã³ã®ãªãã³ãŒããžã®æé©åãè©Šã¿ãã®ãããããããšã§ãã
-
clone
generally performs a deep copy of the value, meaning that if you e.g. clone an array, all of the elements of the array are cloned as well. -
The behavior for
clone
is user-defined, so it can perform custom cloning logic if needed.
Copy å
èšèªãšããŠã®ããã©ã«ãã¯ã ãŒãã»ãã³ãã£ã¯ã¹ã§ãããç¹å®ã®åã§ã¯ããã©ã«ãã§ã³ããŒãè¡ãããŸãã
ãããã®å㯠Copy
ãã¬ã€ããå®è£
ããŠããããã§ãã
ããªããå®çŸ©ããç¬èªã®åã®ããã©ã«ããã³ããŒã»ãã³ãã£ã¯ã¹ã«ããããšãåºæ¥ãŸãã
- 代å
¥åŸã¯ã
p1
ãšp2
ã®äž¡æ¹ãç¬èªã®ããŒã¿ãææããŸãã p1.clone()
ã䜿çšããŠããŒã¿ãæ瀺çã«ã³ããŒããããšãã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
ã³ããŒãšã¯ããŒã³äœæã¯åãã§ã¯ãããŸããã
- ã³ããŒãšã¯ãã¡ã¢ãªé åã®ãããåäœã³ããŒã®ããšã§ãããä»»æã®ãªããžã§ã¯ãã§ã¯æ©èœããŸããã
- ã³ããŒã§ã¯ã«ã¹ã¿ã ããžãã¯ã¯äœ¿çšã§ããŸããïŒC++ ã®ã³ããŒã³ã³ã¹ãã©ã¯ã¿ãšã¯ç°ãªããŸãïŒã
- ã¯ããŒã³äœæã¯ããäžè¬çãªãªãã¬ãŒã·ã§ã³ã§ããã
Clone
ãã¬ã€ããå®è£ ããããšã§ã«ã¹ã¿ã åäœãå¯èœã«ãªããŸãã Drop
ãã¬ã€ããå®è£ ããŠããåã§ã¯ãã³ããŒã¯åºæ¥ãŸããã
äžèšã®äŸã§ã次ã®æ¹æ³ãè©ŠããŠãã ããã
String
ãã£ãŒã«ããstruct Point
ã«è¿œå ããŸããString
ãCopy
åã§ã¯ãªããããã³ã³ãã€ã«ã§ããªããªããŸããderive
å±æ§ããCopy
ãåé€ããŸããp1
ã®println!
ã§ã³ã³ãã€ã© ãšã©ãŒãçºçããŸãã- 代ããã«
p1
ã®ã¯ããŒã³ãäœæããã°è§£æ±ºã§ããããšã瀺ããŸãã
ãã®ä»
- Shared references are
Copy
/Clone
, mutable references are not. This is because Rust requires that mutable references be exclusive, so while itâs valid to make a copy of a shared reference, creating a copy of a mutable reference would violate Rustâs borrowing rules.
Drop
ãã¬ã€ã
Drop
ãå®è£
ããŠããå€ã§ã¯ãã¹ã³ãŒãããå€ãããšãã«å®è¡ããã³ãŒããæå®ã§ããŸãã
Speaker Notes
This slide should take about 8 minutes.
std::mem::drop
ã¯std::ops::Drop::drop
ãšåãã§ã¯ãããŸããã- ã¹ã³ãŒãå€ã«ãªããšãå€ã¯èªåçã«ãããããããŸãã
- å€ããããããããéã
std::ops::Drop
ãå®è£ ããŠããå Žåã¯ããã®Drop::drop
å®è£ ãåŒã³åºãããŸãã - ãã®åŸã
Drop
ãå®è£ ããŠãããã©ããã«ãããããããã¹ãŠã®ãã£ãŒã«ãããããããããŸãã std::mem::drop
ã¯ãä»»æã®å€ãåãåã空ã®é¢æ°ã«ãããŸãããéèŠãªã®ã¯ããã®é¢æ°ãå€ã®æææš©ãååŸããããšã§ãã¹ã³ãŒãã®æåŸã§å€ããããããããããšã§ããããã¯ãã¹ã³ãŒãå€ã«ãªãåã«å€ãæ瀺çã«ããããããããã®äŸ¿å©ãªæ¹æ³ã§ãã- ãã®æ¹æ³ã¯ã
drop
ã§äœããã®åŠçïŒããã¯ã®è§£æŸããã¡ã€ã«ã®ã¯ããŒãºãªã©ïŒãè¡ããªããžã§ã¯ãã«äœ¿çšãããšäŸ¿å©ã§ãã
- ãã®æ¹æ³ã¯ã
è°è«ã®ãã€ã³ã:
Drop::drop
ãself
ããã©ã¡ãŒã¿ãšããŠåããªãã®ã¯ãªãã§ããïŒ- çãåç: ãã®å Žåããããã¯ã®æåŸã«
std::mem::drop
ãåŒã³åºããããããå¥ã®Drop::drop
ãåŒã³åºãããã¹ã¿ã㯠ãªãŒããŒãããŒãçºçããŸãã
- çãåç: ãã®å Žåããããã¯ã®æåŸã«
drop(a)
ãa.drop()
ã«çœ®ãæããŠã¿ãŠãã ããã
æŒç¿: ãã«ããŒå
ãã®äŸã§ã¯ããã¹ãŠã®ããŒã¿ãæã€è€éãªããŒã¿åãå®è£ ããŸããããã«ã㌠ãã¿ãŒã³ãã§äŸ¿å©ãªé¢æ°ã䜿çšããŠãæ°ããå€ã 1 ã€ãã€æ§ç¯ã§ããããã«ããŸãã
æããŠããéšåãèšå ¥ããŠãã ããã
解ç
ã¹ããŒããã€ã³ã¿
This segment should take about 55 minutes. It contains:
Slide | Duration |
---|---|
Box | 10 minutes |
Rc | 5 minutes |
ææããããã¬ã€ããªããžã§ã¯ã | 10 minutes |
æŒç¿: ãã€ããªããªãŒ | 30 minutes |
Box<T>
Box
ã¯ãããŒãäžã®ããŒã¿ãžã®ææãã€ã³ã¿ã§ãã
Box<T>
㯠Deref<Target = T>
ãå®è£
ããŠãããããBox<T>
ã«å¯Ÿã㊠T ã®ã¡ãœãããçŽæ¥åŒã³åºãããšãã§ããŸãã
Recursive data types or data types with dynamic sizes cannot be stored inline without a pointer indirection. Box
accomplishes that indirection:
Speaker Notes
This slide should take about 8 minutes.
-
Box
㯠C++ ã®std::unique_ptr
ãšäŒŒãŠããŸãããnull ã§ã¯ãªãããšãä¿èšŒãããŠããç¹ãç°ãªããŸãã -
Box
ã¯æ¬¡ã®ãããªå Žåã«åœ¹ç«ã¡ãŸãã- have a type whose size canât be known at compile time, but the Rust compiler wants to know an exact size.
- 倧éã®ããŒã¿ã®æææš©ãã ãŒããããå Žåãã¹ã¿ãã¯äžã®å€§éã®ããŒã¿ãã³ããŒãããªãããã«ããã«ã¯ã代ããã«
Box
ã«ããããŒãäžã«ããŒã¿ãæ ŒçŽãããã€ã³ã¿ã®ã¿ã移åãããããã«ããŸãã
-
ä»®ã«
Box
ã䜿çšããã«List
ãList
ã«çŽæ¥åã蟌ãããšãããšãã³ã³ãã€ã©ã¯ã¡ã¢ãªå ã®æ§é äœã®åºå®ãµã€ãºãèšç®ããããšããŸããïŒList
ã¯ç¡éãµã€ãºã«ãªããŸãïŒã -
Box
ããã®åé¡ã解決ã§ããã®ã¯ããã®ãµã€ãºãéåžžã®ãã€ã³ã¿ãšåãã§ãããåã«ããŒãå ã® List ã®æ¬¡ã®èŠçŽ ãæãã ãã ãã ããã§ãã -
Remove the
Box
in the List definition and show the compiler error. We get the message ârecursive without indirectionâ, because for data recursion, we have to use indirection, aBox
or reference of some kind, instead of storing the value directly. -
Though
Box
looks likestd::unique_ptr
in C++, it cannot be empty/null. This makesBox
one of the types that allow the compiler to optimize storage of some enums (the âniche optimizationâ).
Rc
Rc
ã¯ãåç
§ã«ãŠã³ããããå
±æãã€ã³ã¿ã§ããè€æ°ã®å ŽæããåãããŒã¿ãåç
§ããå¿
èŠãããå Žåã«äœ¿çšããŸãã
- See
Arc
andMutex
if you are in a multi-threaded context. - å
±æãã€ã³ã¿ã
Weak
ãã€ã³ã¿ã«ããŠã³ã°ã¬ãŒã (downgrade) ãããšãããããããããµã€ã¯ã«ãäœæã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
Rc
ã®ã«ãŠã³ãã¯ãåç §ãããéãæå¹ã§ããããšãä¿èšŒããŸãã- Rust ã®
Rc
㯠C++ ã®std::shared_ptr
ã«äŒŒãŠããŸãã Rc::clone
ã®åäœã¯è»œéã§ããåãå²ãåœãŠé åãžã®ãã€ã³ã¿ãäœæããåç §ã«ãŠã³ããå¢ããã ãã§ããããŒãã¯ããŒã³ãäœæããªãã®ã§ãæ§èœäžã®åé¡ç®æãã³ãŒãããæ¢ãå Žåã«ã¯éåžžç¡èŠããããšãåºæ¥ãŸããmake_mut
ã¯ãå¿ èŠã«å¿ããŠå éšã®å€ã®ã¯ããŒã³ãäœæãïŒãclone-on-writeãïŒãå¯å€åç §ãè¿ããŸããRc::strong_count
ã䜿çšããŠåç §ã«ãŠã³ãã確èªããŸããRc::downgrade
ã¯ãïŒå€ãã®å ŽåãRefCell
ãšçµã¿åãããŠïŒé©åã«ããããããããµã€ã¯ã«ãäœæããããã®åŒ±åç §ã«ãŠã³ã (weakly reference-counted) ãªããžã§ã¯ããæäŸããŸãã
ææããããã¬ã€ããªããžã§ã¯ã
We previously saw how trait objects can be used with references, e.g &dyn Pet
. However, we can also use trait objects with smart pointers like Box
to create an owned trait object: Box<dyn Pet>
.
pets
ãå²ãåœãŠãåŸã®ã¡ã¢ãªã¬ã€ã¢ãŠãïŒ
Speaker Notes
This slide should take about 10 minutes.
- åããã¬ã€ããå®è£
ããåã§ãã£ãŠããã®ãµã€ãºã¯ç°ãªãããšããããŸãããã®ãããäžã®äŸã§Vec
ãšæžãããšã¯ã§ããŸããã dyn Pet
ã¯ã³ã³ãã€ã©ã«ããã®åãPet
ãã¬ã€ããå®è£ ããåçãªãµã€ãºã®åã§ããããšãäŒããŸãã- äžã®äŸã§ã¯
pets
ã¯ã¹ã¿ãã¯ã«ç¢ºä¿ããããã¯ã¿ãŒã®ããŒã¿ã¯ããŒãäžã«ãããŸããäºã€ã®ãã¯ã¿ãŒã®èŠçŽ 㯠ãã¡ãããã€ã³ã¿ ã§ãïŒ- ãã¡ãããã€ã³ã¿ã¯double-widthãã€ã³ã¿ã§ããããã¯äºã€ã®èŠçŽ ãããªããŸãïŒå®éã®ãªããžã§ã¯ããžã®ãã€ã³ã¿ãšããã®ãªããžã§ã¯ãã®
Pet
ã®å®è£ ã®ããã®ä»®æ³é¢æ°ããŒãã« (vtable)ã§ãã - âFidoâãšåä»ãããã
Dog
ã®ããŒã¿ã¯name
ãšage
ã®ãã£ãŒã«ãã«å¯Ÿå¿ããŸããïŒèš³æ³š: âFidoâãšã¯ããããç¬ã®æ称ã§ãæ¥æ¬èªã§ããããããã®ãããªååã§ããïŒäŸã®Cat
ã«ã¯lives
ãã£ãŒã«ãããããŸããïŒèš³æ³š: ããã§Cat
ãlives
ãšãããã£ãŒã«ããæã¡ã9ã§åæåããŠããã®ã¯âA cat has nine livesâ âç«ã¯ïŒã€ã®åœãæã€âãšããããšããã«ç±æ¥ããŸããïŒ
- ãã¡ãããã€ã³ã¿ã¯double-widthãã€ã³ã¿ã§ããããã¯äºã€ã®èŠçŽ ãããªããŸãïŒå®éã®ãªããžã§ã¯ããžã®ãã€ã³ã¿ãšããã®ãªããžã§ã¯ãã®
- äžã®äŸã«ãããŠãäžã®ã³ãŒãã«ããåºåçµæãæ¯ã¹ãŠã¿ãŸãããïŒ
println!("{} {}", std::mem::size_of::<Dog>(), std::mem::size_of::<Cat>()); println!("{} {}", std::mem::size_of::<&Dog>(), std::mem::size_of::<&Cat>()); println!("{}", std::mem::size_of::<&dyn Pet>()); println!("{}", std::mem::size_of::<Box<dyn Pet>>());
æŒç¿: ãã€ããªããªãŒ
ãã€ããªããªãŒã¯ããã¹ãŠã®ããŒãã« 2 ã€ã®åïŒå·Šãšå³ïŒãããããªãŒåã®ããŒã¿æ§é ã§ããããã§ã¯ãåããŒããå€ãæ ŒçŽããããªãŒãäœæããŸããããç¹å®ã®ããŒã N ã«ã€ããŠãN ã®å·ŠåŽã®ãµãããªãŒå ã®ãã¹ãŠã®ããŒãã«ã¯ããå°ããå€ãå«ãŸããN ã®å³åŽã®ãµãããªãŒå ã®ãã¹ãŠã®ããŒãã«ã¯ãã倧ããå€ãå«ãŸããŸãã
次ã®åãå®è£ ããŠãæå®ããããã¹ããéãããã«ããŸãã
è¿œå ã®å®ç¿: ãã€ããªããªãŒã«å€ãé çªã«è¿ãã€ãã¬ãŒã¿ãå®è£ ããŸãã
解ç
ãããã
Including 10 minute breaks, this session should take about 1 hour and 55 minutes. It contains:
Segment | Duration |
---|---|
åçš | 55 minutes |
ã©ã€ãã¿ã€ã | 50 minutes |
åçš
This segment should take about 55 minutes. It contains:
Slide | Duration |
---|---|
å€ã®åçš | 10 minutes |
åçšãã§ã㯠| 10 minutes |
Borrow Errors | 3 minutes |
å éšå¯å€æ§ | 10 minutes |
æŒç¿: å¥åº·ã«é¢ããçµ±èš | 20 minutes |
å€ã®åçš
åã«èª¬æããããã«ãé¢æ°ãåŒã³åºããšãã«æææš©ã移åãã代ããã«ãé¢æ°ã§å€ãåçšã§ããŸãã
add
é¢æ°ã¯ 2 ã€ã®ãã€ã³ãã åçš ããæ°ãããã€ã³ããè¿ããŸãã- åŒã³åºãå ã¯å ¥åã®æææš©ãä¿æããŸãã
Speaker Notes
This slide should take about 10 minutes.
ãã®ã¹ã©ã€ãã§ã¯ã1 æ¥ç®ã®åç §ã«é¢ããè³æãæ¯ãè¿ãã§ãããå°ã察象ãåºããé¢æ°ã®åŒæ°ãšæ»ãå€ãå«ããŠããŸãã
ãã®ä»
Notes on stack returns and inlining:
-
Demonstrate that the return from
add
is cheap because the compiler can eliminate the copy operation, by inlining the call to add into main. Change the above code to print stack addresses and run it on the Playground or look at the assembly in Godbolt. In the âDEBUGâ optimization level, the addresses should change, while they stay the same when changing to the âRELEASEâ setting: -
The Rust compiler can do automatic inlining, that can be disabled on a function level with
#[inline(never)]
. -
Once disabled, the printed address will change on all optimization levels. Looking at Godbolt or Playground, one can see that in this case, the return of the value depends on the ABI, e.g. on amd64 the two i32 that is making up the point will be returned in 2 registers (eax and edx).
åçšãã§ãã¯
Rust ã® åçšãã§ãã«ãŒ ã¯ãå€ãåçšããæ¹æ³ã«å¶éãèšããŸããä»»æã®å€ã«å¯ŸããŠãåžžã«æ¬¡ã®å¶éã課ãããŸãã
- å€ãžã®å ±æåç §ã 1 ã€ä»¥äžæã€ããšãåºæ¥ãŸãããŸãã¯ã
- å€ãžã®æä»åç §ã 1 ã€ã ãæã€ããšãåºæ¥ãŸãã
Speaker Notes
This slide should take about 10 minutes.
- èŠä»¶ã¯ã競åããåç §ãåãæç¹ã«ååšããªãããšã§ããåç §ãã©ãã§å€ãããŠããŠãæ§ããŸããã
- äžèšã®ã³ãŒãã¯ã
a
ãc
ãéããŠå¯å€ãšããŠåçšãããŠãããšåæã«ãb
ãéããŠäžå€ãšããŠåçšãããŠãããããã³ã³ãã€ã«ã§ããŸããã b
ã®println!
ã¹ããŒãã¡ã³ããc
ãå°å ¥ããã¹ã³ãŒãã®åã«ç§»åããŠãã³ãŒããã³ã³ãã€ã«åºæ¥ãããã«ããŸãã- ãã®å€æŽåŸãã³ã³ãã€ã©ã¯ c ãéããa ã®å¯å€åç §ãããåã«ããbã䜿ãããŠããªãããšãèªèããŸããããã¯ããã³ã¬ãã·ã«ã« ã©ã€ãã¿ã€ã (ânon-lexical lifetimesâ)ããšåŒã°ããåçšãã§ãã«ãŒã®æ©èœã§ãã
- æä»åç §å¶çŽã¯éåžžã«åŒ·åã§ããRust ã¯ãã®å¶çŽã䜿çšããŠãããŒã¿ãžã®ç«¶åãçºçããªãããã«ãããšãšãã«ãã³ãŒããæé©åããŠããŸããããšãã°ãå ±æåç §ãéããŠåŸãããå€ã¯ããã®åç §ãåç¶ããéãå®å šã«ã¬ãžã¹ã¿ã«ãã£ãã·ã¥ããããšãåºæ¥ãŸã
- åçšãã§ãã«ãŒã¯ãæ§é äœå ã®ç°ãªããã£ãŒã«ããžã®æä»åç §ãåæã«ååŸãããªã©ãå€ãã®äžè¬çãªãã¿ãŒã³ã«å¯Ÿå¿ããããã«èšèšãããŠããŸããããããç¶æ³ã«ãã£ãŠã¯åçšãã§ãã«ãŒãã³ãŒããæ£ããç解ã§ããããåçšãã§ãã«ãŒãšã®æŠããã«çºå±ããããšãå€ããããŸãã
Borrow Errors
As a concrete example of how these borrowing rules prevent memory errors, consider the case of modifying a collection while there are references to its elements:
Similarly, consider the case of iterator invalidation:
Speaker Notes
This slide should take about 3 minutes.
- In both of these cases, modifying the collection by pushing new elements into it can potentially invalidate existing references to the collectionâs elements if the collection has to reallocate.
å éšå¯å€æ§
å Žåã«ãã£ãŠã¯ãå ±æïŒèªã¿åãå°çšïŒåç §ã®èåŸã«ããããŒã¿ãå€æŽããå¿ èŠããããŸããããšãã°ãå ±æããŒã¿æ§é ã«å éšãã£ãã·ã¥ãããããã®ãã£ãã·ã¥ãèªã¿åãå°çšã¡ãœããããæŽæ°ããå¿ èŠãããå ŽåããããŸãã
ãå éšå¯å€æ§ããã¿ãŒã³ã¯ãå ±æåç §ãéããæä»çïŒå¯å€ïŒã¢ã¯ã»ã¹ãå¯èœã«ããŸããæšæºã©ã€ãã©ãªã«ã¯ããããå®å šã«è¡ãããã®æ¹æ³ãããã€ãçšæãããŠãããéåžžã¯ã©ã³ã¿ã€ã ãã§ãã¯ãå®è¡ããããšã§å®å šæ§ã確ä¿ããŸãã
Cell
Cell
wraps a value and allows getting or setting the value using only a shared reference to the Cell
. However, it does not allow any references to the inner value. Since there are no references, borrowing rules cannot be broken.
RefCell
RefCell
allows accessing and mutating a wrapped value by providing alternative types Ref
and RefMut
that emulate &T
/&mut T
without actually being Rust references.
These types perform dynamic checks using a counter in the RefCell
to prevent existence of a RefMut
alongside another Ref
/RefMut
.
By implementing Deref
(and DerefMut
for RefMut
), these types allow calling methods on the inner value without allowing references to escape.
Speaker Notes
This slide should take about 10 minutes.
ãã®ã¹ã©ã€ãã§éèŠãªã®ã¯ãRust ã«ã¯ãå
񑆇
§ã®èåŸã«ããããŒã¿ãå€æŽããå®å
šãªæ¹æ³ãçšæãããŠãããšããããšã§ããå®å
šæ§ã確ä¿ããã«ã¯ããŸããŸãªæ¹æ³ããããŸãããããã§ã¯ RefCell
ãš Cell
ãåãäžããŸãã
-
RefCell
ã¯ãã©ã³ã¿ã€ã ãã§ãã¯ãšãšãã« Rust ã®éåžžã®åçšã«ãŒã«ïŒè€æ°ã®å ±æåç §ãŸãã¯åäžã®æä»åç §ïŒãé©çšããŸãããã®å Žåããã¹ãŠã®åçšã¯éåžžã«çããéè€ããªãããããã§ãã¯ã¯åžžã«æåããŸãã- The extra block in the
RefCell
example is to end the borrow created by the call toborrow_mut
before we print the cell. Trying to print a borrowedRefCell
just shows the message"{borrowed}"
.
- The extra block in the
-
Cell
ã¯å®å šæ§ã確ä¿ããããã®ããã·ã³ãã«ãªæ段ã§ããã&self
ãåãåãset
ã¡ãœãããåããŠããŸããã©ã³ã¿ã€ã ãã§ãã¯ã¯å¿ èŠãããŸããããå€ã移åããå¿ èŠããããããã«ãã£ãŠã³ã¹ããçºçããããšããããŸãã -
Both
RefCell
andCell
are!Sync
, which means&RefCell
and&Cell
canât be passed between threads. This prevents two threads trying to access the cell at once.
æŒç¿: å¥åº·ã«é¢ããçµ±èš
å¥åº·ç®¡çã·ã¹ãã ã®å®è£ ã®äžç°ãšããŠããŠãŒã¶ãŒã®å¥åº·ã«é¢ããçµ±èšæ å ±ã远跡ããå¿ èŠããããŸãã
impl
ãããã¯ã®ã¹ã¿ãé¢æ°ãšãUser
æ§é äœã®å®çŸ©ãããç¶æ
ããéå§ããŸããUser
æ§é äœã® impl
ãããã¯ã«ãããŠã¹ã¿ãåãããé¢æ°ãå®è£
ããããšã§ãã
以äžã®ã³ãŒãã https://play.rust-lang.org/ ã«ã³ããŒããå®äœããªãã¡ãœããã®äžèº«ãå®è£ ããŸãã
// TODO: å®è£
ãå®äºãããããããåé€ããŸãã
#![allow(unused_variables, dead_code)]
#![allow(dead_code)]
pub struct User {
name: String,
age: u32,
height: f32,
visit_count: usize,
last_blood_pressure: Option<(u32, u32)>,
}
pub struct Measurements {
height: f32,
blood_pressure: (u32, u32),
}
pub struct HealthReport<'a> {
patient_name: &'a str,
visit_count: u32,
height_change: f32,
blood_pressure_change: Option<(i32, i32)>,
}
impl User {
pub fn new(name: String, age: u32, height: f32) -> Self {
Self { name, age, height, visit_count: 0, last_blood_pressure: None }
}
pub fn visit_doctor(&mut self, measurements: Measurements) -> HealthReport {
todo!("Update a user's statistics based on measurements from a visit to the doctor")
}
}
fn main() {
let bob = User::new(String::from("Bob"), 32, 155.2);
println!("I'm {} and my age is {}", bob.name, bob.age);
}
#[test]
fn test_visit() {
let mut bob = User::new(String::from("Bob"), 32, 155.2);
assert_eq!(bob.visit_count, 0);
let report =
bob.visit_doctor(Measurements { height: 156.1, blood_pressure: (120, 80) });
assert_eq!(report.patient_name, "Bob");
assert_eq!(report.visit_count, 1);
assert_eq!(report.blood_pressure_change, None);
assert!((report.height_change - 0.9).abs() < 0.00001);
let report =
bob.visit_doctor(Measurements { height: 156.1, blood_pressure: (115, 76) });
assert_eq!(report.visit_count, 2);
assert_eq!(report.blood_pressure_change, Some((-5, -4)));
assert_eq!(report.height_change, 0.0);
}
解ç
ã©ã€ãã¿ã€ã
This segment should take about 50 minutes. It contains:
Slide | Duration |
---|---|
é¢æ°ãšã©ã€ãã¿ã€ã | 10 minutes |
ã©ã€ãã¿ã€ã ã®çç¥ | 5 minutes |
æ§é äœã®ã©ã€ãã¿ã€ã | 5 minutes |
æŒç¿: Protobufã®è§£æ | 30 minutes |
é¢æ°ãšã©ã€ãã¿ã€ã
åç §ã«ã¯ã©ã€ãã¿ã€ã ããããããã¯åç §ããå€ããããé·ãåç¶ãããŠã¯ãªããŸãããããã¯åçšãã§ãã«ãŒã«ãã£ãŠæ€èšŒãããŸãã
ãããŸã§èŠãŠãããšãããã©ã€ãã¿ã€ã ã¯æé»ã«æ±ããŸããã&'a Point
ã&'document str
ã®ããã«æ瀺çã«æå®ããããšãã§ããŸããã©ã€ãã¿ã€ã 㯠'
ã§å§ãŸãã'a
ãäžè¬çãªããã©ã«ãåã§ãã&'a Point
ã¯ããå°ãªããšãã©ã€ãã¿ã€ã a
ã®éã¯æå¹ãªãåçšãã Point
ããšãšè§£éããŸãã
ã©ã€ãã¿ã€ã ã¯åžžã«ã³ã³ãã€ã©ã«ãã£ãŠæšæž¬ãããŸããèªåã§ã©ã€ãã¿ã€ã ãå²ãåœãŠãããšã¯ã§ããŸãããæ瀺çãªã©ã€ãã¿ã€ã ã¢ãããŒã·ã§ã³ã䜿çšãããšããããŸããªãšããã«å¶çŽã課ãããšãã§ããŸããããã«å¯Ÿããã³ã³ãã€ã©ã¯ãã®å¶çŽãæºããã©ã€ãã¿ã€ã ãèšå®ã§ããããšãæ€èšŒããŸãã
é¢æ°ã«å€ãæž¡ããé¢æ°ããå€ãè¿ãããšãèæ ®ããå Žåãã©ã€ãã¿ã€ã ã¯ããè€éã«ãªããŸãã
Speaker Notes
This slide should take about 10 minutes.
ãã®äŸã§ã¯ãã³ã³ãã€ã©ã¯ p3
ã®ã©ã€ãã©ã€ã ãæšæž¬ããããåºæ¥ãŸããããé¢æ°æ¬äœã®å
éšãèŠããšãp3
ã®ã©ã€ãã¿ã€ã 㯠p1
ãš p2
ã®ããããçããããæ³å®ã§ããããšãããããŸãããã ããåãšåæ§ã«ãRust ã§ã¯é¢æ°ã®åŒæ°ãæ»ãå€ã«ã©ã€ãã¿ã€ã ã®æ瀺çãªã¢ãããŒã·ã§ã³ãå¿
èŠã§ãã
left_most
ã« 'a
ãé©åã«è¿œå ããŸãã
fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {
ããã¯ããp1 ãš p2 ã®äž¡æ¹ã 'a
ããé·ãåç¶ãããšãæ»ãå€ã¯å°ãªããšã 'a
ã®éåç¶ããããšããæå³ã«ãªããŸãã
äžè¬çãªã±ãŒã¹ã§ã¯ã次ã®ã¹ã©ã€ãã§èª¬æããããã«ã©ã€ãã¿ã€ã ãçç¥ã§ããŸãã
é¢æ°ãšã©ã€ãã¿ã€ã
é¢æ°ã®åŒæ°ãæ»ãå€ã®ã©ã€ãã¿ã€ã ã¯å®å šã«æå®ããå¿ èŠããããŸãããRust ã§ã¯ã»ãšãã©ã®å Žåãããã€ãã®ç°¡åãªã«ãŒã«ã«ãããã©ã€ãã¿ã€ã ãçç¥ã§ããŸããããã¯æšè«ã§ã¯ãªããæ§æã®çç¥åœ¢ã«ãããŸããã
- ã©ã€ãã¿ã€ã ã¢ãããŒã·ã§ã³ãä»ããŠããªãååŒæ°ã«ã¯ã1 ã€ã®ã©ã€ãã¿ã€ã ãäžããããŸãã
- åŒæ°ã®ã©ã€ãã¿ã€ã ã 1 ã€ãããªãå Žåãã¢ãããŒã·ã§ã³ã®ãªãæ»ãå€ãã¹ãŠã«ãã®ã©ã€ãã¿ã€ã ãäžããããŸãã
- åŒæ°ã®ã©ã€ãã¿ã€ã ãè€æ°ãããæåã®ã©ã€ãã¿ã€ã ã
self
ã§ããå Žåãã¢ãããŒã·ã§ã³ã®ãªãæ»ãå€ãã¹ãŠã«ãã®ã©ã€ãã¿ã€ã ãäžããããŸãã
Speaker Notes
This slide should take about 5 minutes.
ãã®äŸã§ã¯ãcab_distance
ã«é¢ããã©ã€ãã¿ã€ã ã®èšè¿°ã¯çç¥ãããŠããŸãã
nearest
é¢æ°ã¯ãæ瀺çãªã¢ãããŒã·ã§ã³ãå¿
èŠãšããè€æ°ã®åç
§ãåŒæ°ã«å«ãé¢æ°ã®ããäžã€ã®äŸã§ãã
è¿ãããã©ã€ãã¿ã€ã ã«ã€ããŠåã®ã¢ãããŒã·ã§ã³ãä»ããããã«ã·ã°ããã£ã調æŽããŠã¿ãŸãããã
fn nearest<'a, 'q>(points: &'a [Point], query: &'q Point) -> Option<&'q Point> {
ãããããšã³ã³ãã€ã«ãéããªããªããŸããããã¯ãããªãã¡ãã³ã³ãã€ã©ãã¢ãããŒã·ã§ã³ã®åŠ¥åœæ§ããã§ãã¯ããŠãããšããããšã瀺ããã®ã§ãããã ããããã¯çã®ãã€ã³ã¿ïŒå®å šã§ã¯ãªãïŒã«ã¯åœãŠã¯ãŸããŸãããã¢ã³ã»ãŒãRustã䜿çšããå Žåã«ãããã¯ãããããšã©ãŒã®åå ãšãªã£ãŠããŸãã
ã©ã€ãã¿ã€ã ãã©ã®ãããªå Žåã«äœ¿ãã¹ãããåè¬è ãã質åãåãããããããŸãããRust ã®åçšã§ã¯åžžã«ã©ã€ãã¿ã€ã ã䜿çšããŸããã»ãšãã©ã®å Žåãçç¥ãåæšè« ã«ãããã©ã€ãã¿ã€ã ãèšè¿°ããå¿ èŠã¯ãããŸãããããè€éãªã±ãŒã¹ã§ã¯ãã©ã€ãã¿ã€ã ã¢ãããŒã·ã§ã³ã䜿çšããããšã§ãããŸããã解決ã§ããŸããå€ãã®å Žåãç¹ã«ãããã¿ã€ãã³ã°ã§ã¯ãå¿ èŠã«å¿ããŠå€ãã¯ããŒãã³ã°ããŠææããŒã¿ãåŠçããæ¹ãç°¡åã§ãã
ããŒã¿æ§é ãšã©ã€ãã¿ã€ã
ããŒã¿åãåçšããŒã¿ãå éšã«ä¿æããå Žåãã©ã€ãã¿ã€ã ã¢ãããŒã·ã§ã³ãä»ããå¿ èŠããããŸãã
Speaker Notes
This slide should take about 5 minutes.
- äžèšã®äŸã§ã¯ã
Highlight
ã®ã¢ãããŒã·ã§ã³ã«ãããå å ããã&str
ã®åç §å ã®ããŒã¿ã¯ãå°ãªããšããã®ããŒã¿ã䜿çšããHighlight
ã®ã€ã³ã¹ã¿ã³ã¹ãååšããéãåç¶ããªããã°ãªããªããªããŸãã fox
ïŒãŸãã¯dog
ïŒã®ã©ã€ãã¿ã€ã ãçµäºããåã«text
ã䜿çšããããšãåçšãã§ãã«ãŒã¯ãšã©ãŒãã¹ããŒããŸãã- æ¶è²»ããããŒã¿ãå«ãŸããåã§ã¯ããŠãŒã¶ãŒã¯å ã®ããŒã¿ãä¿æããããåŸãªããªããŸããããã¯è»œéã®ãã¥ãŒãäœæããå Žåã«äŸ¿å©ã§ãããäžè¬çã«ã¯äœ¿ãã«ãããªããŸãã
- å¯èœã§ããã°ãããŒã¿æ§é ãããŒã¿ãçŽæ¥ææã§ããããã«ããŸãã
- å éšã«è€æ°ã®åç §ãããæ§é äœã«ã¯ãè€æ°ã®ã©ã€ãã¿ã€ã ã¢ãããŒã·ã§ã³ãå«ãŸããå ŽåããããŸãããããå¿ èŠã«ãªãã®ã¯ãæ§é äœèªäœã®ã©ã€ãã¿ã€ã ã ãã§ãªããåç §å士ã®ã©ã€ãã¿ã€ã ã®é¢ä¿ãèšè¿°ããå¿ èŠãããå Žåã§ããããã¯éåžžã«é«åºŠãªãŠãŒã¹ã±ãŒã¹ã§ãã
æŒç¿: Protobufã®è§£æ
ãã®æŒç¿ã§ã¯ãprotobuf ãã€ã㪠ãšã³ã³ãŒãçšã®ããŒãµãŒãäœæããŸããèŠãããããç°¡åã§ãã®ã§ãå¿é ã¯ãããŸãããããã¯ãããŒã¿ã®ã¹ã©ã€ã¹ãæž¡ãäžè¬çãªè§£æãã¿ãŒã³ã瀺ããŠããŸããåºã«ãªãããŒã¿èªäœãã³ããŒãããããšã¯ãããŸããã
protobuf ã¡ãã»ãŒãžãå®å
šã«è§£æããã«ã¯ããã£ãŒã«ãçªå·ã§ã€ã³ããã¯ã¹ä»ãããããã£ãŒã«ãã®åãç¥ãå¿
èŠããããŸããããã¯éåžžãproto
ãã¡ã€ã«ã§æäŸãããŸãããã®æŒç¿ã§ã¯ããã£ãŒã«ãããšã«åŒã³åºãããé¢æ°ã® match
ã¹ããŒãã¡ã³ãã«ããã®æ
å ±ããšã³ã³ãŒãããŸãã
次㮠proto ã䜿çšããŸãã
message PhoneNumber {
optional string number = 1;
optional string type = 2;
}
message Person {
optional string name = 1;
optional int32 id = 2;
repeated PhoneNumber phones = 3;
}
proto ã¡ãã»ãŒãžã¯ãé£ç¶ãããã£ãŒã«ããšããŠãšã³ã³ãŒããããŸãããããããåŸãã«å€ã䌎ããã¿ã°ããšããŠå®è£
ãããŸããã¿ã°ã«ã¯ãã£ãŒã«ãçªå·ïŒäŸ: Person
ã¡ãã»ãŒãžã® id
ãã£ãŒã«ãã«ã¯ 2
ïŒãšããã€ã ã¹ããªãŒã ãããã€ããŒããã©ã®ããã«æ±ºå®ãããããå®çŸ©ããã¯ã€ã€ãŒã¿ã€ããå«ãŸããŸãã
ã¿ã°ãå«ãæŽæ°ã¯ãVARINT ãšåŒã°ããå¯å€é·ãšã³ã³ãŒãã§è¡šãããŸãã幞ãã«ããparse_varint
ã¯ä»¥äžã§ãã§ã«å®çŸ©ãããŠããŸãããŸãããã®ã³ãŒãã§ã¯ãPerson
ãã£ãŒã«ããš PhoneNumber
ãã£ãŒã«ããåŠçããã¡ãã»ãŒãžã解æããŠãããã®ã³ãŒã«ããã¯ã«å¯Ÿããäžé£ã®åŒã³åºãã«å€æããã³ãŒã«ããã¯ãå®çŸ©ããŠããŸãã
æ®ãäœæ¥ã¯ãparse_field
é¢æ°ãšãPerson
ããã³ PhoneNumber
ã® ProtoMessage
ãã¬ã€ããå®è£
ããã ãã§ãã
Speaker Notes
This slide and its sub-slides should take about 30 minutes.
- In this exercise there are various cases where protobuf parsing might fail, e.g. if you try to parse an
i32
when there are fewer than 4 bytes left in the data buffer. In normal Rust code weâd handle this with theResult
enum, but for simplicity in this exercise we panic if any errors are encountered. On day 4 weâll cover error handling in Rust in more detail.
解ç
4 æ¥ç®ã®ãã¬ãŒãã³ã°ã«ãããã
æ¬æ¥ã¯ãRust ã§ã®å€§èŠæš¡ãªãœãããŠã§ã¢ã®ãã«ãã«é¢é£ãããããã¯ãåãäžããŸãã
- ã€ãã¬ãŒã¿:
Iterator
ãã¬ã€ãã®è©³çŽ°ã - ã¢ãžã¥ãŒã«ãšå¯èŠæ§ã
- Testing.
- ãšã©ãŒåŠç: ãããã¯ã
Result
ãtry æŒç®å?
ã - ã¢ã³ã»ãŒãRust: å®å šãª Rust ã§ã¯èšè¿°ã§ããªãå Žåã®åé¿çã
ã¹ã±ãžã¥ãŒã«
Including 10 minute breaks, this session should take about 2 hours and 40 minutes. It contains:
Segment | Duration |
---|---|
ãããã | 3 minutes |
ã€ãã¬ãŒã¿ | 45 minutes |
ã¢ãžã¥ãŒã« | 40 minutes |
ãã¹ã | 45 minutes |
ã€ãã¬ãŒã¿
This segment should take about 45 minutes. It contains:
Slide | Duration |
---|---|
Iterator | 5 minutes |
IntoIterator | 5 minutes |
FromIterator | 5 minutes |
æŒç¿: ã€ãã¬ãŒã¿ã®ã¡ãœãããã§ãŒã³ | 30 minutes |
Iterator
Iterator
ãã¬ã€ãã¯ãã³ã¬ã¯ã·ã§ã³å
ã®äžé£ã®èŠçŽ ã«å¯ŸããŠé çªã«åŠçãé©çšããããšãå¯èœã«ããŸãããã®ãã¬ã€ãã¯nextã¡ãœãããå¿
èŠãšããããã«ããå€ãã®ã¡ãœãããæäŸããŸããå€ãã®æšæºã©ã€ãã©ãªå㧠Iterator
ãå®è£
ãããŠããŸãããèªåã§å®è£
ããããšãã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
-
Iterator
ãã¬ã€ãã¯ãã³ã¬ã¯ã·ã§ã³ã«å¯Ÿããå€ãã®äžè¬çãªé¢æ°åããã°ã©ãã³ã° ãªãã¬ãŒã·ã§ã³ïŒäŸ:map
ãfilter
ãreduce
ãªã©ïŒãå®è£ ããŸãããã®ãã¬ã€ãã®ããã¥ã¡ã³ãã«ãããŠããããã®ãã¹ãŠã®ãªãã¬ãŒã·ã§ã³ã«é¢ãã説æã確èªã§ããŸããRust ã§ã¯ããããã®é¢æ°ã«ãããåçã®åœä»€åå®è£ ãšåããããå¹ççãªã³ãŒããçæãããŸãã -
IntoIterator
ã¯ãforã«ãŒããå®çŸããããã®ãã¬ã€ãã§ããã³ã¬ã¯ã·ã§ã³åïŒVec<T>
ãªã©ïŒãšããããã«å¯Ÿããåç §ïŒ&Vec<T>
ã&[T]
ãªã©ïŒã«ãããŠå®è£ ãããŠããŸãããŸããç¯å²ãè¡šãåã«ãããŠãå®è£ ãããŠããŸããfor i in some_vec { .. }
ã䜿çšããŠãã¯ã¿ãŒãå埩åŠçã§ããã®ã«ãsome_vec.next()
ãååšããªãã®ã¯ãã®ããã§ãã
IntoIterator
Iterator
ãã¬ã€ãã¯ãã€ãã¬ãŒã¿ãäœæããåŸã«å埩åŠçãè¡ãæ¹æ³ã瀺ããŸããé¢é£ãããã¬ã€ã IntoIterator
ã¯ãããåã«å¯Ÿããã€ãã¬ãŒã¿ãäœæããæ¹æ³ãå®çŸ©ããŸãããã㯠for
ã«ãŒãã«ãã£ãŠèªåçã«äœ¿çšãããŸãã
Speaker Notes
This slide should take about 5 minutes.
IntoIterator
ã®ããã¥ã¡ã³ããã¯ãªãã¯ããŠã芧ãã ãããIntoIterator
ã®ãã¹ãŠã®å®è£
ã§ã次㮠2 ã€ã®åã宣èšããå¿
èŠããããŸãã
Item
: å埩åŠçããåïŒi8
ãªã©ïŒãIntoIter
:into_iter
ã¡ãœããã«ãã£ãŠè¿ãããIterator
åã
IntoIter
ãšItem
ã¯é¢é£ããããã€ãã¬ãŒã¿ã¯Item
ãšåãåãæã€å¿
èŠããããŸããããªãã¡ãOption<Item>
ãè¿ããŸãã
ãã®äŸã¯ãx 座æšãš y 座æšã®ãã¹ãŠã®çµã¿åãããå埩åŠçããŠããŸãã
main
ã§ã°ãªããã 2 åå埩åŠçããŠã¿ãŸããããããã¯ãªã倱æããã®ã§ãããããIntoIterator::into_iter
㯠self
ã®æææš©ãååŸããããšã«çç®ããŠãã ããã
ãã®åé¡ãä¿®æ£ããã«ã¯ã&Grid
ã« IntoIterator
ãå®è£
ããGrid
ãžã®åç
§ã GridIter
ã«ä¿åããŸãã
æšæºã©ã€ãã©ãªåã§ãåãåé¡ãçºçããå¯èœæ§ããããŸããfor e in some_vector
ã¯ãsome_vector
ã®æææš©ãååŸãããã®ãã¯ã¿ãŒã®ææèŠçŽ ãå埩åŠçããŸããsome_vector
ã®èŠçŽ ãžã®åç
§ãå埩åŠçããã«ã¯ã代ããã« for e in &some_vector
ã䜿çšããŸãã
FromIterator
FromIterator
ã䜿çšãããšãIterator
ããã³ã¬ã¯ã·ã§ã³ãäœæã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
Iterator
ã®å®è£
fn collect<B>(self) -> B
where
B: FromIterator<Self::Item>,
Self: Sized
ãã®ã¡ãœãã㧠B
ãæå®ããã«ã¯ã次㮠2 ã€ã®æ¹æ³ããããŸãã
- ãturbofishãã䜿çšããå Žå: äŸãã°ãäžèšã«ãããã
some_iterator.collect::<COLLECTION_TYPE>()
ãããã§äœ¿çšãããŠãã_ ã¯Rustã«Vecã®
èŠçŽ ã®æ¹ãæšæž¬ãããããã®ãã®ã§ãã - åæšè«ã䜿çšããå Žå:
let prime_squares: Vec<_> = some_iterator.collect()
ããã®åœ¢åŒã䜿çšããããã«äŸãæžãæããŠãã ããã
Vec
ã HashMap
ãªã©ã« FromIterator
ã®åºæ¬çãªå®è£
ãçšæãããŠããŸãããŸããIterator<Item = Result<V, E>>
ã Result<Vec<V>, E>
ã«å€æã§ãããã®ãªã©ãããç¹åããå®è£
ããããŸãã
æŒç¿: ã€ãã¬ãŒã¿ã®ã¡ãœãããã§ãŒã³
ãã®æŒç¿ã§ã¯ãè€éãªèšç®ãå®è£
ããããã«Iterator
ãã¬ã€ãã§æäŸãããŠããã¡ãœãããããã€ããæ¢ããŠäœ¿çšããå¿
èŠããããŸãã
次ã®ã³ãŒãã https://play.rust-lang.org/ ã«ã³ããŒãããã¹ããéãããã«ããŠãã ãããã€ãã¬ãŒã¿åŒã䜿çšãããã®çµæãcollect
ããããšã§æ»ãå€ãçæããŸãã
解ç
ã¢ãžã¥ãŒã«
This segment should take about 40 minutes. It contains:
Slide | Duration |
---|---|
ã¢ãžã¥ãŒã« | 3 minutes |
ãã¡ã€ã«ã·ã¹ãã éå±€ | 5 minutes |
å¯èŠæ§ | 5 minutes |
useãsuperãself | 10 minutes |
æŒç¿: GUI ã©ã€ãã©ãªã®ã¢ãžã¥ãŒã« | 15 minutes |
ã¢ãžã¥ãŒã«
impl
ãããã¯ã§é¢æ°ãåã®åå空éã«æå±ãããæ¹æ³ã¯ãã§ã«èŠãŠããŸããã
åæ§ã«ãmod
ã䜿çšããŠåãšé¢æ°ã®åå空éãæå®ã§ããŸãã
Speaker Notes
This slide should take about 3 minutes.
- ããã±ãŒãž(package)ã¯æ©èœãæäŸãããã®ã§ãããäžã€ä»¥äžã®ã¯ã¬ãŒãããã«ãããæ¹æ³ãèšè¿°ãã
Cargo.toml
ãã¡ã€ã«ãå«ããã®ã§ãã - ãã€ããªã¯ã¬ãŒãã®å Žåã¯å®è¡å¯èœãã¡ã€ã«ãçæããã©ã€ãã©ãªã¯ã¬ãŒãã®å Žåã¯ã©ã€ãã©ãªãçæããŸãã
- ã¢ãžã¥ãŒã«ã«ãã£ãŠæ§æãšã¹ã³ãŒããå®çŸ©ãããŸãããã®ã»ã¯ã·ã§ã³ã§ã¯ã¢ãžã¥ãŒã«ã«çŠç¹ãåœãŠãŸãã
ãã¡ã€ã«ã·ã¹ãã éå±€
ã¢ãžã¥ãŒã«ã®å®çŸ©å 容ãçç¥ãããšãRust ã¯ãããå¥ã®ãã¡ã€ã«ã§æ¢ããŸãã
This tells Rust that the garden
module content is found at src/garden.rs
. Similarly, a garden::vegetables
module can be found at src/garden/vegetables.rs
.
crate
ã«ãŒãã¯ä»¥äžã®å Žæã«ãããŸãã
src/lib.rs
ïŒã©ã€ãã©ãª ã¯ã¬ãŒãã®å ŽåïŒsrc/main.rs
ïŒãã€ã㪠ã¯ã¬ãŒãã®å ŽåïŒ
ãã¡ã€ã«ã§å®çŸ©ãããã¢ãžã¥ãŒã«ã«å¯ŸããŠããå éšããã¥ã¡ã³ãçšã³ã¡ã³ããã䜿çšããŠèª¬æãå ããããšãã§ããŸãããããã®ã³ã¡ã³ãã¯ããããå«ãŸããã¢ã€ãã ïŒãã®å Žåã¯ã¢ãžã¥ãŒã«ïŒã«å¯Ÿãã説æã«ãªããŸãã
Speaker Notes
This slide should take about 5 minutes.
-
Rust 2018 ããåã§ã¯ãã¢ãžã¥ãŒã«ã
module.rs
ã§ã¯ãªãmodule/mod.rs
ã«é 眮ããå¿ èŠããããŸããããã㯠2018 以éã®ãšãã£ã·ã§ã³ã§ãäŸç¶ãšããŠãµããŒããããŠããŸãã -
filename/mod.rs
ã®ä»£ããã«filename.rs
ãå°å ¥ãããäž»ãªçç±ã¯ãmod.rs
ãšããååã®ãã¡ã€ã«ãå€ããããšãããããIDEã§åºå¥ããã®ãé£ããå Žåãããããã§ãã -
ããæ·±ããã¹ãã§ã¯ãã¡ã€ã³ ã¢ãžã¥ãŒã«ããã¡ã€ã«ã§ãã£ãŠãããã©ã«ãã䜿çšã§ããŸãã
src/ âââ main.rs âââ top_module.rs âââ top_module/ âââ sub_module.rs
-
Rust ãã¢ãžã¥ãŒã«ãæ€çŽ¢ããå Žæã¯ãã³ã³ãã€ã© ãã£ã¬ã¯ãã£ãã§å€æŽã§ããŸãã
#[path = "some/path.rs"] mod some_module;
ããã¯ãããšãã° Go ã§ããè¡ãããŠããããã«ã
some_module_test.rs
ãšããååã®ãã¡ã€ã«ã«ã¢ãžã¥ãŒã«ã®ãã¹ããé 眮ããå Žåã«äŸ¿å©ã§ãã
å¯èŠæ§
ã¢ãžã¥ãŒã«ã¯ãã©ã€ãã·ãŒã®å¢çã§ãã
- ã¢ãžã¥ãŒã« ã¢ã€ãã ã¯ããã©ã«ãã§ãã©ã€ããŒãã§ãïŒå®è£ ã®è©³çŽ°ã¯è¡šç€ºãããŸããïŒã
- 芪ã¢ã€ãã ãšå åŒã¢ã€ãã ã¯åžžã«èŠããŸãã
- èšãæããã°ãããã¢ã€ãã ãã¢ãžã¥ãŒã«
foo
ããèŠããå Žåããã®ã¢ã€ãã ã¯foo
ã®ãã¹ãŠã®åå«ããèŠããŸãã
Speaker Notes
This slide should take about 5 minutes.
- ã¢ãžã¥ãŒã«ãå
¬éããã«ã¯
pub
ããŒã¯ãŒãã䜿çšããŸãã
ãŸããé«åºŠãª pub(...)
æå®åã䜿çšããŠãå
¬éç¯å²ãå¶éããããšãã§ããŸãã
- Rust ãªãã¡ã¬ã³ã¹ ãã芧ãã ããã
pub(crate)
ã®å¯èŠæ§ãèšå®ããã®ã¯äžè¬çãªãã¿ãŒã³ã§ãã- ããã»ã©äžè¬çã§ã¯ãããŸããããç¹å®ã®ãã¹ã«å¯ŸããŠå¯èŠæ§ãæå®ããããšãåºæ¥ãŸãã
- ã©ã®ãããªå Žåããç¥å ã¢ãžã¥ãŒã«ïŒããã³ãã®ãã¹ãŠã®åå«ïŒã«å¯èŠæ§ãäžããå¿ èŠããããŸãã
useãsuperãself
ã¢ãžã¥ãŒã«ã¯ãuse
ã䜿çšããŠå¥ã®ã¢ãžã¥ãŒã«ã®ã·ã³ãã«ãã¹ã³ãŒãã«åã蟌ãããšãã§ããŸãã次ã®ãããªèšè¿°ã¯ã¢ãžã¥ãŒã«ã®å
é ã«ãããŠããèŠãããŸãã
ãã¹
ãã¹ã¯æ¬¡ã®ããã«è§£æ±ºãããŸãã
-
çžå¯Ÿãã¹ã®å Žå:
foo
ãŸãã¯self::foo
ã¯ãçŸåšã®ã¢ãžã¥ãŒã«å ã®foo
ãåç §ããŸããsuper::foo
ã¯ã芪ã¢ãžã¥ãŒã«å ã®foo
ãåç §ããŸãã
-
絶察ãã¹ã®å Žå:
crate::foo
ã¯ãçŸåšã®ã¯ã¬ãŒãã®ã«ãŒãå ã®foo
ãåç §ããŸããbar::foo
ã¯ãbar
ã¯ã¬ãŒãå ã®foo
ãåç §ããŸãã
Speaker Notes
This slide should take about 8 minutes.
-
ã·ã³ãã«ã¯ãããçããã¹ã§ãåãšã¯ã¹ããŒããããã®ãäžè¬çã§ããããšãã°ãã¯ã¬ãŒãå ã®æäžäœã®
lib.rs
ã«ã以äžã®ããã«èšè¿°ããŸããmod storage; pub use storage::disk::DiskStorage; pub use storage::network::NetworkStorage;
ããã«ãããçã䜿ãããããã¹ã䜿çšããŠã
DiskStorage
ãšNetworkStorage
ãä»ã®ã¯ã¬ãŒãã§äœ¿çšã§ããããã«ãªããŸãã -
ã»ãšãã©ã®å Žåã
use
ãæå®ããå¿ èŠãããã®ã¯ã¢ãžã¥ãŒã«å ã§å®éã«çŽæ¥äœ¿çšãããã¢ã€ãã ã®ã¿ã§ãããã ãããããã¬ã€ããå®è£ ããåããã§ã«ã¹ã³ãŒãã«å«ãŸããŠããå Žåã§ãããã®ãã¬ã€ãã®ã¡ãœãããåŒã³åºãã«ã¯ããã®ãã¬ã€ããã¹ã³ãŒãã«å«ãŸããŠããå¿ èŠããããŸããããšãã°ãRead
ãã¬ã€ããå®è£ ããåã§read_to_string
ã¡ãœããã䜿çšããã«ã¯ãuse std::io::Read
ãšããèšè¿°ãå¿ èŠã«ãªããŸãã -
use
ã¹ããŒãã¡ã³ãã«ã¯use std::io::*
ãšããããã«ã¯ã€ã«ãã«ãŒããå«ããããšãã§ããŸãããã®æ¹æ³ã¯ãã©ã®ã¢ã€ãã ãã€ã³ããŒããããã®ããæ確ã§ã¯ãªããæéã®çµéãšãšãã«å€åããå¯èœæ§ããããããããããããŸããã
æŒç¿: GUI ã©ã€ãã©ãªã®ã¢ãžã¥ãŒã«
ãã®æŒç¿ã§ã¯ãå°èŠæš¡ãª GUI ã©ã€ãã©ãªå®è£
ãåç·šæããŸãããã®ã©ã€ãã©ãªã§ã¯ãWidget
ãã¬ã€ãããã®ãã¬ã€ãã®ããã€ãã®å®è£
ãmain
é¢æ°ãå®çŸ©ããŠããŸãã
éåžžã¯ãååãŸãã¯å¯æ¥ã«é¢é£ããåã®ã»ãããåå¥ã®ã¢ãžã¥ãŒã«ã«é 眮ããã®ã§ããŠã£ãžã§ãã ã¿ã€ãããšã«ç¬èªã®ã¢ãžã¥ãŒã«ãçšæããå¿ èŠããããŸãã
Cargo Setup
Rust ãã¬ã€ã°ã©ãŠã³ã㯠1 ã€ã®ãã¡ã€ã«ãããµããŒãããŠããªããããããŒã«ã« ãã¡ã€ã« ã·ã¹ãã 㧠Cargo ãããžã§ã¯ããäœæããå¿ èŠããããŸãã
cargo init gui-modules
cd gui-modules
cargo run
çæããã src/main.rs
ãç·šéã㊠mod
ã¹ããŒãã¡ã³ããè¿œå ããsrc
ãã£ã¬ã¯ããªã«ãã¡ã€ã«ãè¿œå ããŸãã
ãœãŒã¹
GUI ã©ã€ãã©ãªã®åäžã¢ãžã¥ãŒã«å®è£ ã¯æ¬¡ã®ãšããã§ãã
pub trait Widget {
/// `self` ã®èªç¶ãªå¹
ã
fn width(&self) -> usize;
/// ãŠã£ãžã§ããããããã¡ã«æç»ããŸãã
fn draw_into(&self, buffer: &mut dyn std::fmt::Write);
/// ãŠã£ãžã§ãããæšæºåºåã«æç»ããŸãã
fn draw(&self) {
let mut buffer = String::new();
self.draw_into(&mut buffer);
println!("{buffer}");
}
}
pub struct Label {
label: String,
}
impl Label {
fn new(label: &str) -> Label {
Label { label: label.to_owned() }
}
}
pub struct Button {
label: Label,
}
impl Button {
fn new(label: &str) -> Button {
Button { label: Label::new(label) }
}
}
pub struct Window {
title: String,
widgets: Vec<Box<dyn Widget>>,
}
impl Window {
fn new(title: &str) -> Window {
Window { title: title.to_owned(), widgets: Vec::new() }
}
fn add_widget(&mut self, widget: Box<dyn Widget>) {
self.widgets.push(widget);
}
fn inner_width(&self) -> usize {
std::cmp::max(
self.title.chars().count(),
self.widgets.iter().map(|w| w.width()).max().unwrap_or(0),
)
}
}
impl Widget for Window {
fn width(&self) -> usize {
// æ ç·çšã« 4 ã€ã®ããã£ã³ã°ãè¿œå ããŸãã
self.inner_width() + 4
}
fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {
let mut inner = String::new();
for widget in &self.widgets {
widget.draw_into(&mut inner);
}
let inner_width = self.inner_width();
// TODO: Result<(), std::fmt::Error> ãè¿ãããã« draw_into ãå€æŽããŸãã次ã«ã.unwrap() ã®ä»£ããã«
// ? æŒç®åã䜿çšããŸãã
writeln!(buffer, "+-{:-<inner_width$}-+", "").unwrap();
writeln!(buffer, "| {:^inner_width$} |", &self.title).unwrap();
writeln!(buffer, "+={:=<inner_width$}=+", "").unwrap();
for line in inner.lines() {
writeln!(buffer, "| {:inner_width$} |", line).unwrap();
}
writeln!(buffer, "+-{:-<inner_width$}-+", "").unwrap();
}
}
impl Widget for Button {
fn width(&self) -> usize {
self.label.width() + 8 // ããã£ã³ã°ãå°ãè¿œå ããŸãã
}
fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {
let width = self.width();
let mut label = String::new();
self.label.draw_into(&mut label);
writeln!(buffer, "+{:-<width$}+", "").unwrap();
for line in label.lines() {
writeln!(buffer, "|{:^width$}|", &line).unwrap();
}
writeln!(buffer, "+{:-<width$}+", "").unwrap();
}
}
impl Widget for Label {
fn width(&self) -> usize {
self.label.lines().map(|line| line.chars().count()).max().unwrap_or(0)
}
fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {
writeln!(buffer, "{}", &self.label).unwrap();
}
}
fn main() {
let mut window = Window::new("Rust GUI Demo 1.23");
window.add_widget(Box::new(Label::new("This is a small text GUI demo.")));
window.add_widget(Box::new(Button::new("Click me!")));
window.draw();
}
Speaker Notes
This slide and its sub-slides should take about 15 minutes.
èªåã«ãšã£ãŠèªç¶ãªæ¹æ³ã§ã³ãŒããåå²ããå¿
èŠãª mod
ãuse
ãpub
宣èšã«æ
£ããããåè¬è
ã«ä¿ããŸãããã®åŸãã©ã®æ§æãæãæ
£çšçã§ãããã«ã€ããŠè©±ãåããŸãã
解ç
src
âââ main.rs
âââ widgets
â âââ button.rs
â âââ label.rs
â âââ window.rs
âââ widgets.rs
// ---- src/widgets.rs ----
mod button;
mod label;
mod window;
pub trait Widget {
/// `self` ã®èªç¶ãªå¹
ã
fn width(&self) -> usize;
/// ãŠã£ãžã§ããããããã¡ã«æç»ããŸãã
fn draw_into(&self, buffer: &mut dyn std::fmt::Write);
/// ãŠã£ãžã§ãããæšæºåºåã«æç»ããŸãã
fn draw(&self) {
let mut buffer = String::new();
self.draw_into(&mut buffer);
println!("{buffer}");
}
}
pub use button::Button;
pub use label::Label;
pub use window::Window;
// ---- src/widgets/label.rs ----
use super::Widget;
pub struct Label {
label: String,
}
impl Label {
pub fn new(label: &str) -> Label {
Label { label: label.to_owned() }
}
}
impl Widget for Label {
fn width(&self) -> usize {
// ANCHOR_END: Label-width
self.label.lines().map(|line| line.chars().count()).max().unwrap_or(0)
}
// ANCHOR: Label-draw_into
fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {
// ANCHOR_END: Label-draw_into
writeln!(buffer, "{}", &self.label).unwrap();
}
}
// ---- src/widgets/button.rs ----
use super::{Label, Widget};
pub struct Button {
label: Label,
}
impl Button {
pub fn new(label: &str) -> Button {
Button { label: Label::new(label) }
}
}
impl Widget for Button {
fn width(&self) -> usize {
// ANCHOR_END: Button-width
self.label.width() + 8 // ããã£ã³ã°ãå°ãè¿œå ããŸãã
}
// ANCHOR: Button-draw_into
fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {
// ANCHOR_END: Button-draw_into
let width = self.width();
let mut label = String::new();
self.label.draw_into(&mut label);
writeln!(buffer, "+{:-<width$}+", "").unwrap();
for line in label.lines() {
writeln!(buffer, "|{:^width$}|", &line).unwrap();
}
writeln!(buffer, "+{:-<width$}+", "").unwrap();
}
}
// ---- src/widgets/window.rs ----
use super::Widget;
pub struct Window {
title: String,
widgets: Vec<Box<dyn Widget>>,
}
impl Window {
pub fn new(title: &str) -> Window {
Window { title: title.to_owned(), widgets: Vec::new() }
}
pub fn add_widget(&mut self, widget: Box<dyn Widget>) {
self.widgets.push(widget);
}
fn inner_width(&self) -> usize {
std::cmp::max(
self.title.chars().count(),
self.widgets.iter().map(|w| w.width()).max().unwrap_or(0),
)
}
}
impl Widget for Window {
fn width(&self) -> usize {
// ANCHOR_END: Window-width
// æ ç·ã« 4 ã€ã®ããã£ã³ã°ãè¿œå ããŸãã
self.inner_width() + 4
}
// ANCHOR: Window-draw_into
fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {
// ANCHOR_END: Window-draw_into
let mut inner = String::new();
for widget in &self.widgets {
widget.draw_into(&mut inner);
}
let inner_width = self.inner_width();
// TODO: ãšã©ãŒåŠçã«ã€ããŠåŠç¿ããåŸã§ã
// Result<(), std::fmt::Error> ãè¿ãããã« draw_into ãå€æŽã§ããŸãã次ã«ãããã§
// .unwrap() ã®ä»£ããã« ? æŒç®åã䜿çšããŸãã
writeln!(buffer, "+-{:-<inner_width$}-+", "").unwrap();
writeln!(buffer, "| {:^inner_width$} |", &self.title).unwrap();
writeln!(buffer, "+={:=<inner_width$}=+", "").unwrap();
for line in inner.lines() {
writeln!(buffer, "| {:inner_width$} |", line).unwrap();
}
writeln!(buffer, "+-{:-<inner_width$}-+", "").unwrap();
}
}
// ---- src/main.rs ----
mod widgets;
use widgets::Widget;
fn main() {
let mut window = widgets::Window::new("Rust GUI Demo 1.23");
window
.add_widget(Box::new(widgets::Label::new("This is a small text GUI demo.")));
window.add_widget(Box::new(widgets::Button::new("Click me!")));
window.draw();
}
ãã¹ã
This segment should take about 45 minutes. It contains:
Slide | Duration |
---|---|
ãã¹ãã¢ãžã¥ãŒã« | 5 minutes |
ä»ã®ã¿ã€ãã®ãã¹ã | 5 minutes |
ã³ã³ãã€ã©ã® Lints ãš Clippy | 3 minutes |
æŒç¿: Luhnã¢ã«ãŽãªãºã | 30 minutes |
ãŠããããã¹ã
Rust ãš Cargo ã«ã¯ãã·ã³ãã«ãªåäœãã¹ã ãã¬ãŒã ã¯ãŒã¯ãä»å±ããŠããŸãã
-
åäœãã¹ãã¯ã³ãŒãã®ããããå Žæã«èšè¿°å¯èœã§ãã
-
çµ±åãã¹ãã¯
tests/
ãã£ã¬ã¯ããªå ã«èšè¿°ããŸãã
ãã¹ãã«ã¯ #[test]
ã®ããŒã¯ãä»ããŸããå€ãã®å Žåãåäœãã¹ãã¯éåžžãã¹ããããtests
ã¢ãžã¥ãŒã«ã«é
眮ããã#[cfg(test)]
ã«ãããã¹ãã®ãã«ãæã«ã®ã¿ã³ã³ãã€ã«ãããããã«ãªããŸãã
- ããã«ããããã©ã€ããŒã ãã«ããŒã®åäœãã¹ããè¡ããŸãã
#[cfg(test)]
å±æ§ãä»äžãããã³ãŒãã¯cargo test
ã®å®è¡æã«ã®ã¿æå¹ã«ãªããŸãã
Speaker Notes
This slide should take about 5 minutes.
çµæã衚瀺ããã«ã¯ããã¬ã€ã°ã©ãŠã³ãã§ãã¹ããå®è¡ããŸãã
ä»ã®ã¿ã€ãã®ãã¹ã
ã€ã³ãã°ã¬ãŒã·ã§ã³ãã¹ã
ã©ã€ãã©ãªãã¯ã©ã€ã¢ã³ããšããŠãã¹ãããå Žåã¯ãçµ±åãã¹ãã䜿çšããŸãã
tests/
ã®äžã« .rs
ãã¡ã€ã«ãäœæããŸãã
// tests/my_library.rs
use my_library::init;
#[test]
fn test_init() {
assert!(init().is_ok());
}
ãããã®ãã¹ãã§ã¯ãã¯ã¬ãŒãã®å ¬é API ã«ã®ã¿ã¢ã¯ã»ã¹ã§ããŸãã
ããã¥ã¡ã³ããŒã·ã§ã³ãã¹ã
Rust ã«ã¯ãããã¥ã¡ã³ãã®ãã¹ãã«é¢ããæ©èœãçµã¿èŸŒãŸããŠããŸãã
///
ã³ã¡ã³ãå ã®ã³ãŒããããã¯ã¯ãèªåçã« Rust ã³ãŒããšã¿ãªãããŸãã- ã³ãŒãã¯
cargo test
ã®äžç°ãšããŠã³ã³ãã€ã«ãããå®è¡ãããŸãã - ã³ãŒãã«
#
ãè¿œå ãããšãããã¥ã¡ã³ãã«ã¯è¡šç€ºãããªããªããŸãããã³ã³ãã€ã«ãšå®è¡ã¯åŒãç¶ãè¡ãããŸãã - Rust ãã¬ã€ã°ã©ãŠã³ã ã§äžèšã®ã³ãŒãããã¹ãããŸãã
ã³ã³ãã€ã©ã® Lints ãš Clippy
Rust ã³ã³ãã€ã©ã¯ãèªã¿ããããšã©ãŒããã³lintã¡ãã»ãŒãžãçæããŸããClippy ã§ã¯ãããã«å€ãã® lint ãã°ã«ãŒãã«ãŸãšããããŠããããããžã§ã¯ãããšã«æå¹ã«ã§ããŸãã
Speaker Notes
This slide should take about 3 minutes.
ã³ãŒããµã³ãã«ãå®è¡ããŠãšã©ãŒ ã¡ãã»ãŒãžã確èªããŸããããã«ã lint ã衚瀺ãããŠããŸãããã³ãŒãã®ã³ã³ãã€ã«ãäžåºŠã³ã³ãã€ã«åºæ¥ããšè¡šç€ºãããªããªããŸãããããã® lint ã衚瀺ããã«ã¯ããã¬ã€ã°ã©ãŠã³ã ãµã€ãã«åãæ¿ããŸãã
lint ã解決ããåŸããã¬ã€ã°ã©ãŠã³ã ãµã€ã㧠clippy
ãå®è¡ããŠãClippy ã®èŠåã衚瀺ããŸããClippy ã«ã¯ãlint ã«é¢ããåºç¯ãªããã¥ã¡ã³ãããããæ°ãã lintïŒããã©ã«ãã§ãšã©ãŒã«ãªããªã³ã ãå«ãïŒãåžžã«è¿œå ãããŠããŸãã
help: ...
ãä»ããšã©ãŒãèŠåã¯ãcargo fix
ãŸãã¯ãšãã£ã¿ã䜿çšããŠä¿®æ£ã§ããŸãã
æŒç¿: Luhnã¢ã«ãŽãªãºã
Luhn ã¢ã«ãŽãªãºã ã¯ãã¯ã¬ãžãã ã«ãŒãçªå·ã®æ€èšŒã«äœ¿çšãããŸãããã®ã¢ã«ãŽãªãºã ã¯æååãå ¥åãšããŠåãåãã以äžã®åŠçãè¡ã£ãŠã¯ã¬ãžãã ã«ãŒãçªå·ãæ€èšŒããŸãã
-
Ignore all spaces. Reject numbers with fewer than two digits.
-
å³ããå·Šã«èŠãŠãããªããããããã2æ¡ç®ã®æ°åã 2 åã«ããŸããæ°å€
1234
ã®å Žåã3
ãš1
ã 2 åã«ããŸããæ°å€98765
ã®å Žåã6
ãš8
ã 2 åã«ããŸãã -
æ¡ã 2 åã«ããåŸãçµæã 9 ãã倧ããå Žåã¯ãã®æ¡ãåèšããŸãããããã£ãŠã
7
ã 2 åãããš14
ã«ãªãã1 + 4 = 5
ã«ãªããŸãã -
2 åã«ããŠããªãæ°åãš 2 åã«ããæ°åããã¹ãŠåèšããŸãã
-
ã¯ã¬ãžãã ã«ãŒãçªå·ã¯ãåèšã
0
ã§çµããå Žåã«æå¹ã§ãã
The provided code provides a buggy implementation of the luhn algorithm, along with two basic unit tests that confirm that most of the algorithm is implemented correctly.
以äžã®ã³ãŒãã https://play.rust-lang.org/ ã«ã³ããŒããæäŸãããå®è£ ã®ãã°ãçºèŠããããã®è¿œå ã®ãã¹ããèšè¿°ããèŠã€ãããã°ãä¿®æ£ããŠãã ããã
解ç
ãããã
Including 10 minute breaks, this session should take about 2 hours and 20 minutes. It contains:
Segment | Duration |
---|---|
ãšã©ãŒåŠç | 1 hour and 5 minutes |
Unsafe Rust | 1 hour and 5 minutes |
ãšã©ãŒåŠç
This segment should take about 1 hour and 5 minutes. It contains:
Slide | Duration |
---|---|
ãããã¯ïŒpanicïŒ | 3 minutes |
Result | 5 minutes |
TryæŒç®å | 5 minutes |
Tryå€æ | 5 minutes |
Errorãã¬ã€ã | 5 minutes |
thiserror | 5 minutes |
anyhow | 5 minutes |
æŒç¿: Result ã䜿çšããæžãæã | 30 minutes |
ãããã¯ïŒpanicïŒ
Rust ã¯ããããã¯ãã䜿çšããŠèŽåœçãªãšã©ãŒãåŠçããŸãã
å®è¡æã«èŽåœçãªãšã©ãŒãçºçãããšãRust ã¯ãããã¯ãããªã¬ãŒããŸãã
- ãããã¯ã¯ãå埩äžèœãªãšã©ãŒãäºæããªããšã©ãŒã«äœ¿çšããããã®ãã®ã§ãã
- ãããã¯ã¯ããã°ã©ã ã«ãã°ãããããšã®å åã§ãã
- ã©ã³ã¿ã€ã ãšã©ãŒïŒå¢çãã§ãã¯ã®å€±æãªã©ïŒã¯ããããã¯ã«ãªãå ŽåããããŸãã
- ã¢ãµãŒã·ã§ã³ïŒ
assert!
ãªã©ïŒã¯å€±ææã«ãããã¯ã«ãªããŸãã - ç¹å®ã®ç®çã§ãããã¯ãããŠããå Žåã«ã¯ã
panic!
ãã¯ãã䜿çšã§ããŸãã
- ãããã¯ãçºçãããšãã¹ã¿ãã¯ããã¢ã³ã¯ã€ã³ãããããé¢æ°ããªã¿ãŒã³ããããã®ããã«å€ããããããããŸãã
- ã¯ã©ãã·ã¥ã蚱容ãããªãå Žåã¯ããããã¯ãçºçããªã APIïŒ
Vec::get
ãªã©ïŒã䜿çšããŸãã
Speaker Notes
This slide should take about 3 minutes.
ããã©ã«ãã§ã¯ããããã¯ãçºçãããšã¹ã¿ãã¯ã¯ã¢ã³ã¯ã€ã³ããããŸããã¢ã³ã¯ã€ã³ãã¯ä»¥äžã®ããã«ãã£ããã§ããŸãã
- ãã£ããã¯äžè¬çã§ã¯ãªãããã
catch_unwind
ã䜿çšããŠäŸå€åŠçãå®è£ ããããšããªãã§ãã ããã - ããã¯ã1 ã€ã®ãªã¯ãšã¹ããã¯ã©ãã·ã¥ããå Žåã§ãå®è¡ãç¶ããå¿ èŠããããµãŒããŒã§æçšã§ãã
- ããã¯ã
Cargo.toml
ã§panic = 'abort'
ãèšå®ãããŠããå Žåã¯æ©èœããŸããã
Result
Our primary mechanism for error handling in Rust is the Result
enum, which we briefly saw when discussing standard library types.
Speaker Notes
This slide should take about 5 minutes.
-
Result
has two variants:Ok
which contains the success value, andErr
which contains an error value of some kind. -
Whether or not a function can produce an error is encoded in the functionâs type signature by having the function return a
Result
value. -
Like with
Option
, there is no way to forget to handle an error: You cannot access either the success value or the error value without first pattern matching on theResult
to check which variant you have. Methods likeunwrap
make it easier to write quick-and-dirty code that doesnât do robust error handling, but means that you can always see in your source code where proper error handling is being skipped.
ãã®ä»
It may be helpful to compare error handling in Rust to error handling conventions that students may be familiar with from other programming languages.
äŸå€
-
Many languages use exceptions, e.g. C++, Java, Python.
-
In most languages with exceptions, whether or not a function can throw an exception is not visible as part of its type signature. This generally means that you canât tell when calling a function if it may throw an exception or not.
-
Exceptions generally unwind the call stack, propagating upward until a
try
block is reached. An error originating deep in the call stack may impact an unrelated function further up.
Error Numbers
-
Some languages have functions return an error number (or some other error value) separately from the successful return value of the function. Examples include C and Go.
-
Depending on the language it may be possible to forget to check the error value, in which case you may be accessing an uninitialized or otherwise invalid success value.
TryæŒç®å
connection-refused ã file-not-found ãªã©ã®ã©ã³ã¿ã€ã ãšã©ãŒã¯ Result
åã§åŠçãããŸããããã¹ãŠã®åŒã³åºãã§ãã®åãç
§åããã®ã¯é¢åãªå ŽåããããŸããtry æŒç®å ?
ã¯ãåŒã³åºãå
ã«ãšã©ãŒãè¿ãã®ã«äœ¿çšãããŸããããã«ãããäžè¬çãªä»¥äžã®ã³ãŒãããã¯ããã«ã·ã³ãã«ãªã³ãŒãã«å€æã§ããŸãã
match some_expression {
Ok(value) => value,
Err(err) => return Err(err),
}
å€æåŸã®ã³ãŒã:
some_expression?
ãã®æŒç®åã䜿çšããããšã§ããšã©ãŒåŠçã³ãŒããç°¡çŽ åã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
? ã䜿çšã㊠read_username
é¢æ°ãç°¡çŽ åããŸãã
èŠç¹ïŒ
username
å€æ°ã¯ãOk(string)
ãŸãã¯Err(error)
ã®ããããã«ãªããŸããfs::write
åŒã³åºãã䜿çšããŠãããŸããŸãªã·ããªãªïŒãã¡ã€ã«ããªãã空ã®ãã¡ã€ã«ããŠãŒã¶ãŒåã®ãããã¡ã€ã«ãªã©ïŒããã¹ãããŸãã- Note that
main
can return aResult<(), E>
as long as it implementsstd::process::Termination
. In practice, this means thatE
implementsDebug
. The executable will print theErr
variant and return a nonzero exit status on error.
Tryå€æ
?
ãå®éã«å±éãããšãåè¿°ã®ã³ãŒããããå°ãè€éãªã³ãŒãã«ãªããŸãã
expression?
äžã®ã³ãŒãã¯ã以äžãšåãããã«åäœããŸãã
match expression {
Ok(value) => value,
Err(err) => return Err(From::from(err)),
}
ããã§ã® From::from
åŒã³åºãã¯ããšã©ãŒåãé¢æ°ãè¿ãåã«å€æããããšããŠããããšãæå³ããŸããããã«ããããšã©ãŒãäžäœã¬ãã«ã®ãšã©ãŒã«ç°¡åã«ã«ãã»ã«åã§ããŸãã
äŸ
Speaker Notes
This slide should take about 5 minutes.
?
æŒç®åã¯ãé¢æ°ã®æ»ãå€ã®åãšäºææ§ã®ããå€ãè¿ãå¿
èŠããããŸããã€ãŸããResult
ã®å Žåããšã©ãŒåã«äºææ§ããªããã°ãªããŸãããResult<T, ErrorOuter>
ãè¿ãé¢æ°ã¯ãErrorOuter
ãš ErrorInner
ãåãåã§ããããErrorOuter
ã From<ErrorInner>
ãå®è£
ããŠããå Žåã«ã®ã¿ãå Result<U, ErrorInner>
ã®å€ã« ?
ã䜿çšã§ããŸãã
ç¹ã«å€æã 1 ãæã§ã®ã¿çºçããå Žåã¯ãFrom
ãå®è£
ãã代ããã« Result::map_err ã䜿çšããã®ãäžè¬çã§ãã
Option
ã«ã¯äºææ§ã®èŠä»¶ã¯ãããŸãããOption<T>
ãè¿ãé¢æ°ã¯ãä»»æã®TåãšUåã«å¯ŸããŠã?æŒç®åãOption
Result
ãè¿ãé¢æ°ã§ã¯ Option
ã« ?
ã䜿çšã§ããŸããããã®éãåæ§ã§ãããã ããOption::ok_or
㯠Option
ã Result
ã«å€æã§ããResult::ok
㯠Result
ã Option
ã«å€æã§ããŸãã
åçãªãšã©ãŒå
ããŸããŸãªå¯èœæ§ãã«ããŒããç¬èªã®åæåãèšè¿°ããããšãªããããããçš®é¡ã®ãšã©ãŒãè¿ããããã«ãããå ŽåããããŸããstd::error::Error
ãã¬ã€ãã䜿çšãããšããããããšã©ãŒãå«ããããšãã§ãããã¬ã€ã ãªããžã§ã¯ããç°¡åã«äœæã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
read_count
é¢æ°ã¯ãstd::io::Error
ïŒãã¡ã€ã« ãªãã¬ãŒã·ã§ã³ããïŒãŸã㯠std::num::ParseIntError
ïŒString::parse
ããïŒãè¿ãããšãã§ããŸãã
ãšã©ãŒãããã¯ã¹åããããšã§ã³ãŒããç¯çŽã§ããŸãããããã°ã©ã ã§ç°ãªããšã©ãŒã±ãŒã¹ãç°ãªãæ¹æ³ã§é©åã«åŠçããæ©èœã倱ãããŸãããã®ãããã©ã€ãã©ãªã®å
¬é API 㧠Box<dyn Error>
ã䜿çšããããšã¯éåžžããããããŸãããããšã©ãŒ ã¡ãã»ãŒãžãã©ããã«è¡šç€ºãããã ãã®ããã°ã©ã ã§ã¯é©åãªéžæè¢ãšãªãããŸãã
Make sure to implement the std::error::Error
trait when defining a custom error type so it can be boxed.
thiserror
The thiserror
crate provides macros to help avoid boilerplate when defining error types. It provides derive macros that assist in implementing From<T>
, Display
, and the Error
trait.
Speaker Notes
This slide should take about 5 minutes.
Error
å°åºãã¯ãã¯thiserror
ã«ãã£ãŠæäŸãããŸãããã®ãã¯ãã«ã¯ããšã©ãŒåãç°¡æœã«å®çŸ©ããã®ã«åœ¹ç«ã€å±æ§ãæ°å€ãçšæãããŠããŸãã#[error]
ããã®ã¡ãã»ãŒãžã¯ãDisplay
ãã¬ã€ããå°åºããããã«äœ¿çšãããŸãã- Note that the (
thiserror::
)Error
derive macro, while it has the effect of implementing the (std::error::
)Error
trait, is not the same this; traits and macros do not share a namespace.
anyhow
The anyhow
crate provides a rich error type with support for carrying additional contextual information, which can be used to provide a semantic trace of what the program was doing leading up to the error.
This can be combined with the convenience macros from thiserror
to avoid writing out trait impls explicitly for custom error types.
Speaker Notes
This slide should take about 5 minutes.
anyhow::Error
ã¯åºæ¬çã«Box<dyn Error>
ã®ã©ãããŒãšãªã£ãŠããŸãããã®ãããã©ã€ãã©ãªã®å ¬é API ãšããŠã¯äžè¬çã«ã¯é©ããŠããŸããããã¢ããªã§ã¯åºã䜿çšãããŠããŸããanyhow::Result<V>
ã¯Result<V, anyhow::Error>
ã®åãšã€ãªã¢ã¹ã§ãã- Functionality provided by
anyhow::Error
may be familiar to Go developers, as it provides similar behavior to the Goerror
type andResult<T, anyhow::Error>
is much like a Go(T, error)
(with the convention that only one element of the pair is meaningful). anyhow::Context
ã¯ãæšæºã®Result
åãšOption
åã«å®è£ ããããã¬ã€ãã§ãããããã®åã§.context()
ãš.with_context()
ãæå¹ã«ããã«ã¯ãuse anyhow::Context
ãå¿ èŠã§ãã
ãã®ä»
anyhow::Error
has support for downcasting, much likestd::any::Any
; the specific error type stored inside can be extracted for examination if desired withError::downcast
.
æŒç¿: Result ã䜿çšããæžãæã
The following implements a very simple parser for an expression language. However, it handles errors by panicking. Rewrite it to instead use idiomatic error handling and propagate errors to a return from main
. Feel free to use thiserror
and anyhow
.
Hint: start by fixing error handling in the
parse
function. Once that is working correctly, updateTokenizer
to implementIterator<Item=Result<Token, TokenizerError>>
and handle that in the parser.
解ç
Unsafe Rust
This segment should take about 1 hour and 5 minutes. It contains:
Slide | Duration |
---|---|
ã¢ã³ã»ãŒã | 5 minutes |
çãã€ã³ã¿ã®åç §å€ã | 10 minutes |
å¯å€ãªstaticå€æ° | 5 minutes |
å ±çšäœ | 5 minutes |
Unsafeé¢æ°ã®åŒã³åºã | 5 minutes |
Unsafeãªãã¬ã€ãã®å®è£ | 5 minutes |
æŒç¿: FFIã©ãã㌠| 30 minutes |
Unsafe Rust
Rust èšèªã¯ 2 ã€ã®éšåã§æ§æãããŠããŸãã
- å®å šãª Rust: ã¡ã¢ãªã»ãŒãã§ãæªå®çŸ©ã®åäœã¯èµ·ããããŸããã
- ã¢ã³ã»ãŒãRust: åææ¡ä»¶ã«éåããå Žåãæªå®çŸ©ã®åäœãããªã¬ãŒãããå¯èœæ§ããããŸãã
ãã®ã³ãŒã¹ã§ã¯äž»ã«å®å šãª Rust ãèŠãŠããŸããããå®å šã§ãªã Rust ãšã¯äœããç解ããŠããããšãéèŠã§ãã
ã¢ã³ã»ãŒããªã³ãŒãã¯éåžžãå°èŠæš¡ã§åé¢ãããŠããããã®æ£ç¢ºæ§ã¯æ éã«ææžåãããŠããå¿ èŠããããŸããéåžžã¯å®å šãªæœè±¡åã¬ã€ã€ã§ã©ãããããŠããŸãã
ã¢ã³ã»ãŒãRustã§ã¯ã次㮠5 ã€ã®æ°æ©èœãå©çšã§ããŸãã
- çãã€ã³ã¿ã®åç §å€ãã
- å¯å€ã®éçå€æ°ãžã®ã¢ã¯ã»ã¹ãŸãã¯å€æŽã
union
ãã£ãŒã«ããžã®ã¢ã¯ã»ã¹ãextern
é¢æ°ãå«ãunsafe
é¢æ°ã®åŒã³åºããunsafe
ãã¬ã€ãã®å®è£ ã
次ã«ãå®å šã§ãªãæ©èœã«ã€ããŠç°¡åã«èª¬æããŸãã詳ããã¯ãRust Book ã®ç¬¬ 19.1 ç« ãšãRustonomicon ãã芧ãã ããã
Speaker Notes
This slide should take about 5 minutes.
ã¢ã³ã»ãŒãRustã¯ãã³ãŒããæ£ãããªãããšãæå³ãããã®ã§ã¯ãããŸãããããããããŒãäžéšã®ã³ã³ãã€ã©å®å šæ§æ©èœããªãã«ããèªåã§æ£ããã³ãŒããèšè¿°ããªããã°ãªããªãããšãæå³ããŸãããŸããã³ã³ãã€ã©ãRustã®ã¡ã¢ãªå®å šæ§ã«é¢ããã«ãŒã«ã匷å¶ããªããªããšããããšãæå³ããŸãã
çãã€ã³ã¿ã®åç §å€ã
ãã€ã³ã¿ã®äœæã¯å®å
šã§ãããåç
§å€ãã«ã¯ unsafe
ãå¿
èŠã§ãã
Speaker Notes
This slide should take about 10 minutes.
unsafe
ãããã¯ããšã«ã³ã¡ã³ããèšè¿°ãããã®ãããã¯å
ã®ã³ãŒããè¡ãã¢ã³ã»ãŒããªæäœãã©ã®ããã«å®å
šæ§èŠä»¶ãæºãããŠããã®ããèšè¿°ããããšãããããããŸãïŒAndroid Rust ã¹ã¿ã€ã«ã¬ã€ãã§ãå¿
é ãšãããŠããŸãïŒã
ãã€ã³ã¿åç §å€ãã®å Žåãããã¯ãã€ã³ã¿ã valid ã§ãªããã°ãªããªãããšãæå³ããŸããã€ãŸãã次ã®ããã«ãªããŸãã
- ãã€ã³ã¿ã¯ null 以å€ã§ãªããã°ãªããªãããšã
- ãã€ã³ã¿ã¯ãïŒå²ãåœãŠãããåäžã®ãªããžã§ã¯ãã®å¢çå ã§ïŒåç §å€ãå¯èœã§ãªããã°ãªããªãã
- ãªããžã§ã¯ãã解æŸãããŠããªãããšã
- åããã±ãŒã·ã§ã³ã«åæã¢ã¯ã»ã¹ããããšããªãããšã
- åç §ããã£ã¹ãããŠãã€ã³ã¿ãååŸããå Žåãåºã«ãªããªããžã§ã¯ããåç¶ããªããã°ãªãããä»ã®ãããªãåç §ãéããŠããã®ã¡ã¢ãªã«ã¢ã¯ã»ã¹ããªãããš
ã»ãšãã©ã®å Žåããã€ã³ã¿ãé©åã«ã¢ã©ã€ã³ãããå¿ èŠããããŸãã
âNOT SAFEâãšããã³ã¡ã³ãããããšããã¯ãããããUBãã°ã®äŸã瀺ããŠããŸãã*r1
ã®ã©ã€ãã¿ã€ã 㯠'static
ã§ãããããr3
ã®å㯠&'static String
ãšãªããs
ããé·ãåç¶ããŸãããã€ã³ã¿ããã®åç
§ã®äœæã«ã¯çŽ°å¿ã®æ³šæãå¿
èŠã§ãã
å¯å€ãªstaticå€æ°
äžå€ã®éçå€æ°ã¯å®å šã«èªã¿åãããšãã§ããŸãã
ãã ããããŒã¿ç«¶åãçºçããå¯èœæ§ããããããå¯å€éçå€æ°ã®èªã¿åããšæžã蟌ã¿ã¯å®å šã§ã¯ãããŸããã
Speaker Notes
This slide should take about 5 minutes.
-
ãã®ããã°ã©ã ã¯ã·ã³ã°ã«ã¹ã¬ãããªã®ã§å®å šã§ããããããRust ã³ã³ãã€ã©ã¯ä¿å®çã§ãææªã®äºæ ãæ³å®ããŸãã
unsafe
ãåé€ãããšãè€æ°ã®ã¹ã¬ããããéçå€æ°ãå€æŽããããšã¯æªå®çŸ©ã®åäœã§ããããšã説æããã¡ãã»ãŒãžãã³ã³ãã€ã©ã«ãã衚瀺ãããã¯ãã§ãã -
äžè¬çã«ãå¯å€éçå€æ°ã䜿çšããããšã¯ããããããŸããããããŒã ã¢ãã±ãŒã¿ã®å®è£ ãäžéšã® C API ã®æäœãªã©ãäœã¬ãã«ã®
no_std
ã³ãŒãã§ã¯é©ããŠããå ŽåããããŸãã
å ±çšäœ
å ±çšäœã¯åæåã«äŒŒãŠããŸãããã¢ã¯ãã£ã ãã£ãŒã«ããèªåã§ãã©ããã³ã°ããå¿ èŠããããŸãã
Speaker Notes
This slide should take about 5 minutes.
Rust ã§ã¯ãéåžžã¯åæåã䜿çšã§ãããããå ±çšäœã¯ã»ãšãã©å¿ èŠãããŸãããå ±çšäœã¯ãC ã©ã€ãã©ãª API ãšã®ããåãã§å¿ èŠã«ãªãããšããããŸãã
ãã€ããå¥ã®åãšããŠå解éãããå Žåã¯ãstd::mem::transmute
ããzerocopy
ã¯ã¬ãŒãã®ãããªå®å
šãªã©ãããŒã䜿çšããããšãããããããŸãã
Unsafeé¢æ°ã®åŒã³åºã
Unsafeé¢æ°ã®åŒã³åºã
æªå®çŸ©ã®åäœãåé¿ããããã«æºããå¿
èŠãããè¿œå ã®åææ¡ä»¶ãããé¢æ°ãŸãã¯ã¡ãœããã¯ãunsafe
ãšããŒã¯ã§ããŸãã
Unsafeé¢æ°ã®æžãæ¹
æªå®çŸ©ã®åäœãåé¿ããããã«ç¹å®ã®æ¡ä»¶ãå¿
èŠãªå Žåã¯ãç¬èªã®é¢æ°ã unsafe
ãšããŒã¯ã§ããŸãã
Speaker Notes
This slide should take about 5 minutes.
Unsafeé¢æ°ã®åŒã³åºã
get_unchecked
, like most _unchecked
functions, is unsafe, because it can create UB if the range is incorrect. abs
is unsafe for a different reason: it is an external function (FFI). Calling external functions is usually only a problem when those functions do things with pointers which might violate Rustâs memory model, but in general any C function might have undefined behaviour under any arbitrary circumstances.
ãã®äŸã® "C"
㯠ABI ã§ãïŒä»ã® ABI ã䜿çšã§ããŸãïŒã
Unsafeé¢æ°ã®æžãæ¹
å®éã«ã¯ãswap
é¢æ°ã§ã¯ãã€ã³ã¿ã¯äœ¿çšããŸãããããã¯åç
§ã䜿çšããããšã§å®å
šã«å®è¡ã§ããŸãã
ã¢ã³ã»ãŒããªé¢æ°å
ã§ã¯ãã¢ã³ã»ãŒããªã³ãŒããunsafe
ãããã¯ãªãã«èšè¿°ããããšãã§ããŸãããã㯠#[deny(unsafe_op_in_unsafe_fn)]
ã§çŠæ¢ã§ããŸããè¿œå ãããšã©ããªããèŠãŠã¿ãŸããããããã¯ãä»åŸã® Rust ãšãã£ã·ã§ã³ã§å€æŽãããå¯èœæ§ããããŸãã
Unsafeãªãã¬ã€ãã®å®è£
é¢æ°ãšåæ§ã«ãæªå®çŸ©ã®åäœãåé¿ããããã«å®è£
ã§ç¹å®ã®æ¡ä»¶ãä¿èšŒããå¿
èŠãããå Žåã¯ããã¬ã€ãã unsafe
ãšããŠããŒã¯ã§ããŸãã
For example, the zerocopy
crate has an unsafe trait that looks something like this:
Speaker Notes
This slide should take about 5 minutes.
Rustdoc ã«ã¯ããã¬ã€ããå®å
šã«å®è£
ããããã®èŠä»¶ã«ã€ããŠèª¬æãã # Safety
ã»ã¯ã·ã§ã³ãå¿
èŠã§ãã
The actual safety section for IntoBytes
is rather longer and more complicated.
çµã¿èŸŒã¿ã® Send
ãã¬ã€ããš Sync
ãã¬ã€ãã¯ã¢ã³ã»ãŒãã§ãã
å®å šãªFFIã©ãã
Rust ã¯ãå€éšé¢æ°ã€ã³ã¿ãŒãã§ãŒã¹ïŒFFIïŒãä»ããé¢æ°åŒã³åºãã匷åã«ãµããŒãããŠããŸããããã䜿çšããŠããã£ã¬ã¯ããªå
ã®ãã¡ã€ã«åãèªã¿åãããã« Cããã°ã©ã ã§äœ¿çšãã libc
é¢æ°ã®å®å
šãªã©ãããŒãäœæããŸãã
以äžã®ããã¥ã¢ã« ããŒãžãã芧ãã ããã
std::ffi
ã¢ãžã¥ãŒã«ãåç
§ããŠãã ãããããã«ã¯ããã®æŒç¿ã§å¿
èŠãªæåååãå€æ°æ²èŒãããŠããŸãã
å | ãšã³ã³ãŒã | 䜿ã |
---|---|---|
str ãš String | UTF-8 | Rust ã§ã®ããã¹ãåŠç |
CStr ãš CString | NULçµç«¯æåå | C é¢æ°ãšã®éä¿¡ |
OsStr ãš OsString | OS åºæ | OS ãšã®éä¿¡ |
以äžã®ãã¹ãŠã®åéã§å€æãè¡ããŸãã
&str
ããCString
: æ«å°Ÿã®\0
æåã«ãé åãå²ãåœãŠãå¿ èŠããããŸããCString
ãã*const i8
: C é¢æ°ãåŒã³åºãããã®ãã€ã³ã¿ãå¿ èŠã§ãã*const i8
ãã&CStr
: æ«å°Ÿã®\0
æåãæ€åºã§ãããã®ãå¿ èŠã§ãã&CStr
ãã&[u8]
: ãã€ãã®ã¹ã©ã€ã¹ã¯ãäžæãªããŒã¿ãçšã®æ±çšç㪠ã€ã³ã¿ãŒãã§ãŒã¹ã§ãã&[u8]
ãã&OsStr
:&OsStr
ã¯OsString
ã«å€æããããã®äžéã¹ãããã§ãããOsStrExt
ã䜿çšããŠäœæããŸãã&OsStr
å ã®ããŒã¿ãè¿ããããã«åã³readdirãåŒã³åºããããã«ããããã«ã¯&OsStr
å ã®ããŒã¿ãã¯ããŒã³ããå¿ èŠããããŸãã
Nomicon ã«ããFFI ã«é¢ããæçãªç« ããããŸãã
以äžã®ã³ãŒãã https://play.rust-lang.org/ ã«ã³ããŒããäžè¶³ããŠããé¢æ°ãšã¡ãœãããèšå ¥ããŸãã
// TODO: å®è£
ãå®äºãããããããåé€ããŸãã
#![allow(unused_imports, unused_variables, dead_code)]
mod ffi {
use std::os::raw::{c_char, c_int};
#[cfg(not(target_os = "macos"))]
use std::os::raw::{c_long, c_uchar, c_ulong, c_ushort};
// ãªããŒã¯åãhttps://doc.rust-lang.org/nomicon/ffi.html ãã芧ãã ããã
#[repr(C)]
pub struct DIR {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
// readdir(3) ã® Linux ããã¥ã¢ã« ããŒãžã«æ²¿ã£ãã¬ã€ã¢ãŠããino_t ãš
// off_t ã¯
// /usr/include/x86_64-linux-gnu/{sys/types.h, bits/typesizes.h} ã®å®çŸ©ã«åŸã£ãŠè§£æ±ºãããŸãã
#[cfg(not(target_os = "macos"))]
#[repr(C)]
pub struct dirent {
pub d_ino: c_ulong,
pub d_off: c_long,
pub d_reclen: c_ushort,
pub d_type: c_uchar,
pub d_name: [c_char; 256],
}
// macOSããã¥ã¢ã« ããŒãžã®dir(5)ã«æ²¿ã£ãã¬ã€ã¢ãŠãã
#[cfg(all(target_os = "macos"))]
#[repr(C)]
pub struct dirent {
pub d_fileno: u64,
pub d_seekoff: u64,
pub d_reclen: u16,
pub d_namlen: u16,
pub d_type: u8,
pub d_name: [c_char; 1024],
}
unsafe extern "C" {
pub unsafe fn opendir(s: *const c_char) -> *mut DIR;
#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
pub unsafe fn readdir(s: *mut DIR) -> *const dirent;
// https://github.com/rust-lang/libc/issues/414ãããã³ macOS çããã¥ã¢ã« ããŒãžã®stat(2)ã«ããã
// _DARWIN_FEATURE_64_BIT_INODE ã«é¢ããã»ã¯ã·ã§ã³ãã芧ãã ããã
//
// ããããã®ã¢ããããŒããå©çšå¯èœã«ãªãåã«ååšããŠãããã©ãããã©ãŒã ("Platforms that existed before these updates were available")ããšã¯ã
// Intel ããã³ PowerPC äžã® macOSïŒiOS / wearOS ãªã©ã§ã¯ãªãïŒãæããŸãã
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
#[link_name = "readdir$INODE64"]
pub unsafe fn readdir(s: *mut DIR) -> *const dirent;
pub unsafe fn closedir(s: *mut DIR) -> c_int;
}
}
use std::ffi::{CStr, CString, OsStr, OsString};
use std::os::unix::ffi::OsStrExt;
#[derive(Debug)]
struct DirectoryIterator {
path: CString,
dir: *mut ffi::DIR,
}
impl DirectoryIterator {
fn new(path: &str) -> Result<DirectoryIterator, String> {
// opendir ãåŒã³åºããæåããå Žå㯠Ok å€ãè¿ãã
// ãã以å€ã®å Žåã¯ã¡ãã»ãŒãžãšãšãã« Err ãè¿ããŸãã
unimplemented!()
}
}
impl Iterator for DirectoryIterator {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
// NULL ãã€ã³ã¿ãè¿ããããŸã§ readdir ãåŒã³åºãç¶ããŸãã
unimplemented!()
}
}
impl Drop for DirectoryIterator {
fn drop(&mut self) {
// å¿
èŠã«å¿ã㊠closedir ãåŒã³åºããŸãã
unimplemented!()
}
}
fn main() -> Result<(), String> {
let iter = DirectoryIterator::new(".")?;
println!("files: {:#?}", iter.collect::<Vec<_>>());
Ok(())
}
解ç
Android ã§ã® Rust ãžãããã
Rust 㯠Android ã®ã·ã¹ãã ãœãããŠã§ã¢ã§ãµããŒããããŠããŸããã€ãŸããæ°ãããµãŒãã¹ãã©ã€ãã©ãªããã©ã€ããããã«ã¯ãã¡ãŒã ãŠã§ã¢ã Rust ã§äœæã§ããŸãïŒãŸãã¯ãå¿ èŠã«å¿ããŠæ¢åã®ã³ãŒããæ¹åã§ããŸãïŒã
Speaker Notes
Android 㧠Rust ã䜿çšãããããšãå¢ããŠããããã次ã®ããããã«èšåããããšãããããããŸãã
-
Service example: DNS over HTTP.
-
Libraries: Rutabaga Virtual Graphics Interface.
-
Kernel Drivers: Binder.
-
Firmware: pKVM firmware.
ã»ããã¢ãã
ã³ãŒãã®ãã¹ãã®ããã«Cuttlefish Android Virtual Device ã䜿çšããŸããæ¢åã®Deviceãããã°ããã«ã¢ã¯ã»ã¹ã§ããããšã確èªããããã§ãªããã°ä»¥äžã®ã³ãã³ãã«ããäœæããŠãããŠãã ããã
source build/envsetup.sh
lunch aosp_cf_x86_64_phone-trunk_staging-userdebug
acloud create
詳ããã¯ãAndroid ããããã㌠Codelab ãã芧ãã ããã
The code on the following pages can be found in the src/android/
directory of the course material. Please git clone
the repository to follow along.
Speaker Notes
èŠç¹ïŒ
-
Cuttlefish ã¯ãäžè¬ç㪠Linux ãã¹ã¯ãããã§åäœããããã«èšèšããããªãã¡ã¬ã³ã¹ Android ããã€ã¹ã§ããmacOS ã®ãµããŒããäºå®ãããŠããŸãã
-
Cuttlefish ã·ã¹ãã ã€ã¡ãŒãžã¯ãå®éã®ããã€ã¹ã«å¯Ÿããé«ãå¿ å®åºŠãç¶æããŠãããããå€ãã® Rust ãŠãŒã¹ã±ãŒã¹ãå®è¡ããã®ã«çæ³çãªãšãã¥ã¬ãŒã¿ã§ãã
ãã«ãã®ã«ãŒã«
Android ãã«ãã·ã¹ãã ïŒSoongïŒã¯ãããŸããŸãªã¢ãžã¥ãŒã«ãéã㊠Rust ããµããŒãããŠããŸãã
ã¢ãžã¥ãŒã« ã¿ã€ã | 説æ |
---|---|
rust_binary | Rust ãã€ããªãçæããŸãã |
rust_library | Rust ã©ã€ãã©ãªãçæããrlib ãš dylib ã®äž¡æ¹ã®ããªã¢ã³ããæäŸããŸãã |
rust_ffi | cc ã¢ãžã¥ãŒã«ã§äœ¿çšã§ãã Rust C ã©ã€ãã©ãªãçæããéçããªã¢ã³ããšå
±æããªã¢ã³ãã®äž¡æ¹ãæäŸããŸãã |
rust_proc_macro | proc-macro Rust ã©ã€ãã©ãªãçæããŸãããããã¯ã³ã³ãã€ã© ãã©ã°ã€ã³ã«äŒŒãŠããŸãã |
rust_test | æšæºã® Rust ãã¹ãããŒãã¹ã䜿çšãã Rust ãã¹ããã€ããªãçæããŸãã |
rust_fuzz | libfuzzer ãå©çšããŠãRust ãã¡ãºãã€ããªãçæããŸãã |
rust_protobuf | ãœãŒã¹ãçæããç¹å®ã® protobuf çšã®ã€ã³ã¿ãŒãã§ãŒã¹ãæäŸãã Rust ã©ã€ãã©ãªãçæããŸãã |
rust_bindgen | ãœãŒã¹ãçæããC ã©ã€ãã©ãªãžã® Rust ãã€ã³ãã£ã³ã°ãå«ã Rust ã©ã€ãã©ãªãçæããŸãã |
次㫠rust_binary
ãš rust_library
ãèŠãŠãããŸãã
Speaker Notes
è¿œå ã§æ¬¡ã®é ç®ã«èšåããããšãããããããŸãã
-
Cargo ã¯å€èšèªãªããžããªçšã«æé©åãããŠããŸããããŸããã€ã³ã¿ãŒãããããããã±ãŒãžãããŠã³ããŒãããŸãã
-
ã³ã³ãã©ã€ã¢ã³ã¹ããã³ããã©ãŒãã³ã¹äžã®çç±ãããAndroid ã§ã¯ã¯ã¬ãŒããããªãŒå ã«é 眮ããå¿ èŠããããŸãããŸããC /C++ / Java ã³ãŒããšã®çžäºéçšæ§ãå¿ èŠã§ããSoong ã䜿çšããããšã§ããã®ã®ã£ãããåããããšãã§ããŸãã
-
Soong has many similarities to Bazel, which is the open-source variant of Blaze (used in google3).
-
è±ç¥è: ã¹ã¿ãŒãã¬ãã¯ã®ãããŒã¿ãã¯ãã¹ã³ïŒSoongïŒåã¢ã³ããã€ãã§ãã
Rust ãã€ããª
ç°¡åãªã¢ããªããå§ããŸããããAOSP ãã§ãã¯ã¢ãŠãã®ã«ãŒãã§ã次ã®ãã¡ã€ã«ãäœæããŸãã
hello_rust/Android.bp:
rust_binary {
name: "hello_rust",
crate_name: "hello_rust",
srcs: ["src/main.rs"],
}
hello_rust/src/main.rs:
//! Rust ã®ãã¢ã
/// æšæ¶ãæšæºåºåã«åºåããŸãã
fn main() {
println!("Hello from Rust!");
}
ããã§ããã€ããªããã«ããpushãå®è¡ã§ããŸãã
m hello_rust
adb push "$ANDROID_PRODUCT_OUT/system/bin/hello_rust" /data/local/tmp
adb shell /data/local/tmp/hello_rust
Hello from Rust!
Rust ã©ã€ãã©ãª
rust_library
ã䜿çšããŠãAndroid çšã®æ°ãã Rust ã©ã€ãã©ãªãäœæããŸãã
ããã§ã¯ã2 ã€ã®ã©ã€ãã©ãªãžã®äŸåé¢ä¿ã宣èšããŸãã
libgreeting
: 以äžã§å®çŸ©ããŸããlibtextwrap
: ãã§ã«external/rust/crates/
ã«åã蟌ãŸããŠããã¯ã¬ãŒãã§ãã
hello_rust/Android.bp:
rust_binary {
name: "hello_rust_with_dep",
crate_name: "hello_rust_with_dep",
srcs: ["src/main.rs"],
rustlibs: [
"libgreetings",
"libtextwrap",
],
prefer_rlib: true, // ãã€ããã㯠ãªã³ã¯ ãšã©ãŒãåé¿ããããã«å¿
èŠã§ãã
}
rust_library {
name: "libgreetings",
crate_name: "greetings",
srcs: ["src/lib.rs"],
}
hello_rust/src/main.rs:
//! Rust ã®ãã¢ã
use greetings::greeting;
use textwrap::fill;
/// æšæ¶ãæšæºåºåã«åºåããŸãã
fn main() {
println!("{}", fill(&greeting("Bob"), 24));
}
hello_rust/src/lib.rs:
//! æšæ¶ã©ã€ãã©ãªã
/// `name` ã«æšæ¶ããŸãã
pub fn greeting(name: &str) -> String {
format!("Hello {name}, it is very nice to meet you!")
}
åãšåãããã«ãã€ããªããã«ããpushãå®è¡ããŸãã
m hello_rust_with_dep
adb push "$ANDROID_PRODUCT_OUT/system/bin/hello_rust_with_dep" /data/local/tmp
adb shell /data/local/tmp/hello_rust_with_dep
Hello Bob, it is very
nice to meet you!
AIDLïŒAndroidã€ã³ã¿ãŒãã§ã€ã¹å®çŸ©èšèªïŒ
Rust ã§ã¯ Android ã€ã³ã¿ãŒãã§ãŒã¹å®çŸ©èšèªïŒAIDLïŒ ããµããŒããããŠããŸãã
- Rust ã³ãŒãã¯æ¢åã® AIDL ãµãŒããŒãåŒã³åºãããšãã§ããŸãã
- Rust ã§ã¯æ°ãã AIDL ãµãŒããŒãäœæã§ããŸãã
èªçæ¥ãµãŒãã¹ã®ãã¥ãŒããªã¢ã«
To illustrate how to use Rust with Binder, weâre going to walk through the process of creating a Binder interface. Weâre then going to both implement the described service and write client code that talks to that service.
AIDL ã€ã³ã¿ãŒãã§ãŒã¹
ãµãŒãã¹ã® API ã宣èšããã«ã¯ãAIDL ã€ã³ã¿ãŒãã§ãŒã¹ã䜿çšããŸãã
birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl:
package com.example.birthdayservice;
/** èªçæ¥ãµãŒãã¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ã*/
interface IBirthdayService {
/** ããèªçæ¥ããã§ãšãããšããã¡ãã»ãŒãžãçæããŸãã*/
String wishHappyBirthday(String name, int years);
}
birthday_service/aidl/Android.bp:
aidl_interface {
name: "com.example.birthdayservice",
srcs: ["com/example/birthdayservice/*.aidl"],
unstable: true,
backend: {
rust: { // Rust ã¯ããã©ã«ãã§ã¯ç¡å¹ã§ãã
enabled: true,
},
},
}
Speaker Notes
- Note that the directory structure under the
aidl/
directory needs to match the package name used in the AIDL file, i.e. the package iscom.example.birthdayservice
and the file is ataidl/com/example/IBirthdayService.aidl
.
Generated Service API
Binder generates a trait corresponding to the interface definition. trait to talk to the service.
birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl:
/** èªçæ¥ãµãŒãã¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ã*/
interface IBirthdayService {
/** ããèªçæ¥ããã§ãšãããšããã¡ãã»ãŒãžãçæããŸãã*/
String wishHappyBirthday(String name, int years);
}
Generated trait:
trait IBirthdayService {
fn wishHappyBirthday(&self, name: &str, years: i32) -> binder::Result<String>;
}
Your service will need to implement this trait, and your client will use this trait to talk to the service.
Speaker Notes
- The generated bindings can be found at
out/soong/.intermediates/<path to module>/
. - Point out how the generated function signature, specifically the argument and return types, correspond the interface definition.
String
for an argument results in a different Rust type thanString
as a return type.
ãµãŒãã¹ã®å®è£
次ã«ãAIDL ãµãŒãã¹ãå®è£ ããŸãã
birthday_service/src/lib.rs:
use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::IBirthdayService;
use com_example_birthdayservice::binder;
/// `IBirthdayService` ã®å®è£
ã
pub struct BirthdayService;
impl binder::Interface for BirthdayService {}
impl IBirthdayService for BirthdayService {
fn wishHappyBirthday(&self, name: &str, years: i32) -> binder::Result<String> {
Ok(format!("Happy Birthday {name}, congratulations with the {years} years!"))
}
}
birthday_service/Android.bp:
rust_library {
name: "libbirthdayservice",
srcs: ["src/lib.rs"],
crate_name: "birthdayservice",
rustlibs: [
"com.example.birthdayservice-rust",
"libbinder_rs",
],
}
Speaker Notes
- Point out the path to the generated
IBirthdayService
trait, and explain why each of the segments is necessary. - TODO: What does the
binder::Interface
trait do? Are there methods to override? Where source?
AIDL ãµãŒããŒ
次ã«ããµãŒãã¹ãå ¬éãããµãŒããŒãäœæããŸãã
birthday_service/src/server.rs:
//! èªçæ¥ãµãŒãã¹ã
use birthdayservice::BirthdayService;
use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::BnBirthdayService;
use com_example_birthdayservice::binder;
const SERVICE_IDENTIFIER: &str = "birthdayservice";
/// èªçæ¥ãµãŒãã¹ã®ãšã³ã㪠ãã€ã³ãã
fn main() {
let birthday_service = BirthdayService;
let birthday_service_binder = BnBirthdayService::new_binder(
birthday_service,
binder::BinderFeatures::default(),
);
binder::add_service(SERVICE_IDENTIFIER, birthday_service_binder.as_binder())
.expect("Failed to register service");
binder::ProcessState::join_thread_pool();
}
birthday_service/Android.bp:
rust_binary {
name: "birthday_server",
crate_name: "birthday_server",
srcs: ["src/server.rs"],
rustlibs: [
"com.example.birthdayservice-rust",
"libbinder_rs",
"libbirthdayservice",
],
prefer_rlib: true, // ãã€ããã㯠ãªã³ã¯ ãšã©ãŒãåé¿ããããã§ãã
}
Speaker Notes
The process for taking a user-defined service implementation (in this case the BirthdayService
type, which implements the IBirthdayService
) and starting it as a Binder service has multiple steps, and may appear more complicated than students are used to if theyâve used Binder from C++ or another language. Explain to students why each step is necessary.
- Create an instance of your service type (
BirthdayService
). - Wrap the service object in corresponding
Bn*
type (BnBirthdayService
in this case). This type is generated by Binder and provides the common Binder functionality that would be provided by theBnBinder
base class in C++. We donât have inheritance in Rust, so instead we use composition, putting ourBirthdayService
within the generatedBnBinderService
. - Call
add_service
, giving it a service identifier and your service object (theBnBirthdayService
object in the example). - Call
join_thread_pool
to add the current thread to Binderâs thread pool and start listening for connections.
ãããã€
次ã«ããµãŒãã¹ããã«ããpushãéå§ããŸãã
m birthday_server
adb push "$ANDROID_PRODUCT_OUT/system/bin/birthday_server" /data/local/tmp
adb root
adb shell /data/local/tmp/birthday_server
å¥ã®ã¿ãŒããã«ã§ããµãŒãã¹ãå®è¡ãããŠããããšã確èªããŸãã
adb shell service check birthdayservice
Service birthdayservice: found
service call
ã䜿çšããŠãµãŒãã¹ãåŒã³åºãããšãã§ããŸãã
adb shell service call birthdayservice 1 s16 Bob i32 24
Result: Parcel(
0x00000000: 00000000 00000036 00610048 00700070 '....6...H.a.p.p.'
0x00000010: 00200079 00690042 00740072 00640068 'y. .B.i.r.t.h.d.'
0x00000020: 00790061 00420020 0062006f 0020002c 'a.y. .B.o.b.,. .'
0x00000030: 006f0063 0067006e 00610072 00750074 'c.o.n.g.r.a.t.u.'
0x00000040: 0061006c 00690074 006e006f 00200073 'l.a.t.i.o.n.s. .'
0x00000050: 00690077 00680074 00740020 00650068 'w.i.t.h. .t.h.e.'
0x00000060: 00320020 00200034 00650079 00720061 ' .2.4. .y.e.a.r.'
0x00000070: 00210073 00000000 's.!..... ')
AIDL ã¯ã©ã€ã¢ã³ã
ããããããã§ãæ°ãããµãŒãã¹çšã® Rust ã¯ã©ã€ã¢ã³ããäœæããŸãã
birthday_service/src/client.rs:
use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::IBirthdayService;
use com_example_birthdayservice::binder;
const SERVICE_IDENTIFIER: &str = "birthdayservice";
/// èªçæ¥ãµãŒãã¹ãåŒã³åºããŸãã
fn main() -> Result<(), Box<dyn Error>> {
let name = std::env::args().nth(1).unwrap_or_else(|| String::from("Bob"));
let years = std::env::args()
.nth(2)
.and_then(|arg| arg.parse::<i32>().ok())
.unwrap_or(42);
binder::ProcessState::start_thread_pool();
let service = binder::get_interface::<dyn IBirthdayService>(SERVICE_IDENTIFIER)
.map_err(|_| "Failed to connect to BirthdayService")?;
// Call the service.
let msg = service.wishHappyBirthday(&name, years)?;
println!("{msg}");
}
birthday_service/Android.bp:
rust_binary {
name: "birthday_client",
crate_name: "birthday_client",
srcs: ["src/client.rs"],
rustlibs: [
"com.example.birthdayservice-rust",
"libbinder_rs",
],
prefer_rlib: true, // ãã€ããã㯠ãªã³ã¯ ãšã©ãŒãåé¿ããããã§ãã
}
ã¯ã©ã€ã¢ã³ãã libbirthdayservice
ã«äŸåããŠããªãããšã«æ³šç®ããŠãã ããã
ããã€ã¹ã§ã¯ã©ã€ã¢ã³ãããã«ããpushãå®è¡ããŸãã
m birthday_client
adb push "$ANDROID_PRODUCT_OUT/system/bin/birthday_client" /data/local/tmp
adb shell /data/local/tmp/birthday_client Charlie 60
Happy Birthday Charlie, congratulations with the 60 years!
Speaker Notes
Strong<dyn IBirthdayService>
is the trait object representing the service that the client has connected to.Strong
is a custom smart pointer type for Binder. It handles both an in-process ref count for the service trait object, and the global Binder ref count that tracks how many processes have a reference to the object.- Note that the trait object that the client uses to talk to the service uses the exact same trait that the server implements. For a given Binder interface, there is a single Rust trait generated that both client and server use.
- Use the same service identifier used when registering the service. This should ideally be defined in a common crate that both the client and server can depend on.
APIã®å€æŽ
APIãæ¡åŒµããŠãã¯ã©ã€ã¢ã³ããèªçæ¥ã«ãŒãã«è¿œå ããè€æ°è¡ã®ã¡ãã»ãŒãžãæå®ã§ããããã«ããŸãã
package com.example.birthdayservice;
/** èªçæ¥ãµãŒãã¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ã*/
interface IBirthdayService {
/** ããèªçæ¥ããã§ãšãããšããã¡ãã»ãŒãžãçæããŸãã*/
String wishHappyBirthday(String name, int years, in String[] text);
}
This results in an updated trait definition for IBirthdayService
:
trait IBirthdayService {
fn wishHappyBirthday(
&self,
name: &str,
years: i32,
text: &[String],
) -> binder::Result<String>;
}
Speaker Notes
- Note how the
String[]
in the AIDL definition is translated as a&[String]
in Rust, i.e. that idiomatic Rust types are used in the generated bindings wherever possible:in
array arguments are translated to slices.out
andinout
args are translated to&mut Vec<T>
.- Return values are translated to returning a
Vec<T>
.
Updating Client and Service
Update the client and server code to account for the new API.
birthday_service/src/lib.rs:
impl IBirthdayService for BirthdayService {
fn wishHappyBirthday(
&self,
name: &str,
years: i32,
text: &[String],
) -> binder::Result<String> {
let mut msg = format!(
"Happy Birthday {name}, congratulations with the {years} years!",
);
for line in text {
msg.push('\n');
msg.push_str(line);
}
Ok(msg)
}
}
birthday_service/src/client.rs:
let msg = service.wishHappyBirthday(
&name,
years,
&[
String::from("Habby birfday to yuuuuu"),
String::from("And also: many more"),
],
)?;
Speaker Notes
- TODO: Move code snippets into project files where theyâll actually be built?
Working With AIDL Types
AIDL types translate into the appropriate idiomatic Rust type:
- Primitive types map (mostly) to idiomatic Rust types.
- Collection types like slices,
Vec
s and string types are supported. - References to AIDL objects and file handles can be sent between clients and services.
- File handles and parcelables are fully supported.
Primitive Types
Primitive types map (mostly) idiomatically:
AIDL Type | Rust å | Note |
---|---|---|
boolean | bool | |
byte | i8 | Note that bytes are signed. |
char | u16 | Note the usage of u16 , NOT u32 . |
int | i32 | |
long | i64 | |
float | f32 | |
double | f64 | |
String | String |
é åå
The array types (T[]
, byte[]
, and List<T>
) get translated to the appropriate Rust array type depending on how they are used in the function signature:
Position | Rust å |
---|---|
in argument | &[T] |
out /inout argument | &mut Vec<T> |
Return | Vec<T> |
Speaker Notes
- In Android 13 or higher, fixed-size arrays are supported, i.e.
T[N]
becomes[T; N]
. Fixed-size arrays can have multiple dimensions (e.g.int[3][4]
). In the Java backend, fixed-size arrays are represented as array types. - Arrays in parcelable fields always get translated to
Vec<T>
.
ãªããžã§ã¯ãã®éä¿¡
AIDL objects can be sent either as a concrete AIDL type or as the type-erased IBinder
interface:
birthday_service/aidl/com/example/birthdayservice/IBirthdayInfoProvider.aidl:
package com.example.birthdayservice;
interface IBirthdayInfoProvider {
String name();
int years();
}
birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl:
import com.example.birthdayservice.IBirthdayInfoProvider;
interface IBirthdayService {
/** The same thing, but using a binder object. */
String wishWithProvider(IBirthdayInfoProvider provider);
/** The same thing, but using `IBinder`. */
String wishWithErasedProvider(IBinder provider);
}
birthday_service/src/client.rs:
/// Rust struct implementing the `IBirthdayInfoProvider` interface.
struct InfoProvider {
name: String,
age: u8,
}
impl binder::Interface for InfoProvider {}
impl IBirthdayInfoProvider for InfoProvider {
fn name(&self) -> binder::Result<String> {
Ok(self.name.clone())
}
fn years(&self) -> binder::Result<i32> {
Ok(self.age as i32)
}
}
fn main() {
binder::ProcessState::start_thread_pool();
let service = connect().expect("Failed to connect to BirthdayService");
// Create a binder object for the `IBirthdayInfoProvider` interface.
let provider = BnBirthdayInfoProvider::new_binder(
InfoProvider { name: name.clone(), age: years as u8 },
BinderFeatures::default(),
);
// Send the binder object to the service.
service.wishWithProvider(&provider)?;
// Perform the same operation but passing the provider as an `SpIBinder`.
service.wishWithErasedProvider(&provider.as_binder())?;
}
Speaker Notes
- Note the usage of
BnBirthdayInfoProvider
. This serves the same purpose asBnBirthdayService
that we saw previously.
Parcelables
Binder for Rust supports sending parcelables directly:
birthday_service/aidl/com/example/birthdayservice/BirthdayInfo.aidl:
package com.example.birthdayservice;
parcelable BirthdayInfo {
String name;
int years;
}
birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl:
import com.example.birthdayservice.BirthdayInfo;
interface IBirthdayService {
/** The same thing, but with a parcelable. */
String wishWithInfo(in BirthdayInfo info);
}
birthday_service/src/client.rs:
fn main() {
binder::ProcessState::start_thread_pool();
let service = connect().expect("Failed to connect to BirthdayService");
let info = BirthdayInfo { name: "Alice".into(), years: 123 };
service.wishWithInfo(&info)?;
}
Sending Files
Files can be sent between Binder clients/servers using the ParcelFileDescriptor
type:
birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl:
interface IBirthdayService {
/** The same thing, but loads info from a file. */
String wishFromFile(in ParcelFileDescriptor infoFile);
}
birthday_service/src/client.rs:
fn main() {
binder::ProcessState::start_thread_pool();
let service = connect().expect("Failed to connect to BirthdayService");
// Open a file and put the birthday info in it.
let mut file = File::create("/data/local/tmp/birthday.info").unwrap();
writeln!(file, "{name}")?;
writeln!(file, "{years}")?;
// Create a `ParcelFileDescriptor` from the file and send it.
let file = ParcelFileDescriptor::new(file);
service.wishFromFile(&file)?;
}
birthday_service/src/lib.rs:
impl IBirthdayService for BirthdayService {
fn wishFromFile(
&self,
info_file: &ParcelFileDescriptor,
) -> binder::Result<String> {
// Convert the file descriptor to a `File`. `ParcelFileDescriptor` wraps
// an `OwnedFd`, which can be cloned and then used to create a `File`
// object.
let mut info_file = info_file
.as_ref()
.try_clone()
.map(File::from)
.expect("Invalid file handle");
let mut contents = String::new();
info_file.read_to_string(&mut contents).unwrap();
let mut lines = contents.lines();
let name = lines.next().unwrap();
let years: i32 = lines.next().unwrap().parse().unwrap();
Ok(format!("Happy Birthday {name}, congratulations with the {years} years!"))
}
}
Speaker Notes
ParcelFileDescriptor
wraps anOwnedFd
, and so can be created from aFile
(or any other type that wraps anOwnedFd
), and can be used to create a newFile
handle on the other side.- Other types of file descriptors can be wrapped and sent, e.g. TCP, UDP, and UNIX sockets.
Testing in Android
Building on Testing, we will now look at how unit tests work in AOSP. Use the rust_test
module for your unit tests:
testing/Android.bp:
rust_library {
name: "libleftpad",
crate_name: "leftpad",
srcs: ["src/lib.rs"],
}
rust_test {
name: "libleftpad_test",
crate_name: "leftpad_test",
srcs: ["src/lib.rs"],
host_supported: true,
test_suites: ["general-tests"],
}
testing/src/lib.rs:
You can now run the test with
atest --host libleftpad_test
The output looks like this:
INFO: Elapsed time: 2.666s, Critical Path: 2.40s
INFO: 3 processes: 2 internal, 1 linux-sandbox.
INFO: Build completed successfully, 3 total actions
//comprehensive-rust-android/testing:libleftpad_test_host PASSED in 2.3s
PASSED libleftpad_test.tests::long_string (0.0s)
PASSED libleftpad_test.tests::short_string (0.0s)
Test cases: finished with 2 passing and 0 failing out of 2 test cases
Notice how you only mention the root of the library crate. Tests are found recursively in nested modules.
GoogleTest
GoogleTest ã¯ã¬ãŒãã«ããããããã£ãŒã䜿çšããæè»ãªãã¹ã ã¢ãµãŒã·ã§ã³ãå¯èœã«ãªããŸãã
use googletest::prelude::*;
#[googletest::test]
fn test_elements_are() {
let value = vec!["foo", "bar", "baz"];
expect_that!(value, elements_are!(eq(&"foo"), lt(&"xyz"), starts_with("b")));
}
æåŸã®èŠçŽ ã "!"
ã«å€æŽãããšããã¹ãã¯å€±æãããšã©ãŒç®æã瀺ãæ§é åããããšã©ãŒ ã¡ãã»ãŒãžã衚瀺ãããŸãã
---- test_elements_are stdout ----
Value of: value
Expected: has elements:
0. is equal to "foo"
1. is less than "xyz"
2. starts with prefix "!"
Actual: ["foo", "bar", "baz"],
where element #2 is "baz", which does not start with "!"
at src/testing/googletest.rs:6:5
Error: See failure output above
Speaker Notes
This slide should take about 5 minutes.
-
GoogleTest 㯠Rust ãã¬ã€ã°ã©ãŠã³ãã®äžéšã§ã¯ãªãããããã®äŸã¯ããŒã«ã«ç°å¢ã§å®è¡ããå¿ èŠããããŸãã
cargo add googletest
ã䜿çšããŠãæ¢åã® Cargo ãããžã§ã¯ãã«ãã°ããè¿œå ããŸãã -
use googletest::prelude::*;
è¡ã¯ãäžè¬çã«äœ¿çšããããã¯ããšåãã€ã³ããŒãããŸãã -
This just scratches the surface, there are many builtin matchers. Consider going through the first chapter of âAdvanced testing for Rust applicationsâ, a self-guided Rust course: it provides a guided introduction to the library, with exercises to help you get comfortable with
googletest
macros, its matchers and its overall philosophy. -
A particularly nice feature is that mismatches in multi-line strings are shown as a diff:
#[test]
fn test_multiline_string_diff() {
let haiku = "Memory safety found,\n\
Rust's strong typing guides the way,\n\
Secure code you'll write.";
assert_that!(
haiku,
eq("Memory safety found,\n\
Rust's silly humor guides the way,\n\
Secure code you'll write.")
);
}
ããã«ãããå·®åãè²åããããŸãïŒããã§ã¯è²åããããŠããŸããïŒã
Value of: haiku
Expected: is equal to "Memory safety found,\nRust's silly humor guides the way,\nSecure code you'll write."
Actual: "Memory safety found,\nRust's strong typing guides the way,\nSecure code you'll write.",
which isn't equal to "Memory safety found,\nRust's silly humor guides the way,\nSecure code you'll write."
Difference(-actual / +expected):
Memory safety found,
-Rust's strong typing guides the way,
+Rust's silly humor guides the way,
Secure code you'll write.
at src/testing/googletest.rs:17:5
- ãã®ã¯ã¬ãŒã㯠GoogleTest for C++ ãRustã«ç§»æ€ãããã®ã§ãã
ã¢ãã¯
ã¢ãã¯ã«ã¯ãMockall ãšããã©ã€ãã©ãªãåºã䜿çšãããŠããŸãããã¬ã€ãã䜿çšããããã«ã³ãŒãããªãã¡ã¯ã¿ãªã³ã°ããå¿ èŠããããŸããããã«ãããããã«ã¢ãã¯ã§ããããã«ãªããŸãã
use std::time::Duration;
#[mockall::automock]
pub trait Pet {
fn is_hungry(&self, since_last_meal: Duration) -> bool;
}
#[test]
fn test_robot_dog() {
let mut mock_dog = MockPet::new();
mock_dog.expect_is_hungry().return_const(true);
assert_eq!(mock_dog.is_hungry(Duration::from_secs(10)), true);
}
Speaker Notes
This slide should take about 5 minutes.
-
Mockall is the recommended mocking library in Android (AOSP). There are other mocking libraries available on crates.io, in particular in the area of mocking HTTP services. The other mocking libraries work in a similar fashion as Mockall, meaning that they make it easy to get a mock implementation of a given trait.
-
ã¢ãã¯ã䜿çšããéã¯å°ã泚æãå¿ èŠã§ããã¢ãã¯ã䜿çšãããšããã¹ããäŸåé¢ä¿ããå®å šã«åé¢ã§ããŸãããã®çµæãããé«éã§å®å®ãããã¹ãå®è¡ãå¯èœã«ãªããŸããäžæ¹ãã¢ãã¯ã誀ã£ãŠæ§æãããå®éã®äŸåé¢ä¿ã®åäœãšã¯ç°ãªãåºåãè¿ãããå¯èœæ§ããããŸãã
å¯èœãªéããå®éã®äŸåé¢ä¿ã䜿çšããããšãããããããŸããããšãã°ãå€ãã®ããŒã¿ããŒã¹ã§ã¯ã€ã³ã¡ã¢ãª ããã¯ãšã³ããæ§æã§ããŸããã€ãŸãããã¹ãã§æ£ããåäœãåŸããããããé«éã§ããã¹ãåŸã¯èªåçã«ã¯ãªãŒã³ã¢ãããããŸãã
åæ§ã«ãå€ãã®ãŠã§ã ãã¬ãŒã ã¯ãŒã¯ã§ã¯ã
localhost
äžã®ã©ã³ãã ãªããŒãã«ãã€ã³ãããããã»ã¹å ãµãŒããŒãèµ·åã§ããŸãããã®ãããªæ§æã¯å®éã®ç°å¢ã§ã³ãŒãããã¹ãããããšãå¯èœã«ããã®ã§ããã¬ãŒã ã¯ãŒã¯ãã¢ãã¯ããããšãããåžžã«åªå ããŠå©çšããŸãããã -
Mockall 㯠Rust ãã¬ã€ã°ã©ãŠã³ãã®äžéšã§ã¯ãªãããããã®äŸã¯ããŒã«ã«ç°å¢ã§å®è¡ããå¿ èŠããããŸãã
cargo add mockall
ã䜿çšããŠãMockall ãæ¢åã® Cargo ãããžã§ã¯ãã«ãã°ããè¿œå ããŸãã -
Mockall ã«ã¯ããã«å€ãã®æ©èœããããŸããç¹ã«ãæž¡ãããåŒæ°ã«å¿ããŠæåŸ å€ãèšå®ã§ããŸããããã§ã¯ãæåŸã«é€ãäžããŠãããŠãã 3 æéåŸã«ç©ºè ¹ã«ãªãç«ãã¢ãã¯ããããã«ããã䜿çšããŸãã
#[test]
fn test_robot_cat() {
let mut mock_cat = MockPet::new();
mock_cat
.expect_is_hungry()
.with(mockall::predicate::gt(Duration::from_secs(3 * 3600)))
.return_const(true);
mock_cat.expect_is_hungry().return_const(false);
assert_eq!(mock_cat.is_hungry(Duration::from_secs(1 * 3600)), false);
assert_eq!(mock_cat.is_hungry(Duration::from_secs(5 * 3600)), true);
}
.times(n)
ã䜿çšãããšãã¢ãã¯ã¡ãœãããåŒã³åºãããåæ°ãn
ã«å¶éã§ããŸãããããæºããããªãå Žåãã¢ãã¯ã¯ããããæã«èªåçã«ãããã¯ã«ãªããŸãã
ãã°åºå
log
ã¯ã¬ãŒãã䜿çšããŠãèªåçã« ïŒããã€ã¹äžã§ã¯ïŒlogcat
ãŸã㯠ïŒãã¹ãäžã§ã¯ïŒstdout
ã«ãã°ãèšé²ããããã«ããŸãã
hello_rust_logs/Android.bp:
rust_binary {
name: "hello_rust_logs",
crate_name: "hello_rust_logs",
srcs: ["src/main.rs"],
rustlibs: [
"liblog_rust",
"liblogger",
],
host_supported: true,
}
hello_rust_logs/src/main.rs:
//! Rust ãã®ã³ã°ã®ãã¢ã
use log::{debug, error, info};
/// æšæ¶ããã°ã«èšé²ããŸãã
fn main() {
logger::init(
logger::Config::default()
.with_tag_on_device("rust")
.with_max_level(log::LevelFilter::Trace),
);
debug!("Starting program.");
info!("Things are going fine.");
error!("Something went wrong!");
}
ããã€ã¹ã§ãã€ããªããã«ããpushãå®è¡ããŸãã
m hello_rust_logs
adb push "$ANDROID_PRODUCT_OUT/system/bin/hello_rust_logs" /data/local/tmp
adb shell /data/local/tmp/hello_rust_logs
adb logcat
ã§ãã°ã衚瀺ã§ããŸãã
adb logcat -s rust
09-08 08:38:32.454 2420 2420 D rust: hello_rust_logs: Starting program.
09-08 08:38:32.454 2420 2420 I rust: hello_rust_logs: Things are going fine.
09-08 08:38:32.454 2420 2420 E rust: hello_rust_logs: Something went wrong!
Speaker Notes
- The logger implementation in
liblogger
is only needed in the final binary, if youâre logging from a library you only need thelog
facade crate.
çžäºéçšæ§
Rust ã¯ä»ã®èšèªãšã®çžäºéçšæ§ã«åªããŠããããã次ã®ããšãå¯èœã§ãã
- ä»ã®èšèªãã Rust é¢æ°ãåŒã³åºãã
- Rust ããä»ã®èšèªã§èšè¿°ãããé¢æ°ãåŒã³åºãã
ä»ã®èšèªã®é¢æ°ãåŒã³åºãå Žåã¯ãå€éšé¢æ°ã€ã³ã¿ãŒãã§ãŒã¹ïŒFFI: foreign function interfaceïŒã䜿çšããŸãã
C ãšã®çžäºéçšæ§
Rust ã¯ãC ã®åŒã³åºãèŠåã«ãããªããžã§ã¯ã ãã¡ã€ã«ã®ãªã³ã¯ãå®å šã«ãµããŒãããŠããŸããåæ§ã«ãRust é¢æ°ããšã¯ã¹ããŒãã㊠C ããåŒã³åºãããšãã§ããŸãã
ããã¯æåã§è¡ãããšãã§ããŸãã
unsafe extern "C" {
safe fn abs(x: i32) -> i32;
}
fn main() {
let x = -42;
let abs_x = abs(x);
println!("{x}, {abs_x}");
}
We already saw this in the Safe FFI Wrapper exercise.
ããã¯ãã¿ãŒã²ãã ãã©ãããã©ãŒã ãå®å šã«ç解ããŠããããšãåæãšããŠããŸããæ¬çªç°å¢ã§ã®äœ¿çšæšå¥šãããŸããã
次ã«ãããè¯ãéžæè¢ãèŠãŠãããŸãã
Bindgen ã®äœ¿çš
bindgen ããŒã«ã䜿çšãããšãC ããã㌠ãã¡ã€ã«ãããã€ã³ãã£ã³ã°ãèªåçæã§ããŸãã
ãŸããå°ã㪠C ã©ã€ãã©ãªãäœæããŸãã
interoperability/bindgen/libbirthday.h:
typedef struct card {
const char* name;
int years;
} card;
void print_card(const card* card);
interoperability/bindgen/libbirthday.c:
#include <stdio.h>
#include "libbirthday.h"
void print_card(const card* card) {
printf("+--------------\n");
printf("| Happy Birthday %s!\n", card->name);
printf("| Congratulations with the %i years!\n", card->years);
printf("+--------------\n");
}
ããã Android.bp
ãã¡ã€ã«ã«è¿œå ããŸãã
interoperability/bindgen/Android.bp:
cc_library {
name: "libbirthday",
srcs: ["libbirthday.c"],
}
ã©ã€ãã©ãªã®ã©ãã㌠ããã㌠ãã¡ã€ã«ãäœæããŸãïŒãã®äŸã§ã¯å¿ é ã§ã¯ãããŸããïŒã
interoperability/bindgen/libbirthday_wrapper.h:
#include "libbirthday.h"
ããã§ããã€ã³ãã£ã³ã°ãèªåçæã§ããŸãã
interoperability/bindgen/Android.bp:
rust_bindgen {
name: "libbirthday_bindgen",
crate_name: "birthday_bindgen",
wrapper_src: "libbirthday_wrapper.h",
source_stem: "bindings",
static_libs: ["libbirthday"],
}
ããã§ãRust ããã°ã©ã ã§ãã€ã³ãã£ã³ã°ã䜿çšã§ããŸãã
interoperability/bindgen/Android.bp:
rust_binary {
name: "print_birthday_card",
srcs: ["main.rs"],
rustlibs: ["libbirthday_bindgen"],
}
interoperability/bindgen/main.rs:
//! Bindgen ã®ãã¢ã
use birthday_bindgen::{card, print_card};
fn main() {
let name = std::ffi::CString::new("Peter").unwrap();
let card = card { name: name.as_ptr(), years: 42 };
// SAFETY: The pointer we pass is valid because it came from a Rust
// reference, and the `name` it contains refers to `name` above which also
// remains valid. `print_card` doesn't store either pointer to use later
// after it returns.
unsafe {
print_card(&card as *const card);
}
}
ããã€ã¹ã§ãã€ããªããã«ããpushãå®è¡ããŸãã
m print_birthday_card
adb push "$ANDROID_PRODUCT_OUT/system/bin/print_birthday_card" /data/local/tmp
adb shell /data/local/tmp/print_birthday_card
ããã§ãèªåçæããããã¹ããå®è¡ããŠããã€ã³ãã£ã³ã°ãæ©èœããŠããããšã確èªã§ããŸãã
interoperability/bindgen/Android.bp:
rust_test {
name: "libbirthday_bindgen_test",
srcs: [":libbirthday_bindgen"],
crate_name: "libbirthday_bindgen_test",
test_suites: ["general-tests"],
auto_gen_config: true,
clippy_lints: "none", // çæããããã¡ã€ã«ãlint ãã§ãã¯ãã¹ããã
lints: "none",
}
atest libbirthday_bindgen_test
Rust ã®åŒã³åºã
Rust ã®é¢æ°ãšåã¯ãC ã«ç°¡åã«ãšã¯ã¹ããŒãã§ããŸãã
interoperability/rust/libanalyze/analyze.rs
interoperability/rust/libanalyze/analyze.h
#ifndef ANALYSE_H
#define ANALYSE_H
void analyze_numbers(int x, int y);
#endif
interoperability/rust/libanalyze/Android.bp
rust_ffi {
name: "libanalyze_ffi",
crate_name: "analyze_ffi",
srcs: ["analyze.rs"],
include_dirs: ["."],
}
ããã§ãããã C ãã€ããªããåŒã³åºããããã«ãªããŸããã
interoperability/rust/analyze/main.c
#include "analyze.h"
int main() {
analyze_numbers(10, 20);
analyze_numbers(123, 123);
return 0;
}
interoperability/rust/analyze/Android.bp
cc_binary {
name: "analyze_numbers",
srcs: ["main.c"],
static_libs: ["libanalyze_ffi"],
}
ããã€ã¹ã§ãã€ããªããã«ããpushãå®è¡ããŸãã
m analyze_numbers
adb push "$ANDROID_PRODUCT_OUT/system/bin/analyze_numbers" /data/local/tmp
adb shell /data/local/tmp/analyze_numbers
Speaker Notes
#[unsafe(no_mangle)]
disables Rustâs usual name mangling, so the exported symbol will just be the name of the function. You can also use #[unsafe(export_name = "some_name")]
to specify whatever name you want.
C++
CXX ã¯ã¬ãŒãã䜿çšãããšãRust ãš C++ ã®éã§å®å šãªçžäºéçšæ§ã確ä¿ã§ããŸãã
å šäœçãªã¢ãããŒãã¯æ¬¡ã®ããã«ãªããŸãã
ããªããžã¢ãžã¥ãŒã«
CXX ã¯ãåèšèªããä»ã®èšèªã«å
¬éãããé¢æ°ã·ã°ããã£ã®èšè¿°ã«äŸåããŸãããã®èšè¿°ã¯ã#[cxx::bridge]
å±æ§ãã¯ãã§ã¢ãããŒã·ã§ã³ããã Rust ã¢ãžã¥ãŒã«å
ã® extern ãããã¯ã䜿çšããŠæå®ããŸãã
#[allow(unsafe_op_in_unsafe_fn)]
#[cxx::bridge(namespace = "org::blobstore")]
mod ffi {
// äž¡æ¹ã®èšèªããã¢ã¯ã»ã¹ã§ãããã£ãŒã«ããæã€å
±ææ§é äœã
struct BlobMetadata {
size: usize,
tags: Vec<String>,
}
// C++ ã«å
¬éããã Rust ã®åãšã·ã°ããã£ã
extern "Rust" {
type MultiBuf;
fn next_chunk(buf: &mut MultiBuf) -> &[u8];
}
// Rust ã«å
¬éããã C++ ã®åãšã·ã°ããã£ã
unsafe extern "C++" {
include!("include/blobstore.h");
type BlobstoreClient;
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
fn put(self: Pin<&mut BlobstoreClient>, parts: &mut MultiBuf) -> u64;
fn tag(self: Pin<&mut BlobstoreClient>, blobid: u64, tag: &str);
fn metadata(&self, blobid: u64) -> BlobMetadata;
}
}
Speaker Notes
- ããªããžã¯éåžžãã¯ã¬ãŒãå
ã®
ffi
ã¢ãžã¥ãŒã«ã§å®£èšããŸãã - ããªããž ã¢ãžã¥ãŒã«ã§è¡ããã宣èšãããCXX ã¯ããããã Rust ãš C++ ã®å / é¢æ°ã®å®çŸ©ãçæãããããã®ã¢ã€ãã ãäž¡æ¹ã®èšèªã«å ¬éããŸãã
- çæããã Rust ã³ãŒãã衚瀺ããã«ã¯ãcargo-expand ã䜿çšããŠãå±éããã proc ãã¯ãã衚瀺ããŸããã»ãšãã©ã®äŸã§ã¯ã
cargo expand ::ffi
ã䜿çšããŠffi
ã¢ãžã¥ãŒã«ã®ã¿ãå±éããŸãïŒãã ãããã㯠Android ãããžã§ã¯ãã«ã¯åœãŠã¯ãŸããŸããïŒã - çæããã C++ ã³ãŒãã衚瀺ããã«ã¯ã
target/cxxbridge
ã確èªããŸãã
Rust ã®ããªããžå®£èš
#[cxx::bridge]
mod ffi {
extern "Rust" {
type MyType; // ãªããŒã¯å
fn foo(&self); // `MyType` ã®ã¡ãœãã
fn bar() -> Box<MyType>; // Free function
}
}
struct MyType(i32);
impl MyType {
fn foo(&self) {
println!("{}", self.0);
}
}
fn bar() -> Box<MyType> {
Box::new(MyType(123))
}
Speaker Notes
- 芪ã¢ãžã¥ãŒã«ã®ã¹ã³ãŒãå
ã«ãã
extern "Rust"
åç §ã¢ã€ãã ã§å®£èšãããã¢ã€ãã ã - CXX ã³ãŒã ãžã§ãã¬ãŒã¿ã¯ã
extern "Rust"
ã»ã¯ã·ã§ã³ã䜿çšããŠã察å¿ãã C++ 宣èšãå«ã C++ ããã㌠ãã¡ã€ã«ãçæããŸããçæãããããããŒã®ãã¹ã¯ãrs.hãšãããã¡ã€ã«æ¡åŒµåéšåãé€ããããªããžãå«ã Rust ãœãŒã¹ãã¡ã€ã«ãšåãã«ãªããŸãã
çæããã C++
#[cxx::bridge]
mod ffi {
// C++ ã«å
¬éããã Rust ã®åãšã·ã°ããã£ã
extern "Rust" {
type MultiBuf;
fn next_chunk(buf: &mut MultiBuf) -> &[u8];
}
}
ãããã次ã®ãã㪠C++ ãçæãããŸãã
struct MultiBuf final : public ::rust::Opaque {
~MultiBuf() = delete;
private:
friend ::rust::layout;
struct layout {
static ::std::size_t size() noexcept;
static ::std::size_t align() noexcept;
};
};
::rust::Slice<::std::uint8_t const> next_chunk(::org::blobstore::MultiBuf &buf) noexcept;
C++ ã®ããªããžå®£èš
#[cxx::bridge]
mod ffi {
// Rust ã«å
¬éããã C++ ã®åãšã·ã°ããã£ã
unsafe extern "C++" {
include!("include/blobstore.h");
type BlobstoreClient;
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
fn put(self: Pin<&mut BlobstoreClient>, parts: &mut MultiBuf) -> u64;
fn tag(self: Pin<&mut BlobstoreClient>, blobid: u64, tag: &str);
fn metadata(&self, blobid: u64) -> BlobMetadata;
}
}
ãããã次ã®ãã㪠Rust ãçæãããŸãã
#[repr(C)]
pub struct BlobstoreClient {
_private: ::cxx::private::Opaque,
}
pub fn new_blobstore_client() -> ::cxx::UniquePtr<BlobstoreClient> {
extern "C" {
#[link_name = "org$blobstore$cxxbridge1$new_blobstore_client"]
fn __new_blobstore_client() -> *mut BlobstoreClient;
}
unsafe { ::cxx::UniquePtr::from_raw(__new_blobstore_client()) }
}
impl BlobstoreClient {
pub fn put(&self, parts: &mut MultiBuf) -> u64 {
extern "C" {
#[link_name = "org$blobstore$cxxbridge1$BlobstoreClient$put"]
fn __put(
_: &BlobstoreClient,
parts: *mut ::cxx::core::ffi::c_void,
) -> u64;
}
unsafe {
__put(self, parts as *mut MultiBuf as *mut ::cxx::core::ffi::c_void)
}
}
}
// ...
Speaker Notes
- ããã°ã©ããŒã¯ãå ¥åããã·ã°ããã£ãæ£ç¢ºã§ããããšãä¿èšŒããå¿ èŠã¯ãããŸãããCXX ã¯ãã·ã°ããã£ã C++ ã§å®£èšããããã®ãšå®å šã«å¯Ÿå¿ãããšããããšãéçã«ä¿èšŒããŸãã
unsafe extern
ãããã¯ã䜿çšãããšãRust ããå®å šã«åŒã³åºãã C++ é¢æ°ã宣èšã§ããŸãã
å ±æã®å
#[cxx::bridge]
mod ffi {
#[derive(Clone, Debug, Hash)]
struct PlayingCard {
suit: Suit,
value: u8, // A=1ãJ=11ãQ=12ãK=13
}
enum Suit {
Clubs,
Diamonds,
Hearts,
Spades,
}
}
Speaker Notes
- C ã®ãããªïŒåäœïŒåæåã®ã¿ããµããŒããããŠããŸãã
- å
±æåã®
#[derive()]
ã§ã¯ããµããŒãããããã¬ã€ãã®æ°ãéãããŠããŸãã察å¿ããæ©èœã¯ C++ ã³ãŒãã§ãçæãããŸããããšãã°ãHash
ãå°åºãããšã察å¿ãã C++ åã®std::hash
ã®å®è£ ãçæãããŸãã
å ±æã®åæå
#[cxx::bridge]
mod ffi {
enum Suit {
Clubs,
Diamonds,
Hearts,
Spades,
}
}
çæããã Rust:
çæããã C++:
enum class Suit : uint8_t {
Clubs = 0,
Diamonds = 1,
Hearts = 2,
Spades = 3,
};
Speaker Notes
- Rust åŽã§ã¯ãå ±æåæåã«å¯ŸããŠçæãããã³ãŒãã¯ãå®éã«ã¯æ°å€ãã©ããããæ§é äœã§ããããã¯ãåæåã¯ã©ã¹ããªã¹ãããããã¹ãŠã®ããªã¢ã³ããšã¯ç°ãªãå€ãä¿æããããšã¯ C++ ã§ã¯ UB ã§ã¯ãªããRust è¡šçŸã¯åãåäœãããå¿ èŠãããããã§ãã
Rustã®ãšã©ãŒåŠç
#[cxx::bridge]
mod ffi {
extern "Rust" {
fn fallible(depth: usize) -> Result<String>;
}
}
fn fallible(depth: usize) -> anyhow::Result<String> {
if depth == 0 {
return Err(anyhow::Error::msg("fallible1 requires depth > 0"));
}
Ok("Success!".into())
}
Speaker Notes
Result
ãè¿ã Rust é¢æ°ã¯ãC++ åŽã§äŸå€ã«å€æãããŸãã- ã¹ããŒãããäŸå€ã¯åžžã«
rust::Error
åã§ãäž»ã«ãšã©ãŒ ã¡ãã»ãŒãžã®æååãååŸããæ段ãæäŸããŸãããšã©ãŒ ã¡ãã»ãŒãžã¯ããšã©ãŒåã®Display
ã®å®è£ ããååŸãããŸãã - Rust ãã C++ ã«ããã㯠ã¢ã³ã¯ã€ã³ããè¡ããšãããã»ã¹ã¯å¿ ãçŽã¡ã«çµäºããŸãã
C++ã®ãšã©ãŒåŠç
#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
include!("example/include/example.h");
fn fallible(depth: usize) -> Result<String>;
}
}
fn main() {
if let Err(err) = ffi::fallible(99) {
eprintln!("Error: {}", err);
process::exit(1);
}
}
Speaker Notes
Result
ãè¿ãããã«å®£èšããã C++ é¢æ°ã¯ãC++ åŽã§ã¹ããŒãããããããäŸå€ããã£ããããåŒã³åºãå ã® Rust é¢æ°ã«Err
å€ãšããŠè¿ããŸãã- CXX ããªããžã§Resultãè¿ãããã«å®£èšãããŠããªãextern âC++âé¢æ°ããäŸå€ãã¹ããŒããããšã
Result
ãè¿ããããšãããã°ã©ã 㯠C++ ã®std::terminate
ãåŒã³åºããŸãããã®åäœã¯ãåãäŸå€ãnoexcept
C++ é¢æ°ã§ã¹ããŒãããå Žåãšåçã§ãã
ãã®ä»ã®å
Rust å | C++ å |
---|---|
String | rust::String |
&str | rust::Str |
CxxString | std::string |
&[T] /&mut [T] | rust::Slice |
Box<T> | rust::Box<T> |
UniquePtr<T> | std::unique_ptr<T> |
Vec<T> | rust::Vec<T> |
CxxVector<T> | std::vector<T> |
Speaker Notes
- ãããã®åã¯ãå ±ææ§é äœã®ãã£ãŒã«ããšãextern é¢æ°ã®åŒæ°ãšæ»ãå€ã§äœ¿çšã§ããŸãã
- Rust ã®
String
ã¯std::string
ã«çŽæ¥ãããã³ã°ãããŸãããããã«ã¯æ¬¡ã®ãããªçç±ããããŸããstd::string
ã¯ãString
ãå¿ èŠãšãã UTF-8 äžå€æ¡ä»¶ãæºãããŸããã- ãã® 2 ã€ã®åã¯ã¡ã¢ãªå ã®ã¬ã€ã¢ãŠããç°ãªããããèšèªéã§çŽæ¥æž¡ãããšã¯ã§ããŸããã
std::string
ã¯ãRust ã®ã ãŒã ã»ãã³ãã£ã¯ã¹ãšäžèŽããªãã ãŒãã³ã³ã¹ãã©ã¯ã¿ãå¿ èŠãšãããããstd::string
ã Rust ã«å€ã§æž¡ãããšã¯ã§ããŸããã
Building in Android
cc_library_static
ãäœæããŠãCXX ã§çæãããããããŒãšãœãŒã¹ãã¡ã€ã«ãå«ã C++ ã©ã€ãã©ãªããã«ãããŸãã
cc_library_static {
name: "libcxx_test_cpp",
srcs: ["cxx_test.cpp"],
generated_headers: [
"cxx-bridge-header",
"libcxx_test_bridge_header"
],
generated_sources: ["libcxx_test_bridge_code"],
}
Speaker Notes
libcxx_test_bridge_header
ãšlibcxx_test_bridge_code
ããCXX CXXã«ããçæããã C++ ãã€ã³ãã£ã³ã°ã«å¯ŸããäŸåé¢ä¿ã§ããããšã説æããŸãã次ã®ã¹ã©ã€ãã§ãããããã©ã®ãããªèšè¿°ã«ãªã£ãŠãããã説æããŸãã- ãŸããäžè¬ç㪠CXX å®çŸ©ãååŸããããã«ã¯ã
cxx-bridge-header
ã©ã€ãã©ãªã«äŸåããå¿ èŠãããããšã«ã泚æããŠãã ããã - Android 㧠CXX ã䜿çšããããã®è©³çŽ°ãªããã¥ã¡ã³ãã«ã€ããŠã¯ãAndroid ã®ããã¥ã¡ã³ããã芧ãã ããããã®ãªã³ã¯ãã¯ã©ã¹ãšå ±æããŠãåè¬è ãåŸã§æé ã確èªã§ããããã«ããããšãããããããŸãã
Building in Android
genrule ã 2 ã€äœæããŸãã1 ã€ã¯ CXX ããããŒã®çæçšããã 1 ã€ã¯ CXX ãœãŒã¹ãã¡ã€ã«ã®çæçšã§ããããã㯠cc_library_static
ãžã®å
¥åãšããŠäœ¿çšãããŸãã
// lib.rs ã«ãã Rustãããšã¯ã¹ããŒããããé¢æ°ã«å¯Ÿãã
// C++ ãã€ã³ãã£ã³ã°ãå«ã C++ ããããŒãçæããŸãã
genrule {
name: "libcxx_test_bridge_header",
tools: ["cxxbridge"],
cmd: "$(location cxxbridge) $(in) --header > $(out)",
srcs: ["lib.rs"],
out: ["lib.rs.h"],
}
// Rust ãåŒã³åºã C++ ã³ãŒããçæããŸãã
genrule {
name: "libcxx_test_bridge_code",
tools: ["cxxbridge"],
cmd: "$(location cxxbridge) $(in) > $(out)",
srcs: ["lib.rs"],
out: ["lib.rs.cc"],
}
Speaker Notes
cxxbridge
ããŒã«ã¯ãããªããž ã¢ãžã¥ãŒã«ã® C++ åŽãçæããã¹ã¿ã³ãã¢ãã³ ããŒã«ã§ããAndroid ã«çµã¿èŸŒãŸããŠãããSoong ããŒã«ãšããŠå©çšã§ããŸãã- æ
£äŸãšããŠãRust ãœãŒã¹ãã¡ã€ã«ã
lib.rs
ã®å Žåãããã㌠ãã¡ã€ã«ã®ååã¯lib.rs.h
ããœãŒã¹ãã¡ã€ã«ã®ååã¯lib.rs.cc
ãšãªããŸãããã ãããã®åœåèŠåã¯åŒ·å¶ã§ã¯ãããŸããã
Building in Android
libcxx
ãš cc_library_static
ã«äŸåãã rust_binary
ãäœæããŸãã
rust_binary {
name: "cxx_test",
srcs: ["lib.rs"],
rustlibs: ["libcxx"],
static_libs: ["libcxx_test_cpp"],
}
Java ãšã®çžäºéçšæ§
Java ã§ã¯ãJava Native InterfaceïŒJNIïŒ ãä»ããŠå
±æãªããžã§ã¯ããèªã¿èŸŒãããšãã§ããŸããjni
ã¯ã¬ãŒã ã䜿çšãããšãäºææ§ã®ããã©ã€ãã©ãªãäœæã§ããŸãã
ãŸããJava ã«ãšã¯ã¹ããŒããã Rust é¢æ°ãäœæããŸãã
interoperability/java/src/lib.rs:
interoperability/java/Android.bp:
rust_ffi_shared {
name: "libhello_jni",
crate_name: "hello_jni",
srcs: ["src/lib.rs"],
rustlibs: ["libjni"],
}
次ã«ãJava ãããã®é¢æ°ãåŒã³åºããŸãã
interoperability/java/HelloWorld.java:
class HelloWorld {
private static native String hello(String name);
static {
System.loadLibrary("hello_jni");
}
public static void main(String[] args) {
String output = HelloWorld.hello("Alice");
System.out.println(output);
}
}
interoperability/java/Android.bp:
java_binary {
name: "helloworld_jni",
srcs: ["HelloWorld.java"],
main_class: "HelloWorld",
required: ["libhello_jni"],
}
æåŸã«ããã€ããªããã«ããåæãå®è¡ããŸãã
m helloworld_jni
adb sync # requires adb root && adb remount
adb shell /system/bin/helloworld_jni
Chromium ã® Rust ãžãããã
Rust 㯠Chromium ã®ãµãŒãããŒã㣠ã©ã€ãã©ãªã§ãµããŒããããŠããŸããRust ãšæ¢åã® Chromium C++ ã³ãŒããæ¥ç¶ããã«ã¯ããã¡ãŒã¹ã ããŒãã£ã®ã°ã«ãŒã³ãŒãã䜿çšããŸãã
æ¬æ¥ã¯ãRust ã§æååã䜿ã£ãŠé¢çœãããšãããããšæããŸããããèªåã®æ åœéšåã«UTF8 æååã衚瀺ããã³ãŒããããå Žåã¯ãããã§è¿°ã¹ãéšåã§ã¯ãªããèªåã®ã³ãŒãã«å¯ŸããŠãã®æé ãå®è¡ããŠæ§ããŸããã
ã»ããã¢ãã
Chromium ããã«ãããŠå®è¡ã§ããããšã確èªããŸããã³ãŒããæ¯èŒçæè¿ã®ãã®ïŒ2023 幎 11 æã«å¯Ÿå¿ããã³ãããäœçœ® 1223636 以éïŒã§ããã°ãä»»æã®ãã©ãããã©ãŒã ãšãã«ããã©ã°ã®ã»ããã§åé¡ãããŸããã
gn gen out/Debug
autoninja -C out/Debug chrome
out/Debug/chrome # or on Mac, out/Debug/Chromium.app/Contents/MacOS/Chromium
ïŒå埩åŠçã®æéãæçã«ããã«ã¯ãã³ã³ããŒãã³ãã®ãããã°ãã«ããããããããŸãããããããã©ã«ãã§ãïŒ
ãŸã 確èªããŠããªãå Žåã¯ãChromium ã®ãã«ãæ¹æ³ ã確èªããŠãã ããããªããChromium ããã«ãããããã®ã»ããã¢ããã«ã¯æéãããããŸãã
ãŸããVisual Studio Code ãã€ã³ã¹ããŒã«ããŠããããšãããããããŸãã
æŒç¿ã«ã€ããŠ
ã³ãŒã¹ã®ãã®ããŒãã«ã¯ãçžäºã«é¢é£ããäžé£ã®æŒç¿ããããŸããã³ãŒã¹ã®æåŸã ãã§ãªããå šäœãéããŠæŒç¿ãè¡ããŸããç¹å®ã®ããŒããå®äºããæéããªãå ŽåããåŸã§è¿œãã€ãã°ããããå¿é ã¯ãããŸããã
Chromium ãš Cargo ã®ãšã³ã·ã¹ãã ã®æ¯èŒ
The Rust community typically uses cargo
and libraries from crates.io. Chromium is built using gn
and ninja
and a curated set of dependencies.
Rust ã§ã³ãŒããèšè¿°ããéã¯ã次ã®éžæè¢ããããŸãã
//build/rust/*.gni
ã®ãã³ãã¬ãŒãïŒäŸ: åŸã§èª¬æããrust_static_library
ïŒãåèã«ããŠãgn
ãšninja
ã䜿çšããŸããããã«ã¯ãChromium ã®ç£æ»æžã¿ã®ããŒã«ãã§ãŒã³ãšã¯ã¬ãŒãã䜿çšãããŸããcargo
ã䜿çšããŸãããå®éã®å©çšãChromium ã®ç£æ»æžã¿ã®ããŒã«ãã§ãŒã³ãšã¯ã¬ãŒãã«å¶éããŸããcargo
ã䜿çšããããŒã«ãã§ãŒã³ ã ã€ã³ã¿ãŒãããããããŠã³ããŒãããã¯ã¬ãŒã ãä¿¡é ŒããŸãã
ããããã¯ãgn
ãš ninja
ã«çŠç¹ãåœãŠãŸãããããã䜿çšããããšã§ãChromium ãã©ãŠã¶ã« Rust ã³ãŒããçµã¿èŸŒãããšãã§ããŸãããããšã¯å¥ã«ãCargo 㯠Rust ãšã³ã·ã¹ãã ã®éèŠãªéšåã§ããã䜿ãããªããããã«ãªã£ãŠããã¹ãã§ãã
Mini exercise
å°äººæ°ã®ã°ã«ãŒãã«åãã以äžãè¡ããŸãã
cargo
ãã¡ãªãããããããå¯èœæ§ã®ããã·ããªãªããã¬ã€ã³ã¹ããŒãã³ã°ãããããã®ã·ããªãªã®ãªã¹ã¯ ãããã¡ã€ã«ãè©äŸ¡ããŸããgn
ãninja
ããªãã©ã€ã³ã®cargo
ãªã©ã䜿çšããéã«ãã©ã®ããŒã«ãã©ã€ãã©ãªã人ã ãä¿¡é Œããªããã°ãªããªããã«ã€ããŠè©±ãåããŸãã
Speaker Notes
åè¬è ã«ãæŒç¿ãå®äºããåã«ã¹ããŒã«ãŒ ããŒããã®ãããªããããé¡ãããŠãã ãããã³ãŒã¹ã®åè¬è å士ãå°ççã«éãŸã£ãŠãããšä»®å®ããŠã3ïœ4 人ã®å°äººæ°ã®ã°ã«ãŒãã§è©±ãåã£ãŠãããããã«ãé¡ãããŠãã ããã
æŒç¿ã®ååã«é¢ããã¡ã¢ãšãã³ãïŒãCargo ãã¡ãªãããããããã·ããªãªãïŒ:
-
ããŒã«ã®äœææã Chromium ã®äžéšã®ãããã¿ã€ãã³ã°æã«ãcrates.io ã©ã€ãã©ãªã®å å®ãããšã³ã·ã¹ãã ã«ã¢ã¯ã»ã¹ã§ããã®ã¯çŽ æŽãããããšã§ããã»ãŒãã¹ãŠã®äºæã«ã€ããŠã¯ã¬ãŒããçšæãããŠããã倧æŠã®å Žåã¯ãšãŠãå¿«é©ã«äœ¿çšã§ããŸãïŒã³ãã³ãã©ã€ã³ã解æããããã®
clap
ãããŸããŸãªåœ¢åŒãšã®éã§ã·ãªã¢ã«åãŸãã¯éã·ãªã¢ã«åãè¡ãããã®serde
ãã€ãã¬ãŒã¿ãæäœããããã®itertools
ãªã©ïŒãcargo
ã䜿çšãããšãã©ã€ãã©ãªãç°¡åã«è©Šãããšãã§ããŸãïŒCargo.toml
ã« 1 è¡è¿œå ããŠã³ãŒãã®èšè¿°ãéå§ããã ãã§ãïŒãperl
ã®æ®åã«åœ¹ç«ã£ã CPAN ããpython
ã«ãããpip
ãšæ¯èŒããŠã¿ããšè¯ããããããŸããã
-
äž»èŠãª Rust ããŒã«ïŒãã€ããªãŒãçŸåšã®å®å®çãå€ãå®å®çã§åäœããå¿ èŠãããã¯ã¬ãŒãããã¹ããããšãã«ãå¥ã®
rustc
ããŒãžã§ã³ã«åãæ¿ããã®ã«äœ¿çšããrustup
ãªã©ïŒã ãã§ãªãããµãŒãããŒã㣠ããŒã«ã®ãšã³ã·ã¹ãã ïŒMozilla ãæäŸããã»ãã¥ãªãã£ç£æ»ã®å®¹æåãšå ±æã®ããcargo vet
ããã³ãããŒã¯ã容æã«å®è¡ããæ¹æ³ãæäŸããcriterion
ã¯ã¬ãŒããªã©ïŒã«ãããéçºãšã¯ã¹ããªãšã³ã¹ã¯éåžžã«å¿«é©ãšãªã£ãŠããŸããcargo
ã䜿çšãããšãcargo install --locked cargo-vet
ãä»ããŠããŒã«ãç°¡åã«è¿œå ã§ããŸãã- Chrome æ¡åŒµæ©èœã VScode æ¡åŒµæ©èœãšæ¯èŒããŠã¿ãã®ãè¯ããããããŸããã
-
cargo
ãé©åãªéžæãšãªããããªãå¹ åºãæ±çšçãªãããžã§ã¯ãã®äŸã以äžã«ç€ºããŸãã- æå€ãããããŸããããæ¥çã§ã¯ã³ãã³ãã©ã€ã³ ããŒã«ã®äœæã«äœ¿çšããèšèªãšããŠãRust ã®äººæ°ãé«ãŸã£ãŠããŸããã©ã€ãã©ãªã®å¹ ãšãšã«ãŽããã¯ã¹ã®ç¹ã§ Python ã«å¹æµãã€ã€ããè±å¯ãªåã·ã¹ãã ã®ãããã§å ç¢ã§ãïŒã€ã³ã¿ããªã¿èšèªã§ã¯ãªãã³ã³ãã€ã«èšèªãªã®ã§ïŒå®è¡é床ãé«éã§ãã
- Rust ãšã³ã·ã¹ãã ã«åå ããã«ã¯ãCargo ãªã©ã®æšæºã® Rust ããŒã«ã䜿çšããå¿ èŠããããŸããå€éšããã³ã³ããªãã¥ãŒã·ã§ã³ãåããChromium 以å€ïŒBazel ã Android / Soong ã®ãã«ãç°å¢ãªã©ïŒã§ã®äœ¿çšãæšå¥šãããã©ã€ãã©ãªã§ã¯ãCargo ã䜿çšããããšãããããããŸãã
-
cargo
ããŒã¹ã® Chromium é¢é£ãããžã§ã¯ãã®äŸ:serde_json_lenient
ïŒGoogle ã®ä»ã®éšéã§ãã¹ãããçµæãPR ã®ããã©ãŒãã³ã¹ãåäžïŒfont-types
ãªã©ã®ãã©ã³ãåã©ã€ãã©ãªgnrt
ããŒã«ïŒãã®ã³ãŒã¹ã®åŸåã§åãäžããŸãïŒã¯ãã³ãã³ãã©ã€ã³ã®è§£æã«ã¯clap
ã䜿çšããæ§æãã¡ã€ã«ã«ã¯toml
ã䜿çšããŸãã- Disclaimer: a unique reason for using
cargo
was unavailability ofgn
when building and bootstrapping Rust standard library when building Rust toolchain. run_gnrt.py
uses Chromiumâs copy ofcargo
andrustc
.gnrt
depends on third-party libraries downloaded from the internet, butrun_gnrt.py
askscargo
that only--locked
content is allowed viaCargo.lock
.)
- Disclaimer: a unique reason for using
以äžã®ã¢ã€ãã ã¯ãæé»çãŸãã¯æ瀺çã«ä¿¡é ŒãããŠãããšã¿ãªããŠæ§ããŸããã
- LLVM ã©ã€ãã©ãªãClang ã³ã³ãã€ã©ã
rustc
ãœãŒã¹ïŒGitHub ããååŸãããRust ã³ã³ãã€ã© ããŒã ã«ããã¬ãã¥ãŒãåãããã®ïŒãããŒãã¹ãã©ããçšã«ããŠã³ããŒãããããã€ã㪠Rust ã³ã³ãã€ã©ã«äŸåããrustc
ïŒRust ã³ã³ãã€ã©ïŒ rustup
ïŒrustup
ã¯rustc
ãšåãã https://github.com/rust-lang/ çµç¹ã®åäžã§éçºãããŠããããšã説æãããšè¯ããããããŸããïŒcargo
ãrustfmt
ãªã©- ããŸããŸãªå
éšã€ã³ãã©ã¹ãã©ã¯ãã£ïŒ
rustc
ããã«ããã botãäºåæ§ç¯æžã¿ã®ããŒã«ãã§ãŒã³ã Chromium ãšã³ãžãã¢ã«é åžããããã®ã·ã¹ãã ãªã©ïŒ cargo audit
ãcargo vet
ãªã©ã® Cargo ããŒã«//third_party/rust
ã«åã蟌ãŸããRust ã©ã€ãã©ãªïŒsecurity@chromium.org ãç£æ»ïŒ- ãã®ä»ã® Rust ã©ã€ãã©ãªïŒããããªãã®ãããã°ãéåžžã«äººæ°ããããã䜿çšããããã®ããããŸãïŒ
Chromium ã® Rust ããªã·ãŒ
Chromium ã§ã¯ãChromium ã® ãšãªã¢ ãã¯ãã«ã« ãªãŒã ã«ãã£ãŠæ¿èªãããŠãããŸããªã±ãŒã¹ãé€ãããã¡ãŒã¹ã ããŒãã£ã§ã®Rust䜿çšã¯ãŸã èš±å¯ãããŠããŸããã
ãµãŒãããŒã㣠ã©ã€ãã©ãªã«é¢ãã Chromium ã®ããªã·ãŒã«ã€ããŠã¯ããã¡ã ãã芧ãã ãããRust ã¯ãããã©ãŒãã³ã¹ãã»ãã¥ãªãã£ãé«ããããã§æé©ãªéžæè¢ã§ããå Žåãå«ããããŸããŸãªç¶æ³ã§ãµãŒãããŒã㣠ã©ã€ãã©ãªã«äœ¿çšããããšãèš±å¯ãããŠããŸãã
C / C++ API ãçŽæ¥å ¬éãã Rust ã©ã€ãã©ãªã¯ã»ãšãã©ãªããããããããã©ã€ãã©ãªã®ã»ãŒãã¹ãŠã§ãå°éã®ãã¡ãŒã¹ã ããŒã㣠ã°ã«ãŒã³ãŒããå¿ èŠã«ãªããŸãã
ç¹å®ã®ãµãŒãããŒã㣠ã¯ã¬ãŒãçšã®ãã¡ãŒã¹ã ããŒã㣠Rust ã°ã«ãŒã³ãŒãã¯éåžžã
third_party/rust/<crate>/<version>/wrapper
ã«çœ®ãããã¹ãã§ãã
以äžã®çç±ãããæ¬æ¥ã®ã³ãŒã¹ã§ã¯ä»¥äžã«çŠç¹ãåœãŠãŸãã
- ãµãŒãããŒãã£ã® Rust ã©ã€ãã©ãªïŒãã¯ã¬ãŒããïŒãå°å ¥ããã
- Chromium C++ ããã¯ã¬ãŒãã䜿çšã§ããããã«ã°ã«ãŒã³ãŒããèšè¿°ããã
ãã®ããªã·ãŒãå€æŽãããå Žåã¯ãããã«åãããŠã³ãŒã¹ãå€æŽãããŸãã
Build rules
Rust ã³ãŒãã¯éåžžãcargo
ã䜿çšããŠãã«ããããŸããChromium ã¯å¹çãé«ããããã« gn
ãš ninja
ã䜿çšããŠãã«ããããŸããããã®éçã«ãŒã«ã«ãã£ãŠæ倧éã®äžŠååŠçãå¯èœã«ãªããŸããRust ãäŸå€ã§ã¯ãããŸããã
Chromium ã« Rust ã³ãŒããè¿œå ãã
Chromium ã®æ¢åã® BUILD.gn
ãã¡ã€ã«ã§ãrust_static_library
ã宣èšããŸãã
import("//build/rust/rust_static_library.gni")
rust_static_library("my_rust_lib") {
crate_root = "lib.rs"
sources = [ "lib.rs" ]
}
ä»ã® Rust ã¿ãŒã²ããã« deps
ãè¿œå ããããšãã§ããŸããåŸã§ããã䜿çšããŠããµãŒãããŒãã£ã®ã³ãŒããžã®äŸåãèšå®ããŸãã
Speaker Notes
ã¯ã¬ãŒãã«ãŒããšãœãŒã¹ã®å®å
šãªãªã¹ãã®äž¡æ¹ãæå®ããå¿
èŠããããŸããcrate_root
㯠Rust ã³ã³ãã€ã©ã«æž¡ããããã¡ã€ã«ã§ãã³ã³ãã€ã«åäœã®ã«ãŒããã¡ã€ã«ïŒé垞㯠lib.rs
ïŒãè¡šããŸããsources
ã¯ãã¹ãŠã®ãœãŒã¹ãã¡ã€ã«ã®å®å
šãªãªã¹ãã§ãåãã«ããå¿
èŠãªã¿ã€ãã³ã°ã ninja
ãå€æããããã«å¿
èŠã§ãã
ïŒRust ã§ã¯ã¯ã¬ãŒãå
šäœãã³ã³ãã€ã«åäœã§ãããããsource_set
ãšåŒã¹ããããªãã®ã¯ååšããŸãããstatic_library
ãæå°åäœã§ãïŒã
åè¬è ã¯ããªã Rust ã®éçã©ã€ãã©ãªã«å¯Ÿãã gn ã®çµã¿èŸŒã¿ãµããŒã ã§ã¯ãªããgn ãã³ãã¬ãŒãã䜿çšããå¿ èŠãããã®ãçåã«æããããããŸããããã®çãã¯ããã®ãã³ãã¬ãŒãã CXX çžäºéçšãRustã®featuresãåäœãã¹ãããµããŒãããŠããããã§ãããã®äžéšã¯åŸã§äœ¿çšããŸãã
unsafe
Rust ã³ãŒãã®è¿œå
å®å
šã§ãªã Rust ã³ãŒãã¯ããã©ã«ãã§ã¯ rust_static_library
ã§çŠæ¢ãããŠãããã³ã³ãã€ã«ã§ããŸãããå®å
šã§ãªã Rust ã³ãŒããå¿
èŠãªå Žåã¯ãgn ã¿ãŒã²ããã« allow_unsafe = true
ãè¿œå ããŸãïŒãããå¿
èŠã«ãªãç¶æ³ã«ã€ããŠã¯ããã®ã³ãŒã¹ã®åŸåã§èª¬æããŸãïŒã
import("//build/rust/rust_static_library.gni")
rust_static_library("my_rust_lib") {
crate_root = "lib.rs"
sources = [
"lib.rs",
"hippopotamus.rs"
]
allow_unsafe = true
}
Chromium C++ããRustã®ã³ãŒãã«äŸåããã
äžèšã®ã¿ãŒã²ãããããã€ãã® Chromium C++ ã¿ãŒã²ããã® deps
ã«è¿œå ããã ãã§ãã
import("//build/rust/rust_static_library.gni")
rust_static_library("my_rust_lib") {
crate_root = "lib.rs"
sources = [ "lib.rs" ]
}
# ãŸã㯠source_setãstatic_library ãªã©
component("preexisting_cpp") {
deps = [ ":my_rust_lib" ]
}
Speaker Notes
We'll see that this relationship only works if the Rust code exposes plain C APIs
which can be called from C++, or if we use a C++/Rust interop tool.
Visual Studio Code
Rust ã³ãŒãã§ã¯åãçç¥ãããŠãããããåªãã IDE 㯠C++ ã®å Žåãããããã«æçšã§ããVisual Studio Code 㯠Chromium ã® Rust ã§é©åã«æ©èœããŸããVisual Studio Code ã䜿çšããã«ãããã以äžã®ç¹ã確èªããŠãã ããã
- VSCode ã«ã以åã®åœ¢åŒã® Rust ãµããŒãã§ã¯ãªãã
rust-analyzer
æ¡åŒµæ©èœãããããšãç¢ºèª gn gen out/Debug --export-rust-project
ïŒãŸãã¯ããªãã®ãããžã§ã¯ãã«ãããåæ§ã®åºåãã£ã¬ã¯ããªïŒln -s out/Debug/rust-project.json rust-project.json

Speaker Notes
IDE ã«æççãªåè¬è ã«å¯ŸããŠã¯ãrust-analyzer ã®ã³ãŒã ã¢ãããŒã·ã§ã³ãšæ¢çŽ¢æ©èœã®ãã¢ãè¡ããšè¯ããããããŸããã
以äžã®æé ã«æ²¿ã£ãŠãã¢ãè¡ãããšãããããããŸãïŒä»£ããã«èªåãæã粟éããŠãã Chromium é¢é£ã® Rustã³ãŒãã䜿çšããŠãæ§ããŸããïŒã
components/qr_code_generator/qr_code_generator_ffi_glue.rs
ãéããŸãã- `qr_code_generator_ffi_glue.rs ã®
QrCode::new
åŒã³åºãïŒ26 è¡ç®ä»è¿ïŒã«ã«ãŒãœã«ãåãããŸãã - show documentation ã®ãã¢ãè¡ããŸãïŒäžè¬çãªãã€ã³ãã£ã³ã°: vscode = ctrl kiãvim/CoC = KïŒã
- go to definition ã®ãã¢ãè¡ããŸãïŒäžè¬çãªãã€ã³ãã£ã³ã°: vscode = F12ãvim/CoC = g dïŒïŒããã«ããã
//third_party/rust/.../qr_code-.../src/lib.rs
ã«ç§»åããŸãïŒã - outline ã®ãã¢ãè¡ãã
QrCode::with_bits
ã¡ãœããã«ç§»åããŸãïŒ164 è¡ç®ä»è¿ãã¢ãŠãã©ã€ã³ã¯ VSCode ã®ãã¡ã€ã« ãšã¯ã¹ãããŒã© ãã€ã³ã«ãããŸããäžè¬ç㪠vim/CoC ãã€ã³ãã£ã³ã° = space oïŒã - Demo type annotations (there are quite a few nice examples in the
QrCode::with_bits
method)
BUILD.gn
ãã¡ã€ã«ã®ç·šéåŸã¯ gn gen ... --export-rust-project
ãåå®è¡ããå¿
èŠãããããšã説æããŠãã ããïŒãã®ã»ãã·ã§ã³ã®æŒç¿å
šäœã§æ°åè¡ããŸãïŒã
Build rules exercise
Chromium ã®ãã«ãã§ã以äžãå«ãæ°ãã Rust ã¿ãŒã²ããã //ui/base/BUILD.gn
ã«è¿œå ããŸãã
Important: note that no_mangle
here is considered a type of unsafety by the Rust compiler, so youâll need to allow unsafe code in your gn
target.
ãã®æ°ãã Rust ã¿ãŒã²ããã //ui/base:base
ã®äŸåé¢ä¿ãšããŠè¿œå ããŸãããã®é¢æ°ã ui/base/resource/resource_bundle.cc
ã®å
é ã§å®£èšããŸãïŒåŸã»ã©ããã€ã³ãã£ã³ã°çæããŒã«ã§ãããèªååããæ¹æ³ã説æããŸãïŒã
extern "C" void hello_from_rust();
ãã®é¢æ°ã ui/base/resource/resource_bundle.cc
å
ã®ã©ããããåŒã³åºããŸããããããã¯ResourceBundle::MaybeMangleLocalizedString
ã®å
é ããåŒã³åºãããšã§ããChromium ããã«ãããŠå®è¡ããâHello from Rust!â ãäœåºŠãåºåãããŠããããšã確èªããŸãã
VSCode ã䜿çšããŠããå Žåã¯ãVSCode ã§é©åã«åäœããããã« Rust ãèšå®ããŸããããã¯ãåŸç¶ã®æŒç¿ã§åœ¹ç«ã¡ãŸããèšå®ãå®äºããããprintln!
㧠âGo to definitionâ ãå³ã¯ãªãã¯ã§å©çšã§ããããã«ãªããŸãã
åèæ å ±
rust_static_library
gn ãã³ãã¬ãŒã ã§äœ¿çšã§ãããªãã·ã§ã³- Information about
#[unsafe(no_mangle)]
extern "C"
ã«é¢ããæ å ±- gn ã®
--export-rust-project
ã¹ã€ããã«é¢ããæ å ± - VSCode ã« rust-analyzer ãã€ã³ã¹ããŒã«ããæ¹æ³
Speaker Notes
It's really important that students get this running, because future exercises
will build on it.
ãã®äŸã¯ãå ±éã®çžäºéçšèšèªã§ãã C ã«éçŽãããŠãããããäžè¬çã§ã¯ãããŸãããC++ ãš Rust ã¯ã©ã¡ãããC ABI é¢æ°ããã€ãã£ãã«å®£èšããŠåŒã³åºãããšãã§ããŸããã³ãŒã¹ã®åŸåã§ãC++ ã Rust ã«çŽæ¥æ¥ç¶ããŸãã
allow_unsafe = true
is required here because #[unsafe(no_mangle)]
might allow Rust to generate two functions with the same name, and Rust can no longer guarantee that the right one is called.
çŽç²ãª Rust å®è¡å¯èœãã¡ã€ã«ãå¿
èŠãªå Žåã¯ãrust_executable
gn ãã³ãã¬ãŒãã䜿çšããŠè¡ãããšãã§ããŸãã
ãã¹ã
Rust ã³ãã¥ããã£ã¯éåžžããã¹ã察象ã®ã³ãŒããšåããœãŒã¹ãã¡ã€ã«ã«é 眮ãããã¢ãžã¥ãŒã«ã§åäœãã¹ããäœæããŸããããã¯æ¬ã³ãŒã¹ã® åã®éšå ã§èª¬æããŠããã以äžã®ããã«ãªããŸãã
Chromium ã§ã¯åäœãã¹ããå¥ã®ãœãŒã¹ãã¡ã€ã«ã«é
眮ããŠãããRust ã§ããã®æ¹éãç¶ç¶ããŸããããã«ããããã¹ããåžžã«æ€åºå¯èœã«ãªãã2 床ç®ã«ïŒtest
æ§æã§ïŒ.rs
ãã¡ã€ã«ãåãã«ãããå¿
èŠããªããªããŸãã
ãã®çµæãChromium 㧠Rust ã³ãŒãããã¹ãããããã®æ¬¡ã®éžæè¢ãæäŸãããŸãã
- ãã€ãã£ã Rust ãã¹ãïŒäŸ:
#[test]
ïŒã//third_party/rust
以å€ã§ã¯æšå¥šãããŸããã - C++ ã§äœæãããFFI åŒã³åºããä»ã㊠Rust ãå®è¡ãã
gtest
ãã¹ããRust ã³ãŒããåãªãèãFFI ã¬ã€ã€ã§ãããæ¢åã®åäœãã¹ãã§ä»åŸãã®æ©èœãæŒããªãã«ããŒãããå Žåã«ã¯ååã§ãã - Rust ã§äœæãããå
¬é API ãä»ããŠãã¹ã察象ã®ã¯ã¬ãŒãã䜿çšãã
gtest
ãã¹ãïŒå¿ èŠã«å¿ããŠpub mod for_testing { ... }
ã䜿çšïŒãããã«ã€ããŠã¯ã次ã®æ°æã®ã¹ã©ã€ãã§èª¬æããŸãã
Speaker Notes
ãµãŒãããŒã㣠ã¯ã¬ãŒãã®ãã€ãã£ã Rust ãã¹ããæçµçã« Chromium bot ã«ãã£ãŠå®è¡ãããå¿ èŠãããããšã説æããŸãïŒãã®ãããªãã¹ããå¿ èŠã«ãªãããšã¯ãã£ãã«ãªãããµãŒãããŒãã£ã®ã¯ã¬ãŒããè¿œå ãŸãã¯æŽæ°ããåŸã«ã®ã¿å¿ èŠãšãªããŸãïŒã
C++ ã®gtest
ãš Rust ã®gtest
ãã©ã®ãããªå Žåã«äœ¿ãã¹ãããããã€ãã®äŸã䜿ã£ãŠèª¬æãããšããã§ãããã
-
QR ã«ã¯ããã¡ãŒã¹ã ããŒãã£ã® Rust ã¬ã€ã€ã®æ©èœã¯ã»ãšãã©ãããŸããïŒåãªãã·ã³ FFI ã°ã«ãŒã§ãïŒããã®ãããC++ ãš Rust ã®å®è£ ã®äž¡æ¹ããã¹ãããã«ã¯ãæ¢åã® C++ åäœãã¹ãã䜿çšããŸãïŒãã¹ãããã©ã¡ãŒã¿åãã
ScopedFeatureList
ã䜿çšã㊠Rust ãæå¹åãŸãã¯ç¡å¹åã§ããããã«ãªã£ãŠããŸãïŒã -
ä»®å®ã®ããŸãã¯éçºäžã® PNG çµ±åã§ã¯ã
libpng
ã§ã¯æäŸãããŠããã®ã«ãpng
ã¯ã¬ãŒãã§ã¯æ¬ èœããŠãããã¯ã»ã«å€æïŒRGBA => BGRAãã¬ã³ãè£æ£ãªã©ïŒã®ã¡ã¢ãªã»ãŒããªå®è£ ãå¿ èŠãšãªãå ŽåããããŸãããã®ãããªæ©èœã®éçºã«ãããŠã¯ãå¥éRustã§ãã¹ããäœæããããšã圹ç«ã€å ŽåããããŸãã
rust_gtest_interop
ã©ã€ãã©ãª
rust_gtest_interop
ã©ã€ãã©ãªã䜿çšãããšã次ã®ããšãã§ããŸãã
- Rust é¢æ°ã
gtest
ãã¹ãã±ãŒã¹ãšããŠäœ¿çšããïŒ#[gtest(...)]
å±æ§ã䜿çšïŒã expect_eq!
ãªã©ã®ãã¯ãã䜿çšããïŒassert_eq!
ãšäŒŒãŠããŸãããã¢ãµãŒã·ã§ã³ã倱æããŠããããã¯ããããã¹ããçµäºããŸããïŒã
Example:
use rust_gtest_interop::prelude::*;
#[gtest(MyRustTestSuite, MyAdditionTest)]
fn test_addition() {
expect_eq!(2 + 2, 4);
}
Rust ãã¹ãçšã® GN ã«ãŒã«
Rust ã® gtest
ãã¹ãããã«ãããæãç°¡åãªæ¹æ³ã¯ãC++ ã§äœæããããã¹ãããã§ã«å«ãŸããŠããæ¢åã®ãã¹ããã€ããªã«è¿œå ããããšã§ãã次ã«äŸã瀺ããŸãã
test("ui_base_unittests") {
...
sources += [ "my_rust_lib_unittest.rs" ]
deps += [ ":my_rust_lib" ]
}
å¥éãstatic_library
㧠Rust ãã¹ããäœæããããšãå¯èœã§ããããµããŒã ã©ã€ãã©ãªãžã®äŸåé¢ä¿ãæåã§å®£èšããå¿
èŠããããŸãã
rust_static_library("my_rust_lib_unittests") {
testonly = true
is_gtest_unittests = true
crate_root = "my_rust_lib_unittest.rs"
sources = [ "my_rust_lib_unittest.rs" ]
deps = [
":my_rust_lib",
"//testing/rust_gtest_interop",
]
}
test("ui_base_unittests") {
...
deps += [ ":my_rust_lib_unittests" ]
}
chromium::import!
ãã¯ã
GN ã® deps
ã« :my_rust_lib
ãè¿œå ããåŸããmy_rust_lib_unittest.rs
ãã my_rust_lib
ãã€ã³ããŒãããŠäœ¿çšããæ¹æ³ã«ã€ããŠåŠã¶å¿
èŠããããŸããmy_rust_lib
ã«ã¯æ瀺ç㪠crate_name
ãæå®ãããŠããªããããã¯ã¬ãŒãåã¯ã¿ãŒã²ããã®ãã«ãã¹ãšååã«åºã¥ããŠçæãããŸãã幞ããèªåçã«ã€ã³ããŒãããã chromium
ã¯ã¬ãŒããã chromium::import!
ãã¯ãã䜿çšããã°ããã®ãããªæ±ãã«ããååã®äœ¿çšãåé¿ã§ããŸãã
chromium::import! {
"//ui/base:my_rust_lib";
}
use my_rust_lib::my_function_under_test;
å éšã§ããã¯ãã¯æ¬¡ã®ããã«å±éãããŸãã
extern crate ui_sbase_cmy_urust_ulib as my_rust_lib;
use my_rust_lib::my_function_under_test;
詳ããã¯ãchromium::import
ãã¯ãã® ããã¥ã¡ã³ã ã³ã¡ã³ã ãã芧ãã ããã
Speaker Notes
rust_static_library
ã¯ãcrate_name
ããããã£ã«ããæ瀺çãªååã®æå®ããµããŒãããŠããŸãããã¯ã¬ãŒãåã¯ã°ããŒãã«ã«äžæã§ããå¿
èŠããããããããã¯æšå¥šãããŸãããcrates.io ã¯ã¯ã¬ãŒãåã®äžææ§ãä¿èšŒããŠãããããcargo_crate
GN ã¿ãŒã²ããïŒåŸè¿°ã® gnrt
ããŒã«ã§çæïŒã¯çãã¯ã¬ãŒãåã䜿çšããŸãã
Testing exercise
æ°ããªæŒç¿ã®æéã§ãïŒ
Chromium ãã«ãã§ä»¥äžãè¡ã£ãŠãã ããã
hello_from_rust
ã®æšªã«ãã¹ãå¯èœãªé¢æ°ãè¿œå ããŸããããšãã°ãåŒæ°ãšããŠåãåã£ã 2 ã€ã®æŽæ°ãè¿œå ãããn çªç®ã®ãã£ããããæ°ãèšç®ãããã¹ã©ã€ã¹å ã®æŽæ°ãåèšããããªã©ãèããããŸãã- æ°ããé¢æ°ã®ãã¹ããå«ãå¥åã®
..._unittest.rs
ãã¡ã€ã«ãè¿œå ããŸãã - æ°ãããã¹ãã
BUILD.gn
ã«è¿œå ããŸãã - ãã¹ãããã«ãããŠå®è¡ããæ°ãããã¹ããæ©èœããããšã確èªããŸãã
C++ãšã®çžäºéçšæ§
Rust ã³ãã¥ããã£ã«ã¯ C++ ãš Rust ã®çžäºéçšã®ããã®ãªãã·ã§ã³ãè€æ°çšæãããŠããã絶ããæ°ããããŒã«ãéçºãããŠããŸããçŸåšã®ãšãããChromium ã§ã¯ CXX ãšããããŒã«ã䜿çšããŠããŸãã
èšèªå¢çå šäœãã€ã³ã¿ãŒãã§ãŒã¹å®çŸ©èšèªïŒRust ã«ãã䌌ãŠããŸãïŒã§èšè¿°ãããšãCXX ããŒã«ã Rust ãš C++ ã®äž¡æ¹ã§é¢æ°ãšåã®å®£èšãçæããŸãã
CXX ã®è©³çŽ°ãªäœ¿çšäŸã«ã€ããŠã¯ãCXX ãã¥ãŒããªã¢ã« ãã芧ãã ããã
Speaker Notes
å³ãèŠãªãã話ããŸããããè£ã§è¡ãããåŠçã¯ä»¥åãšãŸã£ããåãã§ããããã®ããã»ã¹ãèªååãããšæ¬¡ã®ãããªã¡ãªãããããããšã説æããŸãã
- ãã®ããŒã«ã¯ãC++ åŽãš Rust åŽãäžèŽããããšãä¿èšŒããŸãïŒããšãã°ã
#[cxx::bridge]
ãå®éã® C++ ãŸã㯠Rust ã®å®çŸ©ãšäžèŽããªãå Žåãã³ã³ãã€ã« ãšã©ãŒãçºçããŸãããåæãããŠããªãæåãã€ã³ãã£ã³ã°ã䜿çšãããšãæªå®çŸ©ã®åäœãçºçããŸãïŒã - ãã®ããŒã«ã¯ãC 以å€ã®æ©èœã«å¯Ÿãã FFI ãµã³ã¯ïŒå°ã㪠C-ABI äºæã®ããªãŒé¢æ°ïŒã®çæãèªååããŸãïŒRust ãŸã㯠C++ ã¡ãœãããžã® FFI åŒã³åºãã®æå¹åãªã©ãæåãã€ã³ãã£ã³ã°ã§ã¯ããã®ãããªãããã¬ãã«ã®ããªãŒé¢æ°ãæåã§äœæããå¿ èŠããããŸãïŒã
- ããŒã«ãšã©ã€ãã©ãªã¯ã次ã®ãããªäžé£ã®äž»èŠãªåãåŠçã§ããŸãã
&[T]
ã¯ãç¹å®ã® ABI ãã¡ã¢ãª ã¬ã€ã¢ãŠããä¿èšŒãããã®ã§ã¯ãããŸããããFFI ã®å¢çãè¶ ããŠæž¡ãããšãã§ããŸããæåãã€ã³ãã£ã³ã°ã§ã¯ãstd::span<T>
/&[T]
ãæåã§åé¢ãããã€ã³ã¿ãšé·ãããåæ§ç¯ããå¿ èŠããããŸããèšèªããšã«ç©ºã®ã¹ã©ã€ã¹ã®è¡šçŸæ¹æ³ãè¥å¹²ç°ãªãããããšã©ãŒãçºçãããããªããŸããstd::unique_ptr<T>
ãstd::shared_ptr<T>
ãBox
ãªã©ã®ã¹ããŒã ãã€ã³ã¿ã¯ããã€ãã£ãã«ãµããŒããããŠããŸããæåãã€ã³ãã£ã³ã°ã§ã¯ãC-ABI äºæã®æªå å·¥ãã€ã³ã¿ãæž¡ãå¿ èŠããããããã©ã€ãã¿ã€ã ãšã¡ã¢ãªå®å šæ§ã«é¢ãããªã¹ã¯ãé«ãŸããŸããrust::String
åãšCxxString
åã¯ãèšèªéã®æååè¡šçŸã®éããç解ããç¶æããŸãïŒããšãã°ãrust::String::lossy
ã¯ãé UTF8 ã®å ¥åãã Rust æååãäœæã§ããŸãããŸããrust::String::c_str
ã¯æååã NUL çµç«¯ã§ããŸãïŒã
ãã€ã³ãã£ã³ã°ã®äŸ
CXX ã§ã¯ãC++ ãš Rust ã®å¢çå
šäœã .rs
ãœãŒã¹ã³ãŒãå
ã® cxx::bridge
ã¢ãžã¥ãŒã«ã§å®£èšããå¿
èŠããããŸãã
#[cxx::bridge]
mod ffi {
extern "Rust" {
type MultiBuf;
fn next_chunk(buf: &mut MultiBuf) -> &[u8];
}
unsafe extern "C++" {
include!("example/include/blobstore.h");
type BlobstoreClient;
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
fn put(self: &BlobstoreClient, buf: &mut MultiBuf) -> Result<u64>;
}
}
// Rust ã®åãšé¢æ°ã®å®çŸ©ãããã«èšè¿°ããŸãã
Speaker Notes
以äžã説æããŸãã
- ããã¯éåžžã® Rust
mod
ã®ããã«èŠããŸããã#[cxx::bridge]
ããã·ãŒãžã£ã« ãã¯ãã¯ããã«å¯ŸããŠè€éãªåŠçãè¡ããŸããçæãããã³ãŒãã¯ãã£ãšæŽç·ŽãããŠããŸãããããã§ãã³ãŒãã«ã¯ffi
ãšããmod
ãäœæãããŸãã - Rust ã§ã® C++ ã®
std::unique_ptr
ã®ãã€ãã£ã ãµããŒã - Native support for Rust slices in C++
- C++ ãã Rust ããã³ Rust ã®åãžã®åŒã³åºãïŒäžéšïŒ
- Rust ãã C++ ããã³ C++ ã®åãžã®åŒã³åºãïŒäžéšïŒ
ãããã誀解: Rust 㧠C++ ããããŒã解æãããŠããããã«èŠããŸãããããã¯èª€è§£ã§ãããã®ããããŒã¯ Rust ã§ã¯è§£éããããC++ ã³ã³ãã€ã©ã®ããã«çæããã C++ ã³ãŒãã« #include
ãããŠããã ãã§ãã
CXXã®éç
CXX ã䜿çšãããšãã«æã圹ç«ã€ããŒãžã¯ãåãªãã¡ã¬ã³ã¹ ã§ãã
CXX ã¯åºæ¬çã«ã次ã®ãããªã±ãŒã¹ã«é©ããŠããŸãã
- Rust-C++ ã€ã³ã¿ãŒãã§ãŒã¹ãååã«ã·ã³ãã«ã§ããã¹ãŠã宣èšã§ããå Žåã
- ãã§ã« CXX ã§ãã€ãã£ãã«ãµããŒããããŠããåã®ã¿ã䜿çšããŠããå ŽåïŒäŸ:
std::unique_ptr
ãstd::string
ã&[u8]
ïŒã
Rust ã® Option
åããµããŒããããŠããªããªã©ãCXX ã«ã¯å€ãã®å¶éããããŸãã
ããããå¶éã«ãããChromium ã§ã¯ ä»»æã® Rust ãš C++ ã®çžäºéçšã¯è¡ããããRustã®äœ¿çšã¯ååã«ç¬ç«ããã³ãŒãã«éå®ãããŠããŸããChromium ã§ã® Rust ã®ãŠãŒã¹ã±ãŒã¹ãæ€èšããéã¯ããŸããèšèªå¢çã® CXX ãã€ã³ãã£ã³ã°ã®äžæžããäœæããŠãã·ã³ãã«ã«èŠãããã©ããã確èªããããšãããããããŸãã
Speaker Notes
In addition, right now, Rust code in one component cannot depend on Rust
code in another, due to linking details in our component build. That's another
reason to restrict Rust to use in leaf nodes.
ãŸããCXX ã®ãã®ä»ã®åä»ãªç¹ã説æããå¿ èŠããããŸãã次ã«äŸã瀺ããŸãã
- ãšã©ãŒåŠçã C++ äŸå€ã«åºã¥ããŠè¡ãããïŒæ¬¡ã®ã¹ã©ã€ããåç §ïŒã
- é¢æ°ãã€ã³ã¿ã䜿ãã«ããã
CXXã«ããããšã©ãŒåŠç
CXX ã® Result<T,E>
ã®ãµããŒã ã¯ãC++ äŸå€ã«äŸåããŠãããããChromium ã§ã¯äœ¿çšã§ããŸããã以äžã®ä»£æ¿æ段ããããŸãã
-
Result<T, E>
ã®T
ã®éšå:- out ãã©ã¡ãŒã¿ãä»ããŠè¿ãããšãã§ããŸãïŒäŸ:
&mut T
ïŒããã®ããã«ã¯ãT
ã FFI ã®å¢çãè¶ããŠæž¡ããå¿ èŠããããŸããããšãã°ãT
ã«ã¯ä»¥äžãæå®ããå¿ èŠããããŸãã- ããªããã£ãåïŒ
u32
ãusize
ãªã©ïŒ - (
Box<T>
ãšã¯ç°ãªã)é©åãªããã©ã«ãå€ãæã€cxx
ã§ãã€ãã£ãã«ãµããŒããããŠããåïŒUniquePtr<T>
ãªã©ïŒã
- ããªããã£ãåïŒ
- Rust åŽã§ä¿æããåç
§ãä»ããŠå
¬éã§ããŸããããã¯ã
T
ã Rust åã®å Žåã«å¿ èŠã«ãªãããšããããŸããRust å㯠FFI ã®å¢çãè¶ ããŠæž¡ãããšãã§ãããUniquePtr<T>
ã«æ ŒçŽããããšãã§ããŸããã
- out ãã©ã¡ãŒã¿ãä»ããŠè¿ãããšãã§ããŸãïŒäŸ:
-
Result<T, E>
ã®E
ã®éšå:- ããŒã«å€ãšããŠè¿ãããšãã§ããŸãïŒããšãã°ã
true
ã¯æåãfalse
ã¯å€±æãè¡šããŸãïŒã - çè«äžã¯ãšã©ãŒã®è©³çŽ°ãä¿æã§ããŸããããããŸã§ã¯å®éã«å¿ èŠã«ãªãããšã¯ãããŸããã§ããã
- ããŒã«å€ãšããŠè¿ãããšãã§ããŸãïŒããšãã°ã
CXX Error Handling: QR Example
QR ã³ãŒãçæããŒã«ã¯ãããŒã«å€ãæåãŸãã¯å€±æãäŒéããæåã®çµæã FFI ã®å¢çãè¶ ããŠåãæž¡ãããšãã§ãã äžäŸ ã§ãã
#[cxx::bridge(namespace = "qr_code_generator")]
mod ffi {
extern "Rust" {
fn generate_qr_code_using_rust(
data: &[u8],
min_version: i16,
out_pixels: Pin<&mut CxxVector<u8>>,
out_qr_size: &mut usize,
) -> bool;
}
}
Speaker Notes
åè¬è
㯠out_qr_size
åºåã®ã»ãã³ãã£ã¯ã¹ã«é¢å¿ãæã£ãŠããå¯èœæ§ããããŸããããã¯ãã¯ã¿ãŒã®ãµã€ãºã§ã¯ãªããQR ã³ãŒãã®ãµã€ãºã§ãïŒã€ãŸãããã®æ
å ±ã¯åé·ã§ããããã¯ã¿ãŒã®ãµã€ãºã®å¹³æ¹æ ¹ã«çžåœããŸãïŒã
Rust é¢æ°ãåŒã³åºãåã« out_qr_size
ãåæåããããšã®éèŠæ§ã説æããŸããããåæåãããŠããªãã¡ã¢ãªãæã Rust åç
§ãäœæãããšãæªå®çŸ©ã®åäœãšãªããŸãïŒãã®ãããªã¡ã¢ãªãéåç
§ããæäœã®ã¿ã UB ã«ãªãC++ ãšã¯ç°ãªããŸãïŒã
Pin
ã«ã€ããŠåè¬è
ããå°ããããå Žåã¯ãCXX ã C++ ããŒã¿ãžã®å¯å€åç
§ã®ããã« Pin
ãå¿
èŠãšããçç±ã説æããŸããã€ãŸããC++ ã®ããŒã¿ã«ã¯èªå·±åç
§ãã€ã³ã¿ãå«ãŸããŠããå¯èœæ§ããããããRust ã®ããŒã¿ã®ããã«ç§»åããããšãã§ããŸããã
CXX Error Handling: PNG Example
PNG ãã³ãŒãã®ãããã¿ã€ãã¯ãæåããçµæã FFI ã®å¢çãè¶ããŠæž¡ããªãå Žåã«äœãã§ãããã瀺ããŠããŸãã
#[cxx::bridge(namespace = "gfx::rust_bindings")]
mod ffi {
extern "Rust" {
/// ãã㯠`Result<PngReader<'a>,()>` ãšåçã® FFI 察å¿ã®çµæã
/// è¿ããŸãã
fn new_png_reader<'a>(input: &'a [u8]) -> Box<ResultOfPngReader<'a>>;
/// `crate::png::ResultOfPngReader` åã® C++ ãã€ã³ãã£ã³ã°
type ResultOfPngReader<'a>;
fn is_err(self: &ResultOfPngReader) -> bool;
fn unwrap_as_mut<'a, 'b>(
self: &'b mut ResultOfPngReader<'a>,
) -> &'b mut PngReader<'a>;
/// `crate::png::PngReader` åã® C++ ãã€ã³ãã£ã³ã°
type PngReader<'a>;
fn height(self: &PngReader) -> u32;
fn width(self: &PngReader) -> u32;
fn read_rgba8(self: &mut PngReader, output: &mut [u8]) -> bool;
}
}
Speaker Notes
PngReader
ãš ResultOfPngReader
㯠Rust åã§ãããããã®åã®ãªããžã§ã¯ãã¯ãBox<T>
ãä»ããã« FFI å¢çãè¶ããããšã¯ã§ããŸãããCXX ã§ã¯ Rust ãªããžã§ã¯ããå€ã§æ ŒçŽã§ããªããããout_parameter: &mut PngReader
ãšæžãããšã¯ã§ããŸããã
ãã®äŸã¯ãCXX ãä»»æã®ãžã§ããªã¯ã¹ããã³ãã¬ãŒãããµããŒãããŠããªããŠããæåã§éãžã§ããªãã¯åã«ç¹å / åçžåããããšã§ãFFI å¢çãè¶ããŠæž¡ããããšã瀺ããŠããŸãããã®äŸã§ã¯ãResultOfPngReader
ã¯Result<T, E>
ã®é©åãªã¡ãœããïŒis_err
ãunwrap
ãas_mut
ãªã©ïŒã«æž¡ãããéãžã§ããªãã¯åã§ãã
Chromium 㧠cxx ã䜿çšãã
Chromium ã§ã¯ãRust ã䜿çšãããªãŒãããŒãããšã«ç¬ç«ãã #[cxx::bridge] mod
ãå®çŸ©ããŸããéåžžã¯ãrust_static_library
ããšã« 1 ã€ãã€ã«ãªããŸãã
cxx_bindings = [ "my_rust_file.rs" ]
# ãã¹ãŠã®ãœãŒã¹ãã¡ã€ã«ã§ã¯ãªãã#[cxx::bridge] ãå«ããã¡ã€ã«ã®ãªã¹ã
allow_unsafe = true
äžèšã®ã³ãŒãããcrate_root
ã sources
ãšäžŠãã§ãæ¢åã® rust_static_library
ã¿ãŒã²ããã«è¿œå ããã ãã§ãã
C++ ããããŒã¯é©åãªå Žæã§çæãããããã次ã®ããã«ã€ã³ã¯ã«ãŒãã§ããŸãã
#include "ui/base/my_rust_file.rs.h"
//base
ã«ã¯ãChromium C++ åãã CXX Rust åïŒããã³ãã®éæ¹åïŒãžã®å€æãè¡ãããã®ãŠãŒãã£ãªãã£é¢æ°ãããã€ããããŸãïŒäŸ: SpanToRustSlice
ïŒã
Speaker Notes
åè¬è
ãããallow_unsafe = true
ããªãããã§ãå¿
èŠãªã®ããå°ããããå¯èœæ§ããããŸãã
倧ãŸãã«çãããšãC/C++ ã³ãŒãã¯éåžžã® Rust æšæºã§ã¯ãå®å
šãã§ã¯ãããŸãããRust ãã C/C++ ã«è¡ã£ããæ¥ãããããšãã¡ã¢ãªã«å¯ŸããŠä»»æã®åŠçãè¡ãããRust ç¬èªã®ããŒã¿ ã¬ã€ã¢ãŠãã®å®å
šæ§ãæãªãããå¯èœæ§ããããŸããC/C++ ã®çžäºéçšã§ unsafe
ããŒã¯ãŒããå€ããããšãunsafe
ã«å¯Ÿãã泚ç®åºŠãèããã®ã§ãããã«ã¯ è³åŠäž¡è«ããããŸãããã ãå³å¯ã«ã¯ãå€éšã³ãŒãã Rust ãã€ããªã«åã蟌ããšãRust ã®èŠ³ç¹ããã¯æ³å®ããŠããªãåäœãçºçããå¯èœæ§ããããŸãã
å
·äœçãªçãã¯ããã®ããŒãž ã®äžéšã®å³ã«ãããŸããè£ã§ã¯ãCXX 㯠Rust ã® unsafe
é¢æ°ãš extern "C"
é¢æ°ãçæããŸããããã¯åã®ã»ã¯ã·ã§ã³ã§æåã§è¡ã£ãã®ãšãŸã£ããåãã§ãã
Exercise: Interoperability with C++
ããŒã 1
- å
ã»ã©äœæãã Rust ãã¡ã€ã«ã«ãC++ ããåŒã³åºãåäžã®é¢æ°ã瀺ã
#[cxx::bridge]
ãè¿œå ããŸããããã¯hello_from_rust
ãšããé¢æ°ã§ããã©ã¡ãŒã¿ãåãåãããå€ãè¿ããŸããã - Modify your previous
hello_from_rust
function to removeextern "C"
and#[unsafe(no_mangle)]
. This is now just a standard Rust function. gn
ã¿ãŒã²ãããå€æŽããŠããããã®ãã€ã³ãã£ã³ã°ããã«ãããŸãã- C++ ã³ãŒãã§ã
hello_from_rust
ã®åæ¹å®£èšãåé€ãã代ããã«çæãããããã㌠ãã¡ã€ã«ãã€ã³ã¯ã«ãŒãããŸãã - ãã«ãããŠå®è¡ããŸãã
ããŒã 2
CXX ãå°ã䜿ã£ãŠã¿ãŠãChromium ã«ããã Rust ã®æè»æ§ã«ã€ããŠç解ãæ·±ããŸãããã
以äžãè©ŠããŠãã ããã
- Rust ãã C++ ãåŒã³åºããŸããããã«ã¯ä»¥äžãå¿
èŠã§ãã
cxx::bridge
ããinclude!
ã§ããè¿œå ã®ããã㌠ãã¡ã€ã«ããã®æ°ããããã㌠ãã¡ã€ã«ã§ C++ é¢æ°ã宣èšããå¿ èŠããããŸãã- ãã®ãããªé¢æ°ãåŒã³åºã
unsafe
ãããã¯ããŸã㯠ãã¡ã ã«èšèŒãããŠãããšããã#[cxx::bridge]
å ã§unsafe
ããŒã¯ãŒããæå®ããå¿ èŠããããŸãã #include "third_party/rust/cxx/v1/crate/include/cxx.h"
ãå¿ èŠã«ãªããããããŸããã
- C++ ãã Rust ã« C++ æååãæž¡ããŸãã
- C++ ãªããžã§ã¯ããžã®åç §ã Rust ã«æž¡ããŸãã
- æå³çã«
#[cxx::bridge]
ãšäžèŽããªãããã«Rust é¢æ°ã®ã·ã°ããã£ãå€æŽãã衚瀺ããããšã©ãŒã«æ £ããããã«ããŸãã - æå³çã«
#[cxx::bridge]
ãšäžèŽããªãããã«C++ é¢æ°ã®ã·ã°ããã£ãå€æŽãã衚瀺ããããšã©ãŒã«æ £ããããã«ããŸãã - ãªãããã®åã®
std::unique_ptr
ã C++ ãã Rust ã«æž¡ããŠãRust ãããã€ãã® C++ ãªããžã§ã¯ããææã§ããããã«ããŸãã - Rust ãªããžã§ã¯ããäœæã㊠C++ ã«æž¡ããŠãC++ ããããææã§ããããã«ããŸãïŒãã³ã:
Box
ãå¿ èŠã§ãïŒã - C++ åã§ããã€ãã®ã¡ãœããã宣èšããRust ããåŒã³åºããŸãã
- Rust åã«å¯ŸããŠããã€ãã®ã¡ãœããã宣èšããC++ ããåŒã³åºããŸãã
ããŒã 3
CXX ã®çžäºéçšæ§ã®é·æãšå¶éäºé ã«ã€ããŠç解ãããšããã§ãã€ã³ã¿ãŒãã§ãŒã¹ãéåžžã«ã·ã³ãã«ãªãChromium ã§ã® Rust ã®ãŠãŒã¹ã±ãŒã¹ãããã€ãèããŠã¿ãŸãããããã®ã€ã³ã¿ãŒãã§ãŒã¹ãã©ã®ããã«å®çŸ©ããã°ãããèããŠã¿ãŸãããã
åèæ å ±
Speaker Notes
As students explore Part Two, they're bound to have lots of questions about how
to achieve these things, and also how CXX works behind the scenes.
次ã®ãããªè³ªåãå¯ããããå¯èœæ§ããããŸãã
- X ãš Y ã®äž¡æ¹ãé¢æ°åã§ããå Žåã«ãå X ã®å€æ°ãå Y ã§åæåãããšåé¡ãçºçããŸããããã¯ãC++ é¢æ°ã
cxx::bridge
å ã®å®£èšãšå®å šã«äžèŽããªãããã§ãã - C++ åç §ã Rust åç §ã«èªç±ã«å€æã§ããããã§ãããUB ã®ãªã¹ã¯ã¯ãªãã§ããããïŒCXX ã®äžéæåã®å Žåããµã€ãºããŒãã§ããããããã®ãªã¹ã¯ã¯ãããŸãããCXX ã®ããªãã¢ã«åã§ã¯ UB ãçºçããå¯èœæ§ããããŸãããCXX ã®èšèšäžããã®ãããªäŸãäœæããã®ã¯éåžžã«å°é£ã§ãã
ãµãŒãããŒãã£ã®ã¯ã¬ãŒããè¿œå ãã
Rust ã©ã€ãã©ãªã¯ãã¯ã¬ãŒãããšåŒã°ããcrates.io ã«ãããŸããRust ã¯ã¬ãŒããäºãã«äŸåãããã®ã¯éåžžã«ç°¡åã§ãããå®éã«ãã®ããã«ãªã£ãŠããŸã
ãããã㣠| C++ library | Rust crate |
---|---|---|
Build system | å€æ° | äžè²«ã㊠Cargo.toml |
äžè¬çãªã©ã€ãã©ãª ãµã€ãº | ãã倧 | å° |
æšç§»çäŸåé¢ä¿ | å° | å€æ° |
Chromium ã®ãšã³ãžãã¢ã«ãšã£ãŠãã¯ã¬ãŒãã«ã¯é·æãšçæããããŸãã
- ãã¹ãŠã®ã¯ã¬ãŒããå ±éã®ãã«ãã·ã¹ãã ã䜿çšããŠãããããChromium ãžã®åã蟌ã¿ãèªååã§ããŸãã
- ããããã¯ã¬ãŒãã«ã¯éåžžãæšç§»çäŸåé¢ä¿ããããããè€æ°ã®ã©ã€ãã©ãªãåã蟌ãããšãå¿ èŠã«ãªãå¯èœæ§ããããŸãã
è°è«ããå 容ã¯æ¬¡ã®ãšããã§ãã
- Chromium ãœãŒã¹ã³ãŒã ããªãŒã«ã¯ã¬ãŒããé 眮ããæ¹æ³
- ã¯ã¬ãŒãçšã®
gn
ãã«ãã«ãŒã«ãäœæããæ¹æ³ - ã¯ã¬ãŒãã®ãœãŒã¹ã³ãŒãã®ååãªå®å šæ§ãç£æ»ããæ¹æ³ã
Speaker Notes
All of the things in the table on this slide are generalizations, and
counter-examples can be found. But in general it's important for students
to understand that most Rust code depends on other Rust libraries, because
it's easy to do so, and that this has both benefits and costs.
Cargo.toml
ãã¡ã€ã«ã«ããã¯ã¬ãŒããè¿œå ããæ¹æ³
Chromium ã«ã¯ãäžå
管çãããçŽæ¥çãªã¯ã¬ãŒãäŸåé¢ä¿ã 1 ã»ãããããŸãããããã¯åäžã® Cargo.toml
ã§ç®¡çãããŸãã
[dependencies]
bitflags = "1"
cfg-if = "1"
cxx = "1"
# lots more...
ä»ã® Cargo.toml
ãšåæ§ã«ãäŸåé¢ä¿ã®è©³çŽ° ãæå®ã§ããŸããéåžžã¯ãã¯ã¬ãŒãã§æå¹ã«ãã features
ãæå®ããŸãã
Chromium ã«ã¯ã¬ãŒããè¿œå ããéã¯ãå€ãã®å Žåã gnrt_config.toml
ãšããè¿œå ãã¡ã€ã«ã«æ
å ±ãæå®ããå¿
èŠããããŸããããã«ã€ããŠã¯åŸã§èª¬æããŸãã
gnrt_config.toml
ãæ§æãã
Cargo.toml
ã®ã»ãã«ãgnrt_config.toml
ããããŸããããã«ã¯ãã¯ã¬ãŒããæ±ãããã® Chromium åºæã®æ¡åŒµæ©èœãå«ãŸããŠããŸãã
æ°ããã¯ã¬ãŒããè¿œå ããå Žåã¯ãå°ãªããšã次ã®ããããã® group
ãæå®ããå¿
èŠããããŸãã
# 'safe': The library satisfies the rule-of-2 and can be used in any process.
# 'sandbox': The library does not satisfy the rule-of-2 and must be used in
# a sandboxed process such as the renderer or a utility process.
# 'test': The library is only used in tests.
次ã«äŸã瀺ããŸãã
[crate.my-new-crate]
group = 'test' # only used in test code
ã¯ã¬ãŒãã®ãœãŒã¹ã³ãŒãã®ã¬ã€ã¢ãŠãã«ãã£ãŠã¯ããã®ãã¡ã€ã«ã䜿çšã㊠LICENSE
ãã¡ã€ã«ãèŠã€ããå Žæãæå®ããå¿
èŠããããŸãã
åŸã»ã©ãããã€ãã®åé¡ã解決ããããã«ãã®ãã¡ã€ã«ã«æå®ããå¿ èŠãããèšå®ã«ã€ããŠåãæ±ããŸãã
ã¯ã¬ãŒããããŠã³ããŒããã
gnrt
ãšããããŒã«ã¯ãã¯ã¬ãŒãã®ããŠã³ããŒãæ¹æ³ãš BUILD.gn
ã«ãŒã«ã®çææ¹æ³ãææ¡ããŠããŸãã
ãŸããå¿ èŠãªã¯ã¬ãŒãã次ã®ããã«ããŠã³ããŒãããŸãã
cd chromium/src
vpython3 tools/crates/run_gnrt.py -- vendor
gnrt
ããŒã«ã¯ Chromium ã®ãœãŒã¹ã³ãŒãã®äžéšã§ããããã®ã³ãã³ããå®è¡ãããšãcrates.io
ããäŸåé¢ä¿ãããŠã³ããŒãããŠå®è¡ããŸããããã«é¢ããã»ãã¥ãªãã£äžã®æ±ºå®ã«ã€ããŠã¯ãåã®ã»ã¯ã·ã§ã³ ãã芧ãã ããã
ãã® vendor
ã³ãã³ãã«ããã以äžãããŠã³ããŒããããå ŽåããããŸãã
- Your crate
- çŽæ¥çããã³æšç§»çäŸåé¢ä¿
cargo
ã«ãã£ãŠæ瀺ããããChromium ã§å¿ èŠãšãªãã¯ã¬ãŒãã®å®å šã»ãããåŸãããã®ä»ã®ã¯ã¬ãŒãã®æ°ããããŒãžã§ã³ã
Chromium ã§ã¯ãäžéšã®ã¯ã¬ãŒãã«å¯Ÿãããããã //third_party/rust/chromium_crates_io/patches
ã«ä¿åãããŠããŸãããããã¯èªåçã«åé©çšãããŸããããããé©çšã倱æããå Žåã¯ãæåã«ãã解決ãå¿
èŠã«ãªãå ŽåããããŸãã
gn
ãã«ãã«ãŒã«ãçæãã
ã¯ã¬ãŒããããŠã³ããŒããããã以äžã®ããã« BUILD.gn
ãã¡ã€ã«ãäœæããŸãã
vpython3 tools/crates/run_gnrt.py -- gen
git status
ãå®è¡ãã以äžã確èªããŸãã
third_party/rust/chromium_crates_io/vendor
ã« 1 ã€ä»¥äžã®æ°ããã¯ã¬ãŒã ãœãŒã¹ã³ãŒããããããšthird_party/rust/<crate name>/v<major semver version>
ã« 1 ã€ä»¥äžã®æ°ããBUILD.gn
ãããããš- é©åãª
README.chromium
ãããããš
The âmajor semver versionâ is a Rust âsemverâ version number.
ç¹ã« third_party/rust
以äžã«çæããããã®ããã確èªããŠãã ããã
Speaker Notes
semver ã«ã€ããŠãç¹ã« Chromium ã§ã¯äºææ§ã®ãªãã¯ã¬ãŒãã®ããŒãžã§ã³ãè€æ°èš±å¯ãããããšã説æããŠãããŸããããããã¯æšå¥šãããŸããããCargo ãšã³ã·ã¹ãã ã§å¿ èŠã«ãªãããšããããŸãã
åé¡ã解決ãã
ãã«ãã倱æããå Žåãbuild.rs
ïŒãã«ãæã«ä»»æã®åŠçãè¡ãããã°ã©ã ïŒãåå ã§ããå¯èœæ§ããããŸããããã¯ããã«ãã®äžŠåæ§ãšåçŸæ§ãæ倧åããããã«éçã§æ±ºå®çãªãã«ãã«ãŒã«ãç®æã gn
ãš ninja
ã®èšèšãšã¯ãåºæ¬çã«ççŸããŠããŸãã
äžéšã® build.rs
ã¢ã¯ã·ã§ã³ã¯èªåçã«ãµããŒããããŸãããä»ã®ã¢ã¯ã·ã§ã³ã«ã¯å¯Ÿå¿ãå¿
èŠã§ãã
ãã«ã ã¹ã¯ãªããã®å¹æ | gn ãã³ãã¬ãŒãã«ãããµããŒã | å¿ èŠãªäœæ¥ |
---|---|---|
rustc ã®ããŒãžã§ã³ã確èªããŠæ©èœãæå¹ãŸãã¯ç¡å¹ã«ãã | ã¯ã | ãªã |
ãã©ãããã©ãŒã ãŸã㯠CPU ã確èªããŠæ©èœãæå¹ãŸãã¯ç¡å¹ã«ãã | ã¯ã | ãªã |
Generating code | ã¯ã | ãã - gnrt_config.toml ã§æå®ãã |
C/C++ ã®ãã«ã | ããã | ããããé©çšãã |
ãã®ä»ã®ä»»æã®ã¢ã¯ã·ã§ã³ | ããã | ããããé©çšãã |
幞ããã»ãšãã©ã®ã¯ã¬ãŒãã«ã¯ãã«ã ã¹ã¯ãªãããå«ãŸããŠããããã»ãšãã©ã®ãã«ã ã¹ã¯ãªããã¯äžäœ 2 ã€ã®ã¢ã¯ã·ã§ã³ã®ã¿ãå®è¡ããŸãã
ã³ãŒããçæãããã«ãã¹ã¯ãªãã
ninja
ããã¡ã€ã«ãèŠã€ããããªããšããã¡ãã»ãŒãžã衚瀺ããå Žåã¯ãbuild.rs
ããœãŒã¹ã³ãŒã ãã¡ã€ã«ãäœæããŠãããã©ããã確èªããŸãã
ãããã¡ã€ã«ãäœæãããããã«ãªã£ãŠããããgnrt_config.toml
ãå€æŽããŠãã¯ã¬ãŒãã« build-script-outputs
ãè¿œå ããŸãããããæšç§»çäŸåé¢ä¿ïŒChromium ã³ãŒããçŽæ¥äŸåãã¹ãã§ãªãäŸåé¢ä¿ïŒã®å Žåã¯ãallow-first-party-usage=false
ãè¿œå ããŸãããã®ãã¡ã€ã«ã«ã¯ããã§ã«ããã€ãã®äŸãå«ãŸããŠããŸãã
[crate.unicode-linebreak]
allow-first-party-usage = false
build-script-outputs = ["tables.rs"]
次ã«ãgnrt.py -- gen
ãåå®è¡ã㊠BUILD.gn
ãã¡ã€ã«ãåçæãããã®ç¹å®ã®åºåãã¡ã€ã«ãåŸç¶ã®ãã«ãã¹ãããã§å
¥åãããããšã ninja ã«æããŸãã
C++ããã«ãããããããã¯ãä»»æã®ã¢ã¯ã·ã§ã³ãå®è¡ãããã«ãã¹ã¯ãªãã
äžéšã®ã¯ã¬ãŒãã¯ãcc
ã¯ã¬ãŒãã䜿çšããŠãC / C++ ã©ã€ãã©ãªã®ãã«ããšãªã³ã¯ãè¡ããŸããä»ã®ã¯ã¬ãŒãã¯ããã«ã ã¹ã¯ãªããå
㧠bindgen
ã䜿çšã㊠C / C++ ã解æããŸãããããã®ã¢ã¯ã·ã§ã³ã¯ãChromium ã®ã³ã³ããã¹ãã§ã¯ãµããŒãã§ããŸãããChromiumã® gnãninjaãLLVM ãã«ãã·ã¹ãã ã¯ããã«ã ã¢ã¯ã·ã§ã³éã®é¢ä¿ãéåžžã«å
·äœçã«è¡šçŸããããã§ãã
ãããã£ãŠã次ã®ãããªãªãã·ã§ã³ããããŸãã
- ãããã®ã¯ã¬ãŒãã䜿çšããªã
- ã¯ã¬ãŒãã«ããããé©çšãã
ããã㯠third_party/rust/chromium_crates_io/patches/<crate>
ã«ä¿åããå¿
èŠããããŸããããšãã°ãcxx
ã¯ã¬ãŒãã«å¯Ÿããããã ãã芧ãã ããããŸãããããã¯ã¯ã¬ãŒããã¢ããã°ã¬ãŒãããããã³ã« gnrt
ã«ãã£ãŠèªåçã«é©çšãããŸãã
ã¯ã¬ãŒããžã®äŸåãèšå®ãã
ãµãŒãããŒã㣠ã¯ã¬ãŒããè¿œå ããŠãã«ãã«ãŒã«ãçæããããã¯ã¬ãŒããžã®äŸåãç°¡åã«èšå®ã§ããŸããrust_static_library
ã¿ãŒã²ãããèŠã€ããŠãã¯ã¬ãŒãå
ã® :lib
ã¿ãŒã²ããã« dep
ãè¿œå ããŸãã
å ·äœçã«ã¯æ¬¡ã®ããã«ããŸãã
次ã«äŸã瀺ããŸãã
rust_static_library("my_rust_lib") {
crate_root = "lib.rs"
sources = [ "lib.rs" ]
deps = [ "//third_party/rust/example_rust_crate/v1:lib" ]
}
ãµãŒãããŒã㣠ã¯ã¬ãŒãã®ç£æ»
æ°ããã©ã€ãã©ãªãè¿œå ããå ŽåãChromium ã®æšæºã® ããªã·ãŒ ãé©çšãããŸãããåœç¶ãªããã»ãã¥ãªãã£å¯©æ»ã®å¯Ÿè±¡ã«ããªããŸãã1 ã€ã®ã¯ã¬ãŒãã ãã§ãªãæšç§»çäŸåé¢ä¿ãåã蟌ãå Žåã審æ»ãã¹ãã³ãŒããå€æ°ååšããããšããããŸãããã®äžæ¹ã§ãå®å šãª Rust ã³ãŒãã®åã蟌ã¿ã«é¢ããŠã¯ãæªãå¯äœçšã¯éå®çãšãªããŸããã¯ã¬ãŒãã®å¯©æ»ã¯ã©ã®ããã«è¡ãããã¹ãã§ããããã
Chromium ã¯ä»åŸ cargo vet ãäžå¿ãšããããã»ã¹ã«ç§»è¡ãããŠããäºå®ã§ããã
ãããŸã§ã®éãæ°ããã¯ã¬ãŒããè¿œå ããããã³ã«ã以äžã®ãã§ãã¯ãè¡ããŸãã
- åã¯ã¬ãŒãã䜿çšãããŠããçç±ãšãã¯ã¬ãŒãå士ã®é¢ä¿ãç解ããŸããåã¯ã¬ãŒãã®ãã«ãã·ã¹ãã ã«
build.rs
ãŸãã¯æç¶ãåãã¯ããå«ãŸããŠããå Žåã¯ããã®ç®çã調ã¹ãŸãããŸããChromium ã®éåžžã®ãã«ãæ¹æ³ãšäºææ§ããããã©ããã確èªããŸãã - åã¯ã¬ãŒããååã«ã¡ã³ããã³ã¹ãããŠããã確èªããŸãã
cd third-party/rust/chromium_crates_io; cargo audit
ã䜿çšããŠæ¢ç¥ã®è匱æ§ããã§ãã¯ããŸãïŒæåã«cargo install cargo-audit
ãå®è¡ããå¿ èŠããããŸãããç®èãªããšã«ãããã«ãã£ãŠã€ã³ã¿ãŒãããããå€ãã®äŸåé¢ä¿ãããŠã³ããŒãããããšã«ãªããŸã 2ïŒãunsafe
ãªã³ãŒãã Rule of Two ãæºãããŠããããšã確èªããŸããfs
ããã³net
ã®API ã䜿çšãããŠãããã©ããã確èªããŸãã- æªæãæã£ãŠäžæ£ã«æ¿å ¥ãããå¯èœæ§ã®ããéšåããªããæ¢ãã®ã«ååãªã¬ãã«ã§ã³ãŒããèªã¿ãŸãïŒå€ãã®å Žåãã³ãŒããå€ãããŠå®ç§ã«ãã§ãã¯ããããšã¯ã§ããŸããïŒã
ãããã¯ã¬ã€ãã©ã€ã³ã«ãããŸãããsecurity@chromium.org
ã®å¯©æ»æ
åœè
ãšååããŠãèªä¿¡ãæã£ãŠã¯ã¬ãŒãã䜿çšããããã®é©åãªæ¹æ³ãèŠã€ããŠãã ããã
ã¯ã¬ãŒãã Chromium ãœãŒã¹ã³ãŒãã«ãã§ãã¯ã€ã³ãã
git status
ãå®è¡ãããšã以äžã確èªã§ããŸãã
//third_party/rust/chromium_crates_io
ã«ããã¯ã¬ãŒãã³ãŒã//third_party/rust/<crate>/<version>
ã«ããã¡ã¿ããŒã¿ïŒBUILD.gn
ãšREADME.chromium
ïŒ
åŸè
ã®å Žæã« OWNERS
ãã¡ã€ã«ãè¿œå ããŠãã ããã
ããããã¹ãŠããCargo.toml
ããã³ gnrt_config.toml
ã®å€æŽãšãšãã« Chromium ãªããžããªã«è¿œå ããå¿
èŠããããŸãã
éèŠ: git add -f
ã䜿çšããå¿
èŠããããŸããããããªããšã.gitignore
ãã¡ã€ã«ã«ãã£ãŠäžéšã®ãã¡ã€ã«ãã¹ããããããå¯èœæ§ãããããã§ãã
ãã®éãã€ã³ã¯ã«ãŒã·ãã§ãªãè¡šçŸãåå 㧠presubmit ãã§ãã¯ã倱æããããšããããŸããããã¯ãRust ã®ã¯ã¬ãŒãããŒã¿ã«ã¯ Git ãã©ã³ãã®ååãå«ãŸããŠããåŸåããããå€ãã®ãããžã§ã¯ãã§äŸç¶ãšããŠã€ã³ã¯ã«ãŒã·ãã§ãªãè¡šçŸã䜿çšãããŠããããã§ãããã®ããã以äžãå®è¡ããå¿ èŠããããŸãã
infra/update_inclusive_language_presubmit_exempt_dirs.sh > infra/inclusive_language_presubmit_exempt_dirs.txt
git add -p infra/inclusive_language_presubmit_exempt_dirs.txt # add whatever changes are yours
ã¯ã¬ãŒããææ°ã®ç¶æ ã«ä¿ã€
ãµãŒãããŒãã£ã® Chromium äŸåé¢ä¿ã®ææè ã¯ãã»ãã¥ãªãã£ã«é¢ããä¿®æ£ãè¡ã£ãŠäŸåé¢ä¿ãææ°ã®ç¶æ ã«ä¿ã€ããšãæ±ããããŸããããã¯ãŸããªãèªååãããããšãæåŸ ãããŠããŸãããçŸç¶ã¯ä»ã®ãµãŒãããŒãã£ã®äŸåé¢ä¿ã®å Žåãšåæ§ã«ãããããããŒããã®è²¬ä»»ãè² ããŸãã
æŒç¿
Chromium ã« uwuify ãè¿œå ããã¯ã¬ãŒãã® ããã©ã«ãã®æ©èœ ãç¡å¹ã«ããŸããã¯ã¬ãŒã㯠Chromium ã®å ¬éæ¿ã§äœ¿çšãããŸãããä¿¡é Œã§ããªãå ¥åã®åŠçã«ã¯äœ¿çšãããªããšä»®å®ããŠãã ããã
ïŒæ¬¡ã®æŒç¿ã§ Chromium ã® uwuify ã䜿çšããŸãããããã§è¡ã£ãŠãæ§ããŸããããŸãã¯ãuwuify
ã䜿çšããæ°ãã rust_executable
ã¿ãŒã²ãã ãäœæããããšãã§ããŸãïŒã
Speaker Notes
åè¬è ã¯å€æ°ã®æšç§»çäŸåé¢ä¿ãããŠã³ããŒãããå¿ èŠããããŸãã
å¿ èŠãªã¯ã¬ãŒãã¯æ¬¡ã®ãšããã§ãã
instant
lock_api
parking_lot
parking_lot_core
redox_syscall
scopeguard
smallvec
uwuify
åè¬è ãäžèšä»¥å€ã®ã¯ã¬ãŒããããŠã³ããŒãããŠããå Žåã¯ãããã©ã«ãã®æ©èœãç¡å¹ã«ããã®ãå¿ããŠããå¯èœæ§ããããŸãã
ãã®ã¯ã¬ãŒãã«ååããŠããã Daniel Liu ã«æè¬ããŸãã
ãŸãšã â æŒç¿
ãã®æŒç¿ã§ã¯ãChromium ã®æ°ããæ©èœãè¿œå ããªããããããŸã§åŠãã ããšããŸãšããŸãã
ãããã¯ã ãããžã¡ã³ãéšéããã®ããªãŒãã£ã³ã°
人éé¢ããç±åž¯éšæã«çæ¯ãããã¯ã·ãŒïŒåŠç²Ÿã®äžçš®ïŒã®æãçºèŠãããŸããããã¯ã·ãŒåãã® Chromium ãã§ããã ãæ©ãæäŸããããšãéèŠã§ãã
èŠä»¶ã¯ãChromium ã®ãã¹ãŠã® UI æååããã¯ã·ãŒã®èšèªã«ç¿»èš³ããããšã§ãã
æ£åŒãªç¿»èš³ãè¡ã£ãŠããæéã¯ãããŸãããã幞ãã«ããã¯ã·ãŒã®èšèªã¯è±èªã«éåžžã«è¿ãããã®ç¿»èš³ãè¡ã Rust ã¯ã¬ãŒããããããšãããããŸããã
å®ã¯ãåã®æŒç¿ã§ãã®ã¯ã¬ãŒããã€ã³ããŒãããŠããŸãã
ïŒèšããŸã§ããªããChrome ãå®éã«ç¿»èš³ããã«ã¯çŽ°å¿ã®æ³šæãšåªåãå¿ èŠã§ãã®ã§ãããã¯å ¬éããªãã§ãã ããïŒã
æé
衚瀺åã«ãã¹ãŠã®æååã翻蚳ããããã« ResourceBundle::MaybeMangleLocalizedString
ãå€æŽããŸããChromium ã®ãã®ç¹å¥ãªãã«ãã§ã¯ãmangle_localized_strings_
ã®èšå®ã«é¢ä¿ãªããåžžã«ãã®ããã«ããŸãã
ãããŸã§ã®æŒç¿ããã¹ãŠæ£ããçµãããããŠããã°ãããã§ãã¯ã·ãŒåãã® Chrome ãå®æããŠããã¯ãã§ãã

Speaker Notes
Students will likely need some hints here. Hints include:
- UTF16 ãš UTF8 ã«ã€ããŠãåè¬è
㯠Rust æååãåžžã« UTF8 ã§ããããšã«æ³šæããå¿
èŠããããŸãããããããC++ åŽã§
base::UTF16ToUTF8
ã䜿çšããŠå€æãéå€æããæ¹ããããšå€æããã§ãããã - Rust åŽã§å€æãè¡ãå Žåã¯ã
String::from_utf16
ã®å©çšããšã©ãŒåŠçãå€ãã® u16s ã転éå¯èœãª CXX ã§ãµããŒããããŠããå ã¯ã©ãããæ€èšããå¿ èŠããããŸãã - åè¬è
ã¯ããã€ãã®ç°ãªãæ¹æ³ã§ C++ ãš Rust ã®å¢çãèšèšã§ããŸããããšãã°ãæååãå€ã§ååŸããŠè¿ãããŸãã¯æååãžã®å¯å€åç
§ãååŸãããªã©ã§ããå¯å€åç
§ã䜿çšãããŠããå Žåã¯ããããã CXX ã¯
Pin
ã䜿çšããå¿ èŠãããæšã®ã¡ãã»ãŒãžã衚瀺ããŸããPin
ã®æ©èœã説æããC++ ããŒã¿ãžã®å¯å€åç §ã®ããã« CXX ã§Pin
ãå¿ èŠã«ãªãçç±ã説æããå¿ èŠããããããããŸãããçãã¯ãC++ ããŒã¿ã«ã¯èªå·±åç §ãã€ã³ã¿ãå«ãŸããŠããå¯èœæ§ããããããRust ããŒã¿ã®ããã«ç§»åã§ããªãããã§ãã ResourceBundle::MaybeMangleLocalizedString
ãå«ã C++ ã¿ãŒã²ããã¯ãrust_static_library
ã¿ãŒã²ããã«äŸåããå¿ èŠããããŸããåè¬è ã¯ãã§ã«ãããè¡ã£ãŠããã¯ãã§ããrust_static_library
ã¿ãŒã²ããã¯//third_party/rust/uwuify/v0_2:lib
ã«äŸåããå¿ èŠããããŸãã
æŒç¿ã®è§£ç
Chromium ã®æŒç¿ã®è§£çã«ã€ããŠã¯ããã¡ãã® CL ã·ãªãŒãº ãã芧ãã ããã
ãã¢ã¡ã¿ã«Rustãžãããã
ãã¡ãã¯ãã¢ã¡ã¿ã«Rustã«é¢ããç¬ç«ããïŒæ¥ã³ãŒã¹ã§ãã察象ãšããŠããã®ã¯ãRustã®åºæ¬çãªéšåã«é¢ããŠã¯ç¿åŸæžã¿ãªäººã§ïŒäŸãã°ãæ¬è¬åº§ã§ïŒãCãªã©ã®ä»ã®èšèªã§ãã¢ã¡ã¿ã«éçºã®çµéšããããšçæ³çã§ãã
ä»æ¥ãåãæ±ãã®ã¯ããã¢ã¡ã¿ã«Rustã§ããããªãã¡ãOSãªãã§Rustã®ã³ãŒããå®è¡ããŸãããã®ç« ã¯ä»¥äžã®ãããªæ§æã«ãªããŸã:
no_std
Rustãšã¯?- ãã€ã¯ãã³ã³ãããŒã©åãã®ãã¡ãŒã ãŠã§ã¢éçºã
- ã¢ããªã±ãŒã·ã§ã³ããã»ããµåãã®ããŒãããŒãïŒã«ãŒãã«éçºã
- ãã¢ã¡ã¿ã«Rustéçºã«åœ¹ç«ã€ã¯ã¬ãŒãã®çŽ¹ä»ã
For the microcontroller part of the course we will use the BBC micro:bit v2 as an example. Itâs a development board based on the Nordic nRF52833 microcontroller with some LEDs and buttons, an I2C-connected accelerometer and compass, and an on-board SWD debugger.
ãŸãã¯ããã«ãåŸã»ã©å¿ èŠãšãªãããã€ãã®ããŒã«ãã€ã³ã¹ããŒã«ããŸããgLinuxãŸãã¯Debianã®å Žåã¯ä»¥äžã®ããã«ãªããŸã:
sudo apt install gdb-multiarch libudev-dev picocom pkg-config qemu-system-arm
rustup update
rustup target add aarch64-unknown-none thumbv7em-none-eabihf
rustup component add llvm-tools-preview
cargo install cargo-binutils
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh
ããã«ãplugdev
ã°ã«ãŒãã«micro:bitããã°ã©ã çšããã€ã¹ãžã®ã¢ã¯ã»ã¹ãä»äžããŸã:
echo 'SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0d28", MODE="0660", GROUP="logindev", TAG+="uaccess"' |\
sudo tee /etc/udev/rules.d/50-microbit.rules
sudo udevadm control --reload-rules
MacOSã®å Žåã¯ä»¥äžã®ããã«ãªããŸã:
xcode-select --install
brew install gdb picocom qemu
rustup update
rustup target add aarch64-unknown-none thumbv7em-none-eabihf
rustup component add llvm-tools-preview
cargo install cargo-binutils
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh
no_std
|
|
|
---|---|---|
|
|
|
Speaker Notes
HashMap
ã¯RNGã«äŸåããŸããstd
ã¯core
ãšalloc
ã®äž¡æ¹ãåãšã¯ã¹ããŒãããŸãã
æå°éã®no_std
ããã°ã©ã
Speaker Notes
- ãã®ã³ãŒãã¯ç©ºã®ãã€ããªã«ã³ã³ãã€ã«ãããŸãã
- ãããã¯ãã³ãã©ã¯
std
ãæäŸããã®ã§ãããã䜿ããªãå Žåã¯èªåã§æäŸããå¿ èŠããããŸãã - ãããã¯ã
panic-halt
ã®ãããªå¥ã®ã¯ã¬ãŒããæäŸãããããã¯ãã³ãã©ãå©çšããããšãã§ããŸãã - ã¿ãŒã²ããã«ãã£ãŠã¯ã
eh_personality
ã«é¢ãããšã©ãŒãåé¿ããããã«panic = "abort"
ãæå®ããŠã³ã³ãã€ã«ããå¿ èŠããããŸãã - ãªãã
main
ã®ãããªããã°ã©ã ã®èŠå®ãšã³ããªãã€ã³ãã¯ãªãã®ã§ãèªåã§ãšã³ããªãã€ã³ããå®çŸ©ããå¿ èŠããããŸããéåžžãRustã³ãŒããå®è¡ã§ããããã«ããããã«ã¯ããªã³ã«ã¹ã¯ãªãããšããçšåºŠã®ã¢ã»ã³ããªã³ãŒããå¿ èŠãšããŸãã
alloc
alloc
ã䜿ãããã«ã¯ãã°ããŒãã«ïŒããŒãïŒã¢ãã±ãŒã¿ãå®è£
ããªããã°ãªããŸããã
Speaker Notes
buddy_system_allocator
ã¯ãµãŒãããŒãã£ã®ã¯ã¬ãŒãã§ãåçŽãªããã£ã·ã¹ãã ã¢ãã±ãŒã¿ã§ãããã®ä»ã«ãå©çšã§ããã¯ã¬ãŒãã¯ãããŸãããèªåã§å®è£ ããããå¥ã®ã¢ãã±ãŒã¿ã«èªåã®ã³ãŒããããã¯ããããšãå¯èœã§ãã- ãã©ã¡ãŒã¿å®æ°
LockedHeap
ã¯ã¢ãã±ãŒã¿ã®æ倧ãªãŒãã瀺ããŸãããã®å Žåã2**32ãã€ãã®é åã確ä¿ããããšãå¯èœã§ãã - ããäŸåé¢ä¿ã«ããã¯ã¬ãŒãã
alloc
ã«äŸåããå Žåãå¿ ããã€ããªãã¡ã€ã«ãããäžã€ã ãã®ã°ããŒãã«ãªã¢ãã±ãŒã¿ãååšããããã«ããªããã°ãªããŸãããéåžžãããã¯ãããã¬ãã«ã®ãã€ããªãçæããã¯ã¬ãŒãã«ããå¶åŸ¡ãããŸãã extern crate panic_halt as _
ãšããéšåã¯ãpanic_halt
ã¯ã¬ãŒãã確å®ã«ãªã³ã¯ãããããã¯ãã³ãã©ãå©çšå¯èœã«ããããã«å¿ èŠã§ãã- ãã®äŸã§ç€ºããã³ãŒãã¯ãã«ãã§ããŸããããšã³ããªãã€ã³ãããªãã®ã§å®è¡ããããšã¯ã§ããŸããã
ãã€ã¯ãã³ã³ãããŒã©
cortex_m_rt
ã¯ã¬ãŒãã¯Cortex Mãã€ã¯ãã³ã³ãããŒã©åãã®ãªã»ãããã³ãã©ïŒãšãã®ä»ããããïŒãæäŸããŸãã
次ã¯ãæœè±¡åºŠã®äœãã¬ãã«ããé ã«åšèŸºI/Oã«ã¢ã¯ã»ã¹ããæ¹æ³ã«ã€ããŠèŠãŠãããŸãã
Speaker Notes
- ãªã»ãããã³ãã©ã¯ãªã¿ãŒã³ããªãã®ã§ã
cortex_m_rt::entry
ãã¯ãã¯å¯Ÿè±¡é¢æ°ãfn() -> !
ãšããåã§ããããšãèŠæ±ããŸãã - ãã®äŸã¯
cargo embed --bin minimal
ã«ããå®è¡ããŸã
çMMIOïŒã¡ã¢ãªããããI/OïŒ
倧åã®ãã€ã¯ãã³ã³ãããŒã©ã¯ã¡ã¢ãªããããRIO空éãéããŠåšèŸºI/Oã«ã¢ã¯ã»ã¹ããŸããmicro:bitã®LEDãå ãããŠã¿ãŸããã:
Speaker Notes
- GPIO 0ã®ãã³21ã¯ãããªã¯ã¹LEDã®äžçªç®ã®åã«ããã³28ã¯æåã®è¡ã«æ¥ç¶ãããŠããŸãã
äŸã®å®è¡æ¹æ³:
cargo embed --bin mmio
åšèŸºI/Oãžã¢ã¯ã»ã¹ããããã®ã¯ã¬ãŒãïŒPACsïŒ
svd2rust
ã¯CMSIS-SVD ãã¡ã€ã«ãããã¡ã¢ãªããããããåšèŸºI/Oã«å¯Ÿããã»ãŒå®å
šïŒmostly-safeïŒãªRustã©ãããŒãçæããŸãã
Speaker Notes
- SVD (System View Description)ãã¡ã€ã«ã¯XMLãã¡ã€ã«ã§ããã€ã¹ã®ã¡ã¢ãªããããèšè¿°ãããã®ã§ãããéåžžã·ãªã³ã³ãã³ãã«ããæäŸãããŸãã
- åšèŸºI/Oããšã«ãã¬ãžã¹ã¿ããã£ãŒã«ããšå€ãååã説æãã¢ãã¬ã¹ãªã©ã«ããæ§æãããŠããŸãã
- SVDãã¡ã€ã«ã«ã¯ãã誀ããããããŸãæ å ±ãäžè¶³ããŠããããšãå€ãã®ã§ãæ§ã ãªãããžã§ã¯ãããããä¿®æ£ã»è¿œå ããã¯ã¬ãŒããšããŠå ¬éããŠããŸãã
cortex-m-rt
ã¯ãã¯ã¿ããŒãã«ãæäŸããŸãã- ãã
cargo install cargo-binutils
ãå®è¡ããŠããã°ãcargo objdump --bin pac -- -d --no-show-raw-insn
ãå®è¡ããããšã«ããçæããããã€ããªã®äžèº«ãèŠãããšãã§ããŸãã
äŸã®å®è¡æ¹æ³:
cargo embed --bin pac
HALã¯ã¬ãŒã
å€ãã®ãã€ã¯ãã³ã³ãããŒã©ã«å¯ŸããHALã¯ã¬ãŒããæ§ã
ãªåšèŸºI/Oã«å¯Ÿããã©ãããŒãæäŸããŠããŸãããããã®ã¯ã¬ãŒãã®å€ãã¯embedded-hal
ãå®çŸ©ãããã¬ã€ããå®è£
ããŠããŸãã
Speaker Notes
set_low
ãšset_high
ã¯embedded_hal
ã®OutputPin
ãã¬ã€ãã®å®çŸ©ããã¡ãœããã§ãã- Cortex-MãRISC-Vã®å€ãã®ããã€ã¹ã«å¯ŸããŠHALã¯ã¬ãŒããååšãããããã«ã¯STM32ãGD32ãnRFãNXPãMSP430ãAVRãPICãã€ã¯ãã³ã³ãããŒã©ãªã©ãå«ãŸããŸãã
äŸã®å®è¡æ¹æ³:
cargo embed --bin hal
ããŒããµããŒãã¯ã¬ãŒã
ããŒããµããŒãã¯ã¬ãŒãã¯ç¹å®ã®ããŒãã«å¯ŸããŠæŽã«å©äŸ¿æ§ãåäžãããã©ãããŒãæäŸããŸãã
Speaker Notes
- ãã®äŸã§ã¯ãããŒããµããŒãã¯ã¬ãŒãã¯åã«åãããããååãæäŸããå°ãã®åæåãå®æœããŠããã ãã§ãã
- ãã€ã¯ãã³ã³ãããŒã©ã®å€ã«å®è£
ããããªã³ããŒãããã€ã¹ã«å¯Ÿãããã©ã€ããæäŸãããŠããããšããããŸãã
microbit-v2
ã¯ãããªã¯ã¹LEDã«å¯Ÿããç°¡åãªãã©ã€ããå«ãã§ããŸãã
äŸã®å®è¡æ¹æ³:
cargo embed --bin board_support
ã¿ã€ãã¹ããŒããã¿ãŒã³
Speaker Notes
- ãã®äŸã§ã¯ããã³ãè¡šãã¿ã€ãã¯
Copy
ãClone
ãå®è£ ããŠããŸããããã®ããããã äžã€ã®ã€ã³ã¹ã¿ã³ã¹ã ããååšå¯èœã§ãããã³ãããŒãæ§é äœããã ãŒãããããšãä»ã®èª°ããã®ãã³ã«ã¢ã¯ã»ã¹ããããšã¯ã§ããªããªããŸãã - ãã³ã®èšå®ãå€æŽããããšã¯å€ããã³ã®ã€ã³ã¹ã¿ã³ã¹ãæ¶è²»ããããšã«ãªããŸãããã®ããããã以éã¯å€ãã€ã³ã¹ã¿ã³ã¹ã䜿ãç¶ããããšã¯ã§ããªããªããŸãã
- å€æ°ã®åã¯ãã®ç¶æ ãè¡šãããã«ãªã£ãŠããŸããäŸãã°ããã®äŸã§ã¯åãGPIOãã³ã®ç¶æ ãè¡šããŠããŸãããã®ããã«ã¹ããŒããã·ã³ãã¿ã€ãã·ã¹ãã ã«ç¹ã蟌ãããšã§ãæ£ããèšå®ãããã«ãã³ã䜿ã£ãŠããŸãããšããªããªããŸããäžæ£ãªç¶æ é·ç§»ã«é¢ããŠã¯ã³ã³ãã€ã«æã«çºèŠãããããã«ãªããŸãã
- ã€ã³ããããã³ã«å¯ŸããŠ
is_high
ãåŒã³åºãããšã¯å¯èœã§ãã¢ãŠãããããã³ã«å¯ŸããŠset_high
ãåŒã³åºãããšãå¯èœã§ãããããããã®éã®çµã¿åããã¯äžå¯èœã§ãã - å€ãã®HALã¯ã¬ãŒãããã®ãã¿ãŒã³ãçšããŠããŸãã
embedded-hal
The embedded-hal
crate provides a number of traits covering common microcontroller peripherals:
- GPIO
- PWM
- Delay timers
- I2C and SPI buses and devices
Similar traits for byte streams (e.g. UARTs), CAN buses and RNGs and broken out into embedded-io
, embedded-can
and rand_core
respectively.
Other crates then implement drivers in terms of these traits, e.g. an accelerometer driver might need an I2C or SPI device instance.
Speaker Notes
- The traits cover using the peripherals but not initialising or configuring them, as initialisation and configuration is usually highly platform-specific.
- å€ãã®ãã€ã¯ãã³ã³ãããŒã©ã«å¯Ÿããå®è£ ã«å ããŠãRaspberry Piäžã®Linuxåãã®å®è£ ãååšããŸãã
embedded-hal-async
provides async versions of the traits.embedded-hal-nb
provides another approach to non-blocking I/O, based on thenb
crate.
probe-rs
ãšcargo-embed
probe-rsã¯çµã¿èŸŒã¿åããããã°ã«æçšãªããŒã«ã»ããã§ããããã¯OpenOCDã®ãããªãã®ã§ãããããé«åºŠã«çµ±åãããŠããŸãã
- SWD (Serial Wire Debug) ãCMSIS-DAPçµç±ã®JTAGã ST-LinkãJ-LinkãããŒã
- GDBã¹ã¿ããMicrosoft DAP (Debug Adapter Protocol)ãµãŒã
- Cargoãšã®ã€ã³ãã°ã¬ãŒã·ã§ã³
cargo-embed
ã¯cargoã®ãµãã³ãã³ãã§ããããã€ããªããã«ããããããã©ãã·ã¥ããããRTTïŒReal Time TransfersïŒã®åºåãã°ãååŸããããGDBã«æ¥ç¶ããããã®ãã®ã§ããèšå®ã¯å¯Ÿè±¡ãšãããããžã§ã¯ããã£ã¬ã¯ããªã«ãããEmbed.toml
ãã¡ã€ã«ã«ããè¡ããŸãã
Speaker Notes
- CMSIS-DAP ã¯USBäžã®ARMæšæºãããã³ã«ã§ãã€ã³ãµãŒãããã»ãããã¬ãæ§ã ãªArm Cortexããã»ããµã®ã³ã¢ãµã€ãã»ãããã°ã»ã¢ã¯ã»ã¹ããŒãã«ã¢ã¯ã»ã¹ããããã®ãã®ã§ããBBC micro:bit ã®ãªã³ããŒãã»ãããã¬ããããå©çšããŠããŸãã
- ST-Link ã¯ST Microelectronicsã«ããã€ã³ãµãŒãããã»ãããã¬ã®ç·ç§°ã§ã J-Linkã¯SEGGERã«ããã€ã³ãµãŒãããã»ãããã¬ã®ç·ç§°ã§ãã
- ãããã°ã»ã¢ã¯ã»ã¹ããŒãã¯éåžžïŒãã³ã®JTAGã€ã³ã¿ãã§ãŒã¹ãã2ãã³ã®ã·ãªã¢ã«ã¯ã€ã€ãããã°ã§ãã
- probe-rsã¯èªåã§ç¬èªã®ããŒã«ãçµ±åãããå Žåã«å©çšã§ããã©ã€ãã©ãªã§ãã
- Microsoft Debug Adapter Protocol ã¯VSCodeãä»ã®IDEããããµããŒãããããã€ã¯ãã³ã³ãããŒã©äžã§å®è¡ãããŠããã³ãŒãããããã°ããããšãå¯èœã«ããŸãã
- cargo-embedã¯probe-rsã©ã€ãã©ãªãå©çšããŠçæããããã€ããªã§ãã
- RTT (Real Time Transfers)ã¯ãããã°ãã¹ããšã¿ãŒã²ããéã®ããŒã¿ãå€ãã®ãªã³ã°ãããã¡ãä»ããŠãããšãããããã®ã¡ã«ããºã ã§ãã
ãããã°
Embed.toml:
[default.general]
chip = "nrf52833_xxAA"
[debug.gdb]
enabled = true
ã²ãšã€ã®ã¿ãŒããã«ã§ãsrc/bare-metal/microcontrollers/examples/
ã«ãããŠäžèšãå®è¡:
cargo embed --bin board_support debug
å¥ã®ã¿ãŒããã«ã§ãåããã£ã¬ã¯ããªã§äžèšãå®è¡:
gLinuxãŸãã¯Debianã®å Žå:
gdb-multiarch target/thumbv7em-none-eabihf/debug/board_support --eval-command="target remote :1337"
MacOSã®å Žåã¯ä»¥äžã®ããã«ãªããŸã:
arm-none-eabi-gdb target/thumbv7em-none-eabihf/debug/board_support --eval-command="target remote :1337"
Speaker Notes
GDBã§äžèšãå®è¡ããŠã¿ãŠãã ãã:
b src/bin/board_support.rs:29
b src/bin/board_support.rs:30
b src/bin/board_support.rs:32
c
c
c
ä»ã®ãããžã§ã¯ã
- RTIC
- âReal-Time Interrupt-driven Concurrencyâ.
- Shared resource management, message passing, task scheduling, timer queue.
- Embassy
async
executors with priorities, timers, networking, USB.
- TockOS
- Security-focused RTOS with preemptive scheduling and Memory Protection Unit support.
- Hubris
- Microkernel RTOS from Oxide Computer Company with memory protection, unprivileged drivers, IPC.
- Bindings for FreeRTOS.
ããã€ãã®ãã©ãããã©ãŒã ã§ã¯ std
ã®å®è£
ãããäŸãã° esp-idfã
Speaker Notes
- RTICã¯RTOSãšããŠæããããšãã§ããŸããã䞊è¡å®è¡ã®ãã¬ãŒã ã¯ãŒã¯ãšããŠæããããšãã§ããŸãã
- ä»ã®HALãå šãå«ãã§ããŸããã
- ã¹ã±ãžã¥ãŒãªã³ã°ã¯ã«ãŒãã«ã§ã¯ãªããCortex-M NVIC (Nested Virtual Interrupt Controller)ãå©çšããŠè¡ããŸãã
- Cortex-Mã®ã¿ã®å¯Ÿå¿ã§ãã
- Googleã¯TockOSãTitanã»ãã¥ãªãã£ããŒã®Havenãã€ã¯ãã³ã³ãããŒã©ã§å©çšããŠããŸãã
- FreeRTOS ã¯ã»ãšãã©Cã§æžãããŠããŸãããã¢ããªã±ãŒã·ã§ã³ãéçºããããã®Rustãã€ã³ãã£ã³ã°ãååšããŸãã
ç·Žç¿åé¡
I2Cæ¥ç¶ã®ã³ã³ãã¹ããæ¹äœãèªã¿åãããã®çµæãã·ãªã¢ã«ããŒãã«åºåããŸãã
Speaker Notes
ç·Žç¿åé¡ã«åãçµãã ããšã¯ã 解çãã¿ãŠãæ§ããŸããã
ã³ã³ãã¹
I2Cæ¥ç¶ã®ã³ã³ãã¹ããæ¹äœãèªã¿åãããã®çµæãã·ãªã¢ã«ããŒãã«åºåããŸããããæéãããã°ãLEDããã¿ã³ããªããšãå©çšããŠæ¹äœãåºåããŠã¿ãŠãã ããã
ãã³ã:
lsm303agr
ã¯ã¬ãŒããšmicrobit-v2
ã¯ã¬ãŒãã®ããã¥ã¡ã³ãããªãã³ã«micro:bitããŒããŠã§ã¢ä»æ§ã確èªããŠã¿ãŠãã ããã- LSM303AGRæ £æ§èšæž¬åšã¯å éšã®I2Cãã¹ã«æ¥ç¶ãããŠããŸãã
- TWIã¯I2Cã®å¥åãªã®ã§ãI2Cãã¹ã¿ã¯TWIMãšããååã«ãªã£ãŠããŸãã
- The LSM303AGR driver needs something implementing the
embedded_hal::i2c::I2c
trait. Themicrobit::hal::Twim
struct implements this. - æ§ã
ãªãã³ãåšèŸºI/Oã®ããã®
microbit::Board
ãšããæ§é äœããããŸãã - nRF52833ããŒã¿ã·ãŒããèŠãããšãã§ããŸããããã®ç·Žç¿åé¡ã®ããã«ã¯å¿ èŠãªãã¯ãã§ãã
ç·Žç¿åé¡ã®ãã³ãã¬ãŒã ãããŠã³ããŒãããŠãcompass
ãšãããã£ã¬ã¯ããªã®äžã«ããäžèšã®ãã¡ã€ã«ãèŠãŠãã ããã
src/main.rs:
#![no_main]
#![no_std]
extern crate panic_halt as _;
use core::fmt::Write;
use cortex_m_rt::entry;
use microbit::{hal::{Delay, uarte::{Baudrate, Parity, Uarte}}, Board};
#[entry]
fn main() -> ! {
let mut board = Board::take().unwrap();
// Configure serial port.
let mut serial = Uarte::new(
board.UARTE0,
board.uart.into(),
Parity::EXCLUDED,
Baudrate::BAUD115200,
);
// Use the system timer as a delay provider.
let mut delay = Delay::new(board.SYST);
// Set up the I2C controller and Inertial Measurement Unit.
// TODO
writeln!(serial, "Ready.").unwrap();
loop {
// Read compass data and log it to the serial port.
// TODO
}
}
Cargo.toml (å€æŽã¯äžèŠãªã¯ãã§ã):
[workspace]
[package]
name = "compass"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
cortex-m-rt = "0.7.3"
embedded-hal = "1.0.0"
lsm303agr = "1.1.0"
microbit-v2 = "0.15.1"
panic-halt = "1.0.0"
Embed.toml (å€æŽã¯äžèŠãªã¯ãã§ã):
[default.general]
chip = "nrf52833_xxAA"
[debug.gdb]
enabled = true
[debug.reset]
halt_afterwards = true
.cargo/config.toml (å€æŽã¯äžèŠãªã¯ãã§ã):
[build]
target = "thumbv7em-none-eabihf" # Cortex-M4F
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
rustflags = ["-C", "link-arg=-Tlink.x"]
Linuxã§ã¯ã·ãªã¢ã«ããŒãåºåãäžèšã®ã³ãã³ãã§ç¢ºèªããŸã:
picocom --baud 115200 --imap lfcrlf /dev/ttyACM0
Mac OSã§ã¯ãããªæãã«ãªããŸãïŒããã€ã¹åãå°ãéããããããŸããïŒ:
picocom --baud 115200 --imap lfcrlf /dev/tty.usbmodem14502
Ctrl+A Ctrl+Q ã§picocomãçµäºããŸãã
ãã¢ã¡ã¿ã« Rust ã®ååã®æŒç¿
ã³ã³ãã¹
ïŒæŒç¿ã«æ»ãïŒ
#![no_main]
#![no_std]
extern crate panic_halt as _;
use core::fmt::Write;
use cortex_m_rt::entry;
use core::cmp::{max, min};
use embedded_hal::digital::InputPin;
use lsm303agr::{
AccelMode, AccelOutputDataRate, Lsm303agr, MagMode, MagOutputDataRate,
};
use microbit::display::blocking::Display;
use microbit::hal::twim::Twim;
use microbit::hal::uarte::{Baudrate, Parity, Uarte};
use microbit::hal::{Delay, Timer};
use microbit::pac::twim0::frequency::FREQUENCY_A;
use microbit::Board;
const COMPASS_SCALE: i32 = 30000;
const ACCELEROMETER_SCALE: i32 = 700;
#[entry]
fn main() -> ! {
let mut board = Board::take().unwrap();
// ã·ãªã¢ã«ããŒããèšå®ããŸãã
let mut serial = Uarte::new(
board.UARTE0,
board.uart.into(),
Parity::EXCLUDED,
Baudrate::BAUD115200,
);
// ã·ã¹ãã ã¿ã€ããŒãé
延ç®çã§äœ¿çšããŸãã
let mut delay = Delay::new(board.SYST);
// I2C ã³ã³ãããŒã©ãšæ
£æ§æž¬å®ãŠããããã»ããã¢ããããŸãã
writeln!(serial, "Setting up IMU...").unwrap();
let i2c = Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::K100);
let mut imu = Lsm303agr::new_with_i2c(i2c);
imu.init().unwrap();
imu.set_mag_mode_and_odr(
&mut delay,
MagMode::HighResolution,
MagOutputDataRate::Hz50,
)
.unwrap();
imu.set_accel_mode_and_odr(
&mut delay,
AccelMode::Normal,
AccelOutputDataRate::Hz50,
)
.unwrap();
let mut imu = imu.into_mag_continuous().ok().unwrap();
// ãã£ã¹ãã¬ã€ãšã¿ã€ããŒãã»ããã¢ããããŸãã
let mut timer = Timer::new(board.TIMER0);
let mut display = Display::new(board.display_pins);
let mut mode = Mode::Compass;
let mut button_pressed = false;
writeln!(serial, "Ready.").unwrap();
loop {
// ã³ã³ãã¹ããŒã¿ãèªã¿åããã·ãªã¢ã«ããŒãã«èšé²ããŸãã
while !(imu.mag_status().unwrap().xyz_new_data()
&& imu.accel_status().unwrap().xyz_new_data())
{}
let compass_reading = imu.magnetic_field().unwrap();
let accelerometer_reading = imu.acceleration().unwrap();
writeln!(
serial,
"{},{},{}\t{},{},{}",
compass_reading.x_nt(),
compass_reading.y_nt(),
compass_reading.z_nt(),
accelerometer_reading.x_mg(),
accelerometer_reading.y_mg(),
accelerometer_reading.z_mg(),
)
.unwrap();
let mut image = [[0; 5]; 5];
let (x, y) = match mode {
Mode::Compass => (
scale(-compass_reading.x_nt(), -COMPASS_SCALE, COMPASS_SCALE, 0, 4)
as usize,
scale(compass_reading.y_nt(), -COMPASS_SCALE, COMPASS_SCALE, 0, 4)
as usize,
),
Mode::Accelerometer => (
scale(
accelerometer_reading.x_mg(),
-ACCELEROMETER_SCALE,
ACCELEROMETER_SCALE,
0,
4,
) as usize,
scale(
-accelerometer_reading.y_mg(),
-ACCELEROMETER_SCALE,
ACCELEROMETER_SCALE,
0,
4,
) as usize,
),
};
image[y][x] = 255;
display.show(&mut timer, image, 100);
// ãã¿ã³ A ãæŒãããå Žåã次ã®ã¢ãŒãã«åãæ¿ããŠãã¹ãŠã® LED ãçæéç¹æ»
// ãããŸãã
if board.buttons.button_a.is_low().unwrap() {
if !button_pressed {
mode = mode.next();
display.show(&mut timer, [[255; 5]; 5], 200);
}
button_pressed = true;
} else {
button_pressed = false;
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum Mode {
Compass,
Accelerometer,
}
impl Mode {
fn next(self) -> Self {
match self {
Self::Compass => Self::Accelerometer,
Self::Accelerometer => Self::Compass,
}
}
}
fn scale(value: i32, min_in: i32, max_in: i32, min_out: i32, max_out: i32) -> i32 {
let range_in = max_in - min_in;
let range_out = max_out - min_out;
cap(min_out + range_out * (value - min_in) / range_in, min_out, max_out)
}
fn cap(value: i32, min_value: i32, max_value: i32) -> i32 {
max(min_value, min(value, max_value))
}
ã¢ããªã±ãŒã·ã§ã³ããã»ããµ
ãããŸã§ã¯Arm Cortex-Mã·ãªãŒãºã®ãããªãã€ã¯ãã³ã³ãããŒã©ã«ã€ããŠèŠãŠããŸãããä»åºŠã¯Cortex-Aã察象ãšããŠäœããæžããŠã¿ãŸããããç°¡ååã®ããã«ãããã§ã¯ïŒæ¬ç©ã®ããŒããŠã§ã¢ã§ã¯ãªãïŒQEMUã®aarch64 âvirtâããŒããå©çšããŸãã
Speaker Notes
- 倧ãŸãã«èšã£ãŠããã€ã¯ãã³ã³ãããŒã©ãMMUãè€æ°ã®ç¹æš©ã¬ãã«ïŒArm CPUã«ãããäŸå€ã¬ãã«ãx86ã«ããããªã³ã°ïŒãæããªãã®ã«å¯Ÿããã¢ããªã±ãŒã·ã§ã³ããã»ããµã¯ããããæã£ãŠããŸãã
- QEMU ã¯åã ã®ã¢ãŒããã¯ãã£ã«å¯ŸããŠæ§ã ãªç°ãªããã·ã³ãããŒãã¢ãã«ããµããŒãããŠããŸããä»å䜿ã âvirtâ ããŒãã¯ç¹å®ã®æ¬ç©ã®ããŒããŠã§ã¢ã«å¯Ÿå¿ãããã®ã§ã¯ãªããçŽç²ã«ä»®æ³ãã·ã³ãšããŠèšèšããããã®ã§ãã
Rust ã®æºå
Rustã®ã³ãŒããå®è¡ã§ããããã«ãªãåã«ããã€ãã®åæåãå¿ èŠã§ãã
.section .init.entry, "ax"
.global entry
entry:
/*
* Load and apply the memory management configuration, ready to
* enable MMU and caches.
*/
adrp x30, idmap
msr ttbr0_el1, x30
mov_i x30, .Lmairval
msr mair_el1, x30
mov_i x30, .Ltcrval
/* Copy the supported PA range into TCR_EL1.IPS. */
mrs x29, id_aa64mmfr0_el1
bfi x30, x29, #32, #4
msr tcr_el1, x30
mov_i x30, .Lsctlrval
/*
* Ensure everything before this point has completed, then
* invalidate any potentially stale local TLB entries before they
* start being used.
*/
isb
tlbi vmalle1
ic iallu
dsb nsh
isb
/*
* Configure sctlr_el1 to enable MMU and cache and don't proceed
* until this has completed.
*/
msr sctlr_el1, x30
isb
/* Disable trapping floating point access in EL1. */
mrs x30, cpacr_el1
orr x30, x30, #(0x3 << 20)
msr cpacr_el1, x30
isb
/* Zero out the bss section. */
adr_l x29, bss_begin
adr_l x30, bss_end
0: cmp x29, x30
b.hs 1f
stp xzr, xzr, [x29], #16
b 0b
1: /* Prepare the stack. */
adr_l x30, boot_stack_end
mov sp, x30
/* Set up exception vector. */
adr x30, vector_table_el1
msr vbar_el1, x30
/* Call into Rust code. */
bl main
/* Loop forever waiting for interrupts. */
2: wfi
b 2b
Speaker Notes
- ãã®åæåå
容ã¯Cã®å Žåãšåãã«ãªããŸããããã»ããµç¶æ
ãåæåããŠãBSSããŒãåãããŠãã¹ã¿ãã¯ãã€ã³ã¿ãèšå®ããŸãã
- BSSïŒæŽå²çãªçç±ã«ããblock starting symbolãšåŒã°ããŠãããã®ïŒã¯ãªããžã§ã¯ããã¡ã€ã«ã«ãããŠãŒãåæåãããéçãªå€æ°ãå«ãéšåã§ãããã®éšåã¯ãŒãã«ããé åã®æµªè²»ãé¿ããããã«ã€ã¡ãŒãžããã¯é€å€ãããŠããŸããã³ã³ãã€ã©ã¯ããŒãããã®é åããŒãåæåããããšãæ³å®ããŠããã®ã§ãã
- ã¡ã¢ãªã®åæåæ¹æ³ãã€ã¡ãŒãžã®ããŒãæ¹æ³ã«ãã£ãŠã¯BSSã¯ãã§ã«ãŒãåããããŠããããšããããŸãããããã§ã¯å¿µã®çºã«ãŒãåãããŠããŸãã
- ãããªãã¡ã¢ãªã®readãwriteãããåã«MMUãšãã£ãã·ã¥ãæå¹åããå¿
èŠããããŸãããããããªããšïŒ
- ã¢ã©ã€ã³ãããŠããªãã¢ã¯ã»ã¹ããã©ãŒã«ãã«ãªããŸããæã
ã¯ã³ã³ãã€ã©ãã¢ã©ã€ã³ãããŠããªãã¢ã¯ã»ã¹ãçæããªãããã«
+strict-align
ãªãã·ã§ã³ ãèšå®ããaarch64-unknown-none
ã¿ãŒã²ããåãã«Rustã³ãŒãããã«ãããŸãããã®ããããã§ã¯åé¡ã«ã¯ãªããŸããããäžè¬çã«ã¯ãããšã¯èšããŸããã - ããVMäžã§å®è¡ããŠãããšãããšããã£ãã·ã¥ã³ããŒã¬ã³ã·ãŒã®åé¡ãèµ·ããããšããããŸããåé¡ãªã®ã¯VMããã£ãã·ã¥ãç¡å¹åãããŸãŸçŽæ¥ã¡ã¢ãªã«ã¢ã¯ã»ã¹ããŠããã®ã«å¯Ÿãããã¹ãã¯åãã¡ã¢ãªã«å¯ŸããŠãã£ãã·ã¥å¯èœãªãšã€ãªã¢ã¹ãæã£ãŠããŸããšããããšã§ãããã¹ããä»®ã«æ瀺çã«ã¡ã¢ãªã«ã¢ã¯ã»ã¹ããªããšããŠããææ©çãªã¢ã¯ã»ã¹ã«ãããã£ãã·ã¥ãã£ã«ãèµ·ããããšããããŸãããããªããšããã¹ãããã£ãã·ã¥ããã©ãã·ã¥ãããVMããã£ãã·ã¥ãæå¹åãããšãã«ãVMããã¹ãã®ã©ã¡ããã«ããå€æŽã倱ãããŠããŸããŸããïŒãã£ãã·ã¥ã¯ä»®æ³ã¢ãã¬ã¹ãIPAã§ã¯ãªãç©çã¢ãã¬ã¹ãããŒãšããŠã¢ã¯ã»ã¹ãããŸãïŒ
- ã¢ã©ã€ã³ãããŠããªãã¢ã¯ã»ã¹ããã©ãŒã«ãã«ãªããŸããæã
ã¯ã³ã³ãã€ã©ãã¢ã©ã€ã³ãããŠããªãã¢ã¯ã»ã¹ãçæããªãããã«
- åçŽåã®ããã«ãããŒãã³ãŒãããããŒãžããŒãã«ïŒ
idmap.S
åç §ïŒãå©çšããŸãããã®ããŒãžããŒãã«ã¯æåã®1GiBãããã€ã¹çšã«ã次ã®1GiBãDRAMçšã«ã次ã®1GiBããããªãããã€ã¹çšã«ééçã«ãããããŸããããã¯QEMUã®ã¡ã¢ãªã¬ã€ã¢ãŠãã«åèŽããŸãã - äŸå€ãã¯ã¿ïŒ
vbar_el1
ïŒãèšå®ããŸããããã«é¢ããŠã¯åŸã»ã©è©³ããèŠãŸãã - ä»æ¥ã®ååŸã«æ±ããã¹ãŠã®äŸã¯äŸå€ã¬ãã«ïŒïŒEL1ïŒã§å®è¡ãããããšãæ³å®ããŠããŸãããããå¥ã®äŸå€ã¬ãã«ã§å®è¡ããå¿
èŠãããå Žåã«ã¯ã
entry.S
ãããã«åãããŠå€æŽããå¿ èŠããããŸãã
ã€ã³ã©ã€ã³ã¢ã»ã³ããª
ææRustã³ãŒãã§ã¯æžããªãããšãè¡ãããã«ã¢ã»ã³ããªèšèªã䜿ãå¿ èŠããããŸããäŸãã°ãé»æºãèœãšãããã«ãã¡ãŒã ãŠã§ã¢ã«å¯ŸããŠHVCïŒãã€ããŒãã€ã¶ã³ãŒã«ïŒãçºè¡ããå Žåã§ãïŒ
ïŒããå®éã«é»æºãèœãšãããã°ã©ã ãæžãããå Žåã¯ããããã®ãã¹ãŠã®æ©èœã«å¯Ÿããã©ãããŒãæäŸããŠããsmccc
ã䜿ããšè¯ãã§ããããïŒ
Speaker Notes
- PSCI ã¯Armã®Power State Coordination Interfaceã®ããšã§ãããããã¯ã·ã¹ãã ãCPUé»åç¶æ 管çã®æ©èœãå«ãæšæºçãªã»ããã§ããããã¯å€ãã®ã·ã¹ãã ã§EL3ãã¡ãŒã ãŠã§ã¢ãšãã€ããŒãã€ã¶ã«ããå®è£ ãããŠããŸãã
0 => _
ãšããã·ã³ã¿ãã¯ã¹ã¯ãã€ã³ã©ã€ã³ã¢ã»ã³ããªãå®è¡ããåã«ã¬ãžã¹ã¿ããŒãã§åæåããå®è¡åŸã¯ãã®å€ã¯æ°ã«ããªããšããããšã瀺ããŠããŸããin
ã§ã¯ãªãinout
ã䜿ãå¿ èŠãããã®ã¯ããã®å®è¡ã§ã¬ãžã¹ã¿ã®å€ãäžæžãããŠããŸãå¯èœæ§ãããããã§ãã- This
main
function needs to be#[unsafe(no_mangle)]
andextern "C"
because it is called from our entry point inentry.S
. _x0
â_x3
ã¯ã¬ãžã¹ã¿x0
âx3
ã®å€ã§ãããæ £ç¿çã«ããŒãããŒããããã€ã¹ããªãŒãªã©ãžã®ãã€ã³ã¿ãæž¡ãã®ã«å©çšãããŠããŸããïŒextern "C"
ã«ããæå®ãããïŒaarch64 ã®é¢æ°ã³ãŒã«èŠçŽã§ã¯ã¬ãžã¹ã¿x0
âx7
ã¯æåã®ïŒåã®åŒæ°ãé¢æ°ã«æž¡ãã®ã«å©çšãããããšã«ãªã£ãŠãããããentry.S
ã¯ãããã®å€ãå€æŽããªãããã«ãã以å€ã®ç¹å¥ãªããšãããå¿ èŠã¯ãããŸããã- ãã®äŸã
src/bare-metal/aps/examples
ã«ãããŠmake qemu_psci
ãšããããšã§QEMUã«ããå®è¡ããŠã¿ãŸãããã
MMIOã«å¯Ÿããvolatileã¢ã¯ã»ã¹
- Use
pointer::read_volatile
andpointer::write_volatile
. - 絶察ã«åç §ãä¿æããŠã¯ãããŸããã
- Use
&raw
to get fields of structs without creating an intermediate reference.
Speaker Notes
- Volatileã¢ã¯ã»ã¹ïŒMMIOé åã«å¯Ÿããreadãwriteã¯å¯äœçšãããããšãããã®ã§ãã³ã³ãã€ã©ãããŒããŠã§ã¢ãå®è¡é åºãå€æŽããããè€è£œããããçç¥ãããã§ããªãããã«ããããã®ãã®ã§ãã
- éåžžã¯ãäŸãã°ããå¯å€åç §ã«å¯ŸããŠã©ã€ãããªãŒããããšãã³ã³ãã€ã©ã¯ã©ã€ãããã®ãšåãå€ããªãŒãã§èªã¿åºããããšæ³å®ããå®éã«ã¡ã¢ãªããªãŒãããå¿ èŠã¯ãªããšå€æããŸãã
- ããŒããŠã§ã¢ãžã®volatileã¢ã¯ã»ã¹ãè¡ãããã®æ¢åã®ã¯ã¬ãŒãã«ã¯åç §ãä¿æãããã®ããããŸãããããã¯å¥å šã§ã¯ãããŸãããåç §ãååšããéã¯ãã€ã§ãã³ã³ãã€ã©ããã®åç §ãå€ããŠïŒMMIOé åã«ã¢ã¯ã»ã¹ããŠïŒããŸãå¯èœæ§ããããŸãã
- Use
&raw
to get struct field pointers from a pointer to the struct. - For compatibility with old versions of Rust you can use the
addr_of!
macro instead.
UARTãã©ã€ããæžããŠã¿ãŸããã
QEMUã®âvirtâ ãã·ã³ã«ã¯PL011ãšããUARTãããã®ã§ãããã«å¯Ÿãããã©ã€ããæžããŠã¿ãŸãããã
Speaker Notes
Uart::new
ãã¢ã³ã»ãŒãã§ãã®ä»ã®ã¡ãœãããã»ãŒãã§ãããšããããšã«æ³šç®ããŠãã ãããããã¯ãUart::new
ã®å®å šæ§èŠæ±ãæºããããŠããïŒããªãã¡ç¹å®ã®UARTã«å¯ŸããŠäžã€ãããã©ã€ãã®ã€ã³ã¹ã¿ã³ã¹ãååšããããã®ã¢ãã¬ã¹ç©ºéã«å¯ŸããŠãšã€ãªã¢ã¹ãå šãååšããªãïŒããšããã®åŒã³åºãå ãä¿èšŒããéãããã以éã¯å¿ èŠãªäºåæ¡ä»¶ãæºããããŠãããšæ³å®ããããšãã§ãwrite_byte
ãåžžã«å®å šã«åŒã³åºãããšãã§ããããã«ãªãããšãçç±ã§ãã- éã«ïŒ
new
ãã»ãŒãã«ããŠãwrite_byte
ãã¢ã³ã»ãŒãã«ïŒããããšãã§ããŸãããããããããšwrite_byte
ã®å šåŒã³åºãç®æã«ãããŠå®å šæ§ãèæ ®ããªããã°ãªããªããªããå©äŸ¿æ§ãäœäžããŸã - ããã¯ã¢ã³ã»ãŒããªã³ãŒãã«å¯ŸããŠã»ãŒããªã©ãããŒãæ§ç¯ããå Žåã®å ±éãã¿ãŒã³ã§ãïŒå¥å šæ§ã«é¢ãã蚌æã«é¢ããåŽåãå€æ°ã®å Žæããå°æ°ã®å Žæã«éçŽããŸãã
ä»ã®ãã¬ã€ã
ããã§ã¯Debug
ãã¬ã€ããå°åºããŸããããã®ä»ã«ãããã€ãã®ãã¬ã€ããå®è£
ãããšè¯ãã§ãããã
Speaker Notes
Write
ãå®è£ ãããšãUart
ã¿ã€ãã«å¯ŸããŠwrite!
ãšwriteln!
ãã¯ããå©çšã§ããããã«ãªããŸãã- ãã®äŸã
src/bare-metal/aps/examples
ã«ãããŠmake qemu_minimal
ãšããããšã§ãQEMUã«ããå®è¡ããŠã¿ãŸãããã
UARTãã©ã€ãã®æ¹å
å®éã®ãšããPL011ã«ã¯ãã£ãšå€ãã®ã¬ãžã¹ã¿ãããããããã«ã¢ã¯ã»ã¹ããããã«ãªãã»ããã足ããŠãã€ã³ã¿ãåŸãããšã¯ééãã«ãªãããããå¯èªæ§ãäœäžãããŸããããã«ãããã€ãã¯ããããã£ãŒã«ããªã®ã§ãæ§é åãããæ¹æ³ã§ã¢ã¯ã»ã¹ã§ããã»ããè¯ãã§ãããã
ãªãã»ãã | ã¬ãžã¹ã¿å | å¹ |
---|---|---|
0x00 | DR | 12 |
0x04 | RSR | 4 |
0x18 | FR | 9 |
0x20 | ILPR | 8 |
0x24 | IBRD | 16 |
0x28 | FBRD | 6 |
0x2c | LCR_H | 8 |
0x30 | CR | 16 |
0x34 | IFLS | 6 |
0x38 | IMSC | 11 |
0x3c | RIS | 11 |
0x40 | MIS | 11 |
0x44 | ICR | 11 |
0x48 | DMACR | 3 |
Speaker Notes
- ããã€ãã®IDã¬ãžã¹ã¿ã¯ç°¡ååã®ããã®çç¥ããŠããŸãã
ããããã©ãã°
bitflags
ã¯ã¬ãŒãã¯ããããã©ã°ãæ±ãã®ã«äŸ¿å©ã§ãã
Speaker Notes
bitflags!
ãã¯ãã¯Flags(u16)
ã®ãããªæ°ããã¿ã€ããçæãããã©ã°ãèªã¿æžãããããã®å€ãã®ã¡ãœããå®è£ ãäžç·ã«æäŸããŸãã
è€æ°ã®ã¬ãžã¹ã¿
æ§é äœã䜿ã£ãŠUARTã®ã¬ãžã¹ã¿ã®ã¡ã¢ãªã¬ã€ã¢ãŠããè¡šçŸããããšãã§ããŸãã
Speaker Notes
#[repr(C)]
ã¯ã³ã³ãã€ã©ã«å¯ŸããŠãCãšåãèŠåã«åŸã£ãŠæ§é äœã®ãã£ãŒã«ããå®çŸ©ãããŠããé çªã§é 眮ããããšãæ瀺ããŸããããã¯æ§é äœã®ã¬ã€ã¢ãŠããäºæž¬å¯èœã«ããããã«å¿ èŠã§ãããªããªãã°ãRustæšæºã®è¡šçŸã¯ã³ã³ãã€ã©ããã£ãŒã«ãã奜ããªããã«äžŠã³æ¿ããããšïŒä»ã«ãè²ã ãšãããŸããïŒãèš±ããŠããããã§ãã
ãã©ã€ã
æ°ããå®çŸ©ããRegisters
æ§é äœãæã
ã®ãã©ã€ãã§äœ¿ã£ãŠã¿ãŸãããã
Speaker Notes
- Note the use of
&raw const
/&raw mut
to get pointers to individual fields without creating an intermediate reference, which would be unsound.
䜿çšäŸ
æã ã®ãã©ã€ãã䜿ã£ãŠãã·ãªã¢ã«ã³ã³ãœãŒã«ã«ã©ã€ããããããŠå ¥åããããã€ãããšã³ãŒããå°ããªããã°ã©ã ãæžããŠã¿ãŸãããã
Speaker Notes
- ã€ã³ã©ã€ã³ã¢ã»ã³ã㪠ã®äŸãšåãããã«ããã®
main
é¢æ°ã¯entry.S
ã«ããããšã³ããªãã€ã³ãããåŒã³åºãããŸãã詳现ã¯ãã¡ãã®speaker notesãåç §ããŠãã ããã - ãã®äŸã
src/bare-metal/aps/examples
ã«ãããŠmake qemu
ãšããããšã§QEMUã«ããå®è¡ããŠã¿ãŸãããã
ãã°åºå
log
ã¯ã¬ãŒããæäŸãããã°çšãã¯ãã䜿ãããšè¯ãã§ããããããã¯Log
ãã¬ã€ããå®è£
ããããšã§å¯èœã«ãªããŸãã
Speaker Notes
LOGGER
ãset_logger
ãåŒã³åºãåã«åæåããŠããã®ã§ãlog` ã«ãããunwrapã¯ã»ãŒãã§ãã
䜿çšäŸ
䜿çšåã«loggerãåæåããå¿ èŠããããŸãã
Speaker Notes
- æã ã®ãããã¯ãã³ãã©ããããã¯ã®è©³çŽ°ã«ã€ããŠãã°åºåã§ããããã«ãªã£ãããšã«æ³šç®ããŠãã ããã
- ãã®äŸã
src/bare-metal/aps/examples
ã«ãããŠmake qemu_logger
ãšããããšã§QEMUã«ããå®è¡ããŠã¿ãŸãããã
äŸå€
AArch64ã¯16ãšã³ããªãæã€äŸå€ãã¯ã¿ãŒããŒãã«ãå®çŸ©ããŠããããããã¯ïŒã€ã®ã¹ããŒãïŒçŸåšã®ELã§SP0å©çšãçŸåšã®ELã§SPxå©çšãäœäœã®ELã§AArch64ãäœäœã®ELã§AArch32ïŒã«ãããïŒã€ã®ã¿ã€ãã®äŸå€ïŒåæãIRQãFIQãSErrorïŒã«å¯Ÿå¿ããŸããããã§ã¯Rustã³ãŒãã®åŒã³åºãåã«æ®çºã¬ãžã¹ã¿ã®å€ãã¹ã¿ãã¯ã«éé¿ããããã«ãã¯ã¿ãŒããŒãã«ãã¢ã»ã³ããªèšèªã§å®è£ ããŠããŸãïŒ
Speaker Notes
- ELã¯äŸå€ã¬ãã«ã§ããæ¬æ¥ã®ååŸã«æ±ã£ããã¹ãŠã®äŸã¯EL1ã§å®è¡ãããŠããŸãã
- ç°¡ååã®ããã«ãããã§ã¯çŸåšã®ELäŸå€ã«ãããSP0ãšSPïœã®éããäœäœã®ELã¬ãã«ã«ãããAArch32ãšAArch64ã®éããåºå¥ããŠããŸããã
- ããã§ã¯ãããã®äŸå€ãçºçããªãã¯ããªã®ã§ããã äŸå€ã«é¢ãããã°ãåºåããé»æºãèœãšããŠããŸãã
- äŸå€ãã³ãã©ãšã¡ã€ã³ã®å®è¡ã³ã³ããã¹ãã¯ç°ãªãã¹ã¬ããã®ãããªãã®ã ãšèããããšãã§ããŸããã¡ããã©ã¹ã¬ããéã®å
±æãšåãããã«ã
Send
ãšSync
ã«ããäœãå ±æããããå¶åŸ¡ããããšãã§ããŸããäŸãã°ãäŸå€ãã³ãã©ãšããã°ã©ã ã®ä»ã®ã³ã³ããã¹ãã§ãšããå€ãå ±æãããå Žåã«ããããããSend
ã§ããSync
ã§ãªããã°ãMutex
ã®ãããªãã®ã§ã©ããããŠãstaticã«å®çŸ©ããªããã°ãªããŸããã
ä»ã®ãããžã§ã¯ã
- oreboot
- âcoreboot without the Câ.
- ã¢ãŒããã¯ãã£ã¯x86ãaarch64ãªãã³ã«RISC-VããµããŒãã
- èªèº«ã§å€ãã®ãã©ã€ããæ±ããã«LinuxBootã«äŸåã
- Rust RaspberryPi OS ã®ãã¥ãŒããªã¢ã«
- Initialisation, UART driver, simple bootloader, JTAG, exception levels, exception handling, page tables.
- ãã£ãã·ã¥ã¡ã³ããã³ã¹ãšRustã®åæåã«é¢ããŠã¡ãã£ãšçããããšãããããã®ã§ã補åã³ãŒãã§ç䌌ããã«ã¯å¿ ãããè¯ãäŸã§ã¯ãããŸããã
cargo-call-stack
- ã¹ã¿ãã¯ã®æ倧䜿çšéã«é¢ããéç解æã
Speaker Notes
- RaspberryPi OS ãã¥ãŒããªã¢ã«ã¯MMUããã£ãã·ã¥ãæå¹åããåã«Rustã³ãŒããå®è¡ããŠããŸããããã«ãããäŸãã°ã¹ã¿ãã¯ã¡ã¢ãªãreadãããwriteãããããããšã«ãªããŸãããããïŒ
- MMUãšãã£ãã·ã¥ãæå¹åããŠããªããšãã¢ã©ã€ã³ãããŠããªãã¢ã¯ã»ã¹ã¯ãã©ãŒã«ããåŒãèµ·ãããŸãããã®ãã¥ãŒããªã¢ã«ã§ã¯ãã³ã³ãã€ã©ãã¢ã©ã€ã³ãããŠããªãã¢ã¯ã»ã¹ãçæããªã
+strict-align
ãªãã·ã§ã³ãã»ããããaarch64-unknown-none
ãã¿ãŒã²ãããšããŠãã«ãããŠããã®ã§å€§äžå€«ãªã¯ãã§ãããäžè¬çã«ã¯å€§äžå€«ãšã¯éããŸããã - ããVMäžã§å®è¡ããŠãããšãããšããã£ãã·ã¥ã³ããŒã¬ã³ã·ãŒã®åé¡ãèµ·ããããšããããŸããåé¡ãªã®ã¯VMããã£ãã·ã¥ãç¡å¹åãããŸãŸçŽæ¥ã¡ã¢ãªã«ã¢ã¯ã»ã¹ããŠããã®ã«å¯Ÿãããã¹ãã¯åãã¡ã¢ãªã«å¯ŸããŠãã£ãã·ã¥å¯èœãªãšã€ãªã¢ã¹ãæã£ãŠããŸããšããããšã§ãããã¹ããä»®ã«æ瀺çã«ã¡ã¢ãªã«ã¢ã¯ã»ã¹ããªããšããŠããææ©çãªã¢ã¯ã»ã¹ã«ãããã£ãã·ã¥ãã£ã«ãèµ·ããããšãããããããªããšVMããã¹ãã®ã©ã¡ããã«ããå€æŽã倱ãããŠããŸããŸãããã®ïŒãã€ããŒãã€ã¶ãªãã§çŽæ¥ããŒããŠã§ã¢ã§å®è¡ããïŒå Žåã«ã¯åé¡ã«ã¯ãªããŸããããäžè¬çã«ã¯è¯ããªããã¿ãŒã³ã§ãã
- MMUãšãã£ãã·ã¥ãæå¹åããŠããªããšãã¢ã©ã€ã³ãããŠããªãã¢ã¯ã»ã¹ã¯ãã©ãŒã«ããåŒãèµ·ãããŸãããã®ãã¥ãŒããªã¢ã«ã§ã¯ãã³ã³ãã€ã©ãã¢ã©ã€ã³ãããŠããªãã¢ã¯ã»ã¹ãçæããªã
䟿å©ã¯ã¬ãŒã
ãã¢ã¡ã¿ã«ããã°ã©ãã³ã°ã«ãããŠå ±éã«çºçããåé¡ã«å¯Ÿãã解ãäžããã¯ã¬ãŒãã«ã€ããŠããã€ã玹ä»ããŸãã
zerocopy
ïŒFuchsiaã®ïŒzerocopy
ã¯ã¬ãŒãã¯ãã€ãã·ãŒã±ã³ã¹ãšãã®ä»ã®åã®å€æãå®å
šã«è¡ãããã®ãã¬ã€ãããã¯ããæäŸããŸãã
ããã¯ïŒvolatile readãwriteã䜿çšããŠããªãããïŒMMIOã«ã¯é©ããŠãŸããããäŸãã°DMAã®ãããªããŒããŠã§ã¢ãšå ±æããããŒã¿æ§é ãããã¯å€éšã€ã³ã¿ãã§ãŒã¹ãéããŠéä¿¡ããããŒã¿æ§é ãæ±ãã«å Žåã«ã¯æçšã§ãã
Speaker Notes
FromBytes
ã¯ãããªããã€ããã¿ãŒã³ãæå¹ãªå€ãšãªãåã«å¯ŸããŠå®è£ ããããšãã§ããä¿¡çšã§ããªããã€ãã·ãŒã±ã³ã¹ããã®å®å šãªå€æãå¯èœã«ããŸããRequestType
ã¯u32åã®ãã¹ãŠã®å€ãæå¹ãªenumå€ãšããŠå®çŸ©ããŠããªãã®ã§ããã¹ãŠã®ãã€ããã¿ãŒã³ãæå¹ãšã¯ãªããããããã«å¯ŸããFromBytes
ã®å°åºã¯ãã§ãŒã«ããã§ããããzerocopy::byteorder
ã¯ãã€ããªãŒããæ°ã«ããæ°å€ããªããã£ãã«é¢ããåãæäŸããŸãã- ãã®äŸã
src/bare-metal/useful-crates/zerocopy-example/
ã«ãããŠcargo run
ãšãšããããšã§å®è¡ããŠã¿ãŸããããïŒPlaygroundã§ã¯ãã®äŸãäŸåããã¯ã¬ãŒããå©çšã§ããªãããå®è¡ã§ããŸããïŒ
aarch64-paging
aarch64-paging
ã¯ã¬ãŒãã¯AArch64ä»®æ³ã¡ã¢ãªã·ã¹ãã ã¢ãŒããã¯ãã£ã«åã£ãããŒãžããŒãã«ã®çæãå¯èœã«ããŸãã
Speaker Notes
- çŸæç¹ã§ã¯EL1ãããµããŒããããŠããŸããããä»ã®äŸå€ã¬ãã«ã®ãµããŒããç°¡åã«è¿œå ã§ããã¯ãã§ãã
- ããã¯Androidã§Protected VM Firmwareã®ããã«å©çšãããŠããŸãã
- ãã®äŸã¯æ¬ç©ã®ããŒããŠã§ã¢ãQEMUãå¿ èŠãšããã®ã§ãç°¡åã«ã¯å®è¡ã§ããŸããã
buddy_system_allocator
buddy_system_allocator
ã¯ãµãŒãããŒãã£ã®ã¯ã¬ãŒãã§ãåºæ¬çãªããã£ã·ã¹ãã ã¢ããŒã±ãŒã¿ãå®è£
ããŠããŸãããã®ã¯ã¬ãŒãã¯GlobalAlloc
ãå®è£
ãã LockedHeap
ã«ããïŒ ä»¥åèŠãããã«ïŒæšæºã®alloc
ã¯ã¬ãŒããå©çšå¯èœã«ããããã«äœ¿ããŸãããå¥ã®ã¢ãã¬ã¹ç©ºéãã¢ãã±ãŒãããããã«ã䜿ããŸããäŸãã°ãPCI BARã«å¯ŸããMMIOé åãã¢ãã±ãŒããããå Žåã«ã¯ä»¥äžã®ããã«ã§ããŸãïŒ
Speaker Notes
- PCI BARã¯åžžã«ãµã€ãºãšåãã¢ã©ã€ã³ã«ãªããŸãã
- ãã®äŸã
src/bare-metal/useful-crates/allocator-example/
ã«ãããŠcargo run
ãšããããšã§å®è¡ããŠã¿ãŸããããïŒPlaygroundã§ã¯ãã®äŸãäŸåããã¯ã¬ãŒããå©çšã§ããªãããå®è¡ã§ããŸããïŒ
tinyvec
æã«ã¯Vec
ã®ããã«ãªãµã€ãºã§ããé åãããŒãã䜿ããã«ç¢ºä¿ããããšæãããšããããŸããtinyvec
ã¯éçã«ç¢ºä¿ããŸãã¯ã¹ã¿ãã¯äžã«ç¢ºä¿ããé
åãŸãã¯ã¹ã©ã€ã¹ãå²åœé åãšãããã¯ã¿ãæäŸããŸãããã®å®è£
ã§ã¯ãããã€ã®èŠçŽ ã䜿ãããŠãããã管çããã確ä¿ããã以äžã«äœ¿ãããšãããšãããã¯ããŸãã
Speaker Notes
tinyvec
ã¯åæåã®ããã«èŠçŽ ãšãªãã¿ã€ããDefault
ãå®è£ ããããšãå¿ èŠãšããŸãã- Rust Playgroundã¯
tinyvec
ãå å ããŠããã®ã§ããªã³ã©ã€ã³ã§ãã®äŸãå®è¡ããããšãã§ããŸãã
spin
std::sync
ãæäŸããstd::sync::Mutex
ãšãã®ä»ã®åæããªããã£ãã¯core
ãŸãã¯alloc
ã§ã¯å©çšã§ããŸããããšãªããšãäŸãã°ç°ãªãCPUéã§ã®ç¶æ
å
±æã®ããã®ãåæãå
éšå¯å€æ§ã¯ã©ã®ããã«å®çŸãããè¯ãã®ã§ããããïŒ
spin
ã¯ã¬ãŒãã¯ãããã®å€ãã®ããªããã£ããšç䟡ãªã¹ãã³ããã¯ããŒã¹ã®ãã®ãæäŸããŸãã
Speaker Notes
- å²ã蟌ã¿ãã³ãã©ã§ããã¯ãååŸããå Žåã«ã¯ãããããã¯ãåŒãèµ·ãããªãããã«æ°ãã€ããŠãã ããã
spin
also has a ticket lock mutex implementation; equivalents ofRwLock
,Barrier
andOnce
fromstd::sync
; andLazy
for lazy initialisation.once_cell
ã¯ã¬ãŒããspin::once::Once
ãšã¯å°ãç°ãªãã¢ãããŒãã®é 延åæåã®ããã®æçšãªåãããã€ãæã£ãŠããŸãã- Rust Playgroundã¯
spin
ãå å ããŠããã®ã§ããã®äŸã¯ãªã³ã©ã€ã³ã§å®è¡ã§ããŸãã
Androidäžã®ãã¢ã¡ã¿ã«
AOSPã«ãããŠãã¢ã¡ã¿ã«Rustãã€ããªããã«ãããããã«ã¯ãRustã³ãŒãããã«ãããããã®rust_ffi_static
ãšããSoongã«ãŒã«ããªã³ã«ã¹ã¯ãªãããšããã䜿ã£ãŠãã€ããªãçæããããã®cc_binary
ãšããã«ãŒã«ãããã«ELFãå®è¡å¯èœãªåœ¢åŒã®çãã€ããªã«å€æããraw_binary
ãšããã«ãŒã«ãå¿
èŠã§ãã
rust_ffi_static {
name: "libvmbase_example",
defaults: ["vmbase_ffi_defaults"],
crate_name: "vmbase_example",
srcs: ["src/main.rs"],
rustlibs: [
"libvmbase",
],
}
cc_binary {
name: "vmbase_example",
defaults: ["vmbase_elf_defaults"],
srcs: [
"idmap.S",
],
static_libs: [
"libvmbase_example",
],
linker_scripts: [
"image.ld",
":vmbase_sections",
],
}
raw_binary {
name: "vmbase_example_bin",
stem: "vmbase_example.bin",
src: ":vmbase_example",
enabled: false,
target: {
android_arm64: {
enabled: true,
},
},
}
vmbase
For VMs running under crosvm on aarch64, the vmbase library provides a linker script and useful defaults for the build rules, along with an entry point, UART console logging and more.
#![no_main]
#![no_std]
use vmbase::{main, println};
main!(main);
pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
println!("Hello world");
}
Speaker Notes
main!
ãšãããã¯ãã¯ã¡ã€ã³é¢æ°ãæå®ãããã®ã§ãæå®ãããé¢æ°ã¯vmbase
ã®ãšã³ããªãã€ã³ãããåŒã³åºãããããšã«ãªããŸããvmbase
ã®ãšã³ããªãã€ã³ãã¯ã³ã³ãœãŒã«ã®åæåãè¡ããã¡ã€ã³é¢æ°ããªã¿ãŒã³ããå Žåã«ã¯PSCI_SYSTEM_OFF ãçºè¡ãVMãã·ã£ããããŠã³ããŸãã
ç·Žç¿åé¡
PL031 ãªã¢ã«ã¿ã€ã ã¯ãã㯠ããã€ã¹çšã®ãã©ã€ããäœæããŸãã
Speaker Notes
æŒç¿ã®çµäºåŸã¯ãæäŸãããŠãã ãœãªã¥ãŒã·ã§ã³ ã確èªããŠãã ããã
RTC ãã©ã€ã
QEMU aarch64 virt ãã·ã³ã® 0x9010000 ã«ã¯ãPL031 ãªã¢ã«ã¿ã€ã ã¯ããã¯ãæèŒãããŠããŸãããã®æŒç¿ã§ã¯ããã®ãã©ã€ããäœæããå¿ èŠããããŸãã
- ããã䜿çšããŠçŸåšã®æå»ãã·ãªã¢ã« ã³ã³ãœãŒã«ã«åºåããŸããæ¥æã®åœ¢åŒã«ã¯
chrono
ã¯ã¬ãŒãã䜿çšã§ããŸãã - äžèŽã¬ãžã¹ã¿ãšæªå å·¥ã®å²ã蟌ã¿ã¹ããŒã¿ã¹ã䜿çšããŠãæå®æå»ïŒããšãã° 3 ç§åŸïŒãŸã§ããžãŒãŠã§ã€ãããŸãïŒã«ãŒãå
ã§
core::hint::spin_loop
ãåŒã³åºããŸãïŒã - æéãããå Žåã¯ãRTC ã®äžèŽã«ãã£ãŠçæãããå²ã蟌ã¿ãæå¹ã«ããŠåŠçããŸãã
arm-gic
ã¯ã¬ãŒãã§æäŸãããŠãããã©ã€ãã䜿çšããŠãArm æ±çšå²ã蟌ã¿ã³ã³ãããŒã©ãèšå®ããŠæ§ããŸããã- RTC å²ã蟌ã¿ã䜿çšããŸãããã®å²ã蟌ã¿ã¯ GIC ã«
IntId::spi(2)
ãšããŠæ¥ç¶ãããŠããŸãã - å²ã蟌ã¿ãæå¹ã«ãããšã
arm_gic::wfi()
ã䜿çšããŠã³ã¢ãã¹ãªãŒããããããšãã§ããŸããããã«ãããã³ã¢ã¯å²ã蟌ã¿ãåãããŸã§ã¹ãªãŒãç¶æ ã«ãªããŸãã
- RTC å²ã蟌ã¿ã䜿çšããŸãããã®å²ã蟌ã¿ã¯ GIC ã«
æŒç¿ãã³ãã¬ãŒã ãããŠã³ããŒãããrtc
ãã£ã¬ã¯ããªã§ä»¥äžã®ãã¡ã€ã«ãæ¢ããŸãã
src/main.rs:
#![no_main]
#![no_std]
mod exceptions;
mod logger;
mod pl011;
use crate::pl011::Uart;
use arm_gic::gicv3::GicV3;
use core::panic::PanicInfo;
use log::{error, info, trace, LevelFilter};
use smccc::psci::system_off;
use smccc::Hvc;
/// Base addresses of the GICv3.
const GICD_BASE_ADDRESS: *mut u64 = 0x800_0000 as _;
const GICR_BASE_ADDRESS: *mut u64 = 0x80A_0000 as _;
/// Base address of the primary PL011 UART.
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
// nothing else accesses that address range.
let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };
logger::init(uart, LevelFilter::Trace).unwrap();
info!("main({:#x}, {:#x}, {:#x}, {:#x})", x0, x1, x2, x3);
// SAFETY: `GICD_BASE_ADDRESS` and `GICR_BASE_ADDRESS` are the base
// addresses of a GICv3 distributor and redistributor respectively, and
// nothing else accesses those address ranges.
let mut gic = unsafe { GicV3::new(GICD_BASE_ADDRESS, GICR_BASE_ADDRESS) };
gic.setup();
// TODO: Create instance of RTC driver and print current time.
// TODO: Wait for 3 seconds.
system_off::<Hvc>().unwrap();
}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
error!("{info}");
system_off::<Hvc>().unwrap();
loop {}
}
src/exceptions.rsïŒãã®æŒç¿ã® 3 çªç®ã®ããŒãã§ã®ã¿å€æŽããå¿ èŠããããŸãïŒ:
src/logger.rsïŒå€æŽããå¿ èŠã¯ãããŸããïŒ:
src/pl011.rsïŒå€æŽããå¿ èŠã¯ãããŸããïŒ:
Cargo.toml (å€æŽã¯äžèŠãªã¯ãã§ã):
[workspace]
[package]
name = "rtc"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
arm-gic = "0.1.1"
bitflags = "2.6.0"
chrono = { version = "0.4.38", default-features = false }
log = "0.4.22"
smccc = "0.1.1"
spin = "0.9.8"
[build-dependencies]
cc = "1.1.31"
build.rsïŒå€æŽããå¿ èŠã¯ãããŸããïŒ:
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use cc::Build;
use std::env;
fn main() {
env::set_var("CROSS_COMPILE", "aarch64-none-elf");
env::set_var("CC", "clang");
Build::new()
.file("entry.S")
.file("exceptions.S")
.file("idmap.S")
.compile("empty")
}
entry.SïŒå€æŽããå¿ èŠã¯ãããŸããïŒ:
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.macro adr_l, reg:req, sym:req
adrp \reg, \sym
add \reg, \reg, :lo12:\sym
.endm
.macro mov_i, reg:req, imm:req
movz \reg, :abs_g3:\imm
movk \reg, :abs_g2_nc:\imm
movk \reg, :abs_g1_nc:\imm
movk \reg, :abs_g0_nc:\imm
.endm
.set .L_MAIR_DEV_nGnRE, 0x04
.set .L_MAIR_MEM_WBWA, 0xff
.set .Lmairval, .L_MAIR_DEV_nGnRE | (.L_MAIR_MEM_WBWA << 8)
/* 4 KiB granule size for TTBR0_EL1. */
.set .L_TCR_TG0_4KB, 0x0 << 14
/* 4 KiB granule size for TTBR1_EL1. */
.set .L_TCR_TG1_4KB, 0x2 << 30
/* Disable translation table walk for TTBR1_EL1, generating a translation fault instead. */
.set .L_TCR_EPD1, 0x1 << 23
/* Translation table walks for TTBR0_EL1 are inner sharable. */
.set .L_TCR_SH_INNER, 0x3 << 12
/*
* Translation table walks for TTBR0_EL1 are outer write-back read-allocate write-allocate
* cacheable.
*/
.set .L_TCR_RGN_OWB, 0x1 << 10
/*
* Translation table walks for TTBR0_EL1 are inner write-back read-allocate write-allocate
* cacheable.
*/
.set .L_TCR_RGN_IWB, 0x1 << 8
/* Size offset for TTBR0_EL1 is 2**39 bytes (512 GiB). */
.set .L_TCR_T0SZ_512, 64 - 39
.set .Ltcrval, .L_TCR_TG0_4KB | .L_TCR_TG1_4KB | .L_TCR_EPD1 | .L_TCR_RGN_OWB
.set .Ltcrval, .Ltcrval | .L_TCR_RGN_IWB | .L_TCR_SH_INNER | .L_TCR_T0SZ_512
/* Stage 1 instruction access cacheability is unaffected. */
.set .L_SCTLR_ELx_I, 0x1 << 12
/* SP alignment fault if SP is not aligned to a 16 byte boundary. */
.set .L_SCTLR_ELx_SA, 0x1 << 3
/* Stage 1 data access cacheability is unaffected. */
.set .L_SCTLR_ELx_C, 0x1 << 2
/* EL0 and EL1 stage 1 MMU enabled. */
.set .L_SCTLR_ELx_M, 0x1 << 0
/* Privileged Access Never is unchanged on taking an exception to EL1. */
.set .L_SCTLR_EL1_SPAN, 0x1 << 23
/* SETEND instruction disabled at EL0 in aarch32 mode. */
.set .L_SCTLR_EL1_SED, 0x1 << 8
/* Various IT instructions are disabled at EL0 in aarch32 mode. */
.set .L_SCTLR_EL1_ITD, 0x1 << 7
.set .L_SCTLR_EL1_RES1, (0x1 << 11) | (0x1 << 20) | (0x1 << 22) | (0x1 << 28) | (0x1 << 29)
.set .Lsctlrval, .L_SCTLR_ELx_M | .L_SCTLR_ELx_C | .L_SCTLR_ELx_SA | .L_SCTLR_EL1_ITD | .L_SCTLR_EL1_SED
.set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1
/**
* This is a generic entry point for an image. It carries out the operations required to prepare the
* loaded image to be run. Specifically, it zeroes the bss section using registers x25 and above,
* prepares the stack, enables floating point, and sets up the exception vector. It preserves x0-x3
* for the Rust entry point, as these may contain boot parameters.
*/
.section .init.entry, "ax"
.global entry
entry:
/* Load and apply the memory management configuration, ready to enable MMU and caches. */
adrp x30, idmap
msr ttbr0_el1, x30
mov_i x30, .Lmairval
msr mair_el1, x30
mov_i x30, .Ltcrval
/* Copy the supported PA range into TCR_EL1.IPS. */
mrs x29, id_aa64mmfr0_el1
bfi x30, x29, #32, #4
msr tcr_el1, x30
mov_i x30, .Lsctlrval
/*
* Ensure everything before this point has completed, then invalidate any potentially stale
* local TLB entries before they start being used.
*/
isb
tlbi vmalle1
ic iallu
dsb nsh
isb
/*
* Configure sctlr_el1 to enable MMU and cache and don't proceed until this has completed.
*/
msr sctlr_el1, x30
isb
/* Disable trapping floating point access in EL1. */
mrs x30, cpacr_el1
orr x30, x30, #(0x3 << 20)
msr cpacr_el1, x30
isb
/* Zero out the bss section. */
adr_l x29, bss_begin
adr_l x30, bss_end
0: cmp x29, x30
b.hs 1f
stp xzr, xzr, [x29], #16
b 0b
1: /* Prepare the stack. */
adr_l x30, boot_stack_end
mov sp, x30
/* Set up exception vector. */
adr x30, vector_table_el1
msr vbar_el1, x30
/* Call into Rust code. */
bl main
/* Loop forever waiting for interrupts. */
2: wfi
b 2b
exceptions.SïŒå€æŽããå¿ èŠã¯ãããŸããïŒ:
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Saves the volatile registers onto the stack. This currently takes 14
* instructions, so it can be used in exception handlers with 18 instructions
* left.
*
* On return, x0 and x1 are initialised to elr_el2 and spsr_el2 respectively,
* which can be used as the first and second arguments of a subsequent call.
*/
.macro save_volatile_to_stack
/* Reserve stack space and save registers x0-x18, x29 & x30. */
stp x0, x1, [sp, #-(8 * 24)]!
stp x2, x3, [sp, #8 * 2]
stp x4, x5, [sp, #8 * 4]
stp x6, x7, [sp, #8 * 6]
stp x8, x9, [sp, #8 * 8]
stp x10, x11, [sp, #8 * 10]
stp x12, x13, [sp, #8 * 12]
stp x14, x15, [sp, #8 * 14]
stp x16, x17, [sp, #8 * 16]
str x18, [sp, #8 * 18]
stp x29, x30, [sp, #8 * 20]
/*
* Save elr_el1 & spsr_el1. This such that we can take nested exception
* and still be able to unwind.
*/
mrs x0, elr_el1
mrs x1, spsr_el1
stp x0, x1, [sp, #8 * 22]
.endm
/**
* Restores the volatile registers from the stack. This currently takes 14
* instructions, so it can be used in exception handlers while still leaving 18
* instructions left; if paired with save_volatile_to_stack, there are 4
* instructions to spare.
*/
.macro restore_volatile_from_stack
/* Restore registers x2-x18, x29 & x30. */
ldp x2, x3, [sp, #8 * 2]
ldp x4, x5, [sp, #8 * 4]
ldp x6, x7, [sp, #8 * 6]
ldp x8, x9, [sp, #8 * 8]
ldp x10, x11, [sp, #8 * 10]
ldp x12, x13, [sp, #8 * 12]
ldp x14, x15, [sp, #8 * 14]
ldp x16, x17, [sp, #8 * 16]
ldr x18, [sp, #8 * 18]
ldp x29, x30, [sp, #8 * 20]
/* Restore registers elr_el1 & spsr_el1, using x0 & x1 as scratch. */
ldp x0, x1, [sp, #8 * 22]
msr elr_el1, x0
msr spsr_el1, x1
/* Restore x0 & x1, and release stack space. */
ldp x0, x1, [sp], #8 * 24
.endm
/**
* This is a generic handler for exceptions taken at the current EL while using
* SP0. It behaves similarly to the SPx case by first switching to SPx, doing
* the work, then switching back to SP0 before returning.
*
* Switching to SPx and calling the Rust handler takes 16 instructions. To
* restore and return we need an additional 16 instructions, so we can implement
* the whole handler within the allotted 32 instructions.
*/
.macro current_exception_sp0 handler:req
msr spsel, #1
save_volatile_to_stack
bl \handler
restore_volatile_from_stack
msr spsel, #0
eret
.endm
/**
* This is a generic handler for exceptions taken at the current EL while using
* SPx. It saves volatile registers, calls the Rust handler, restores volatile
* registers, then returns.
*
* This also works for exceptions taken from EL0, if we don't care about
* non-volatile registers.
*
* Saving state and jumping to the Rust handler takes 15 instructions, and
* restoring and returning also takes 15 instructions, so we can fit the whole
* handler in 30 instructions, under the limit of 32.
*/
.macro current_exception_spx handler:req
save_volatile_to_stack
bl \handler
restore_volatile_from_stack
eret
.endm
.section .text.vector_table_el1, "ax"
.global vector_table_el1
.balign 0x800
vector_table_el1:
sync_cur_sp0:
current_exception_sp0 sync_exception_current
.balign 0x80
irq_cur_sp0:
current_exception_sp0 irq_current
.balign 0x80
fiq_cur_sp0:
current_exception_sp0 fiq_current
.balign 0x80
serr_cur_sp0:
current_exception_sp0 serr_current
.balign 0x80
sync_cur_spx:
current_exception_spx sync_exception_current
.balign 0x80
irq_cur_spx:
current_exception_spx irq_current
.balign 0x80
fiq_cur_spx:
current_exception_spx fiq_current
.balign 0x80
serr_cur_spx:
current_exception_spx serr_current
.balign 0x80
sync_lower_64:
current_exception_spx sync_lower
.balign 0x80
irq_lower_64:
current_exception_spx irq_lower
.balign 0x80
fiq_lower_64:
current_exception_spx fiq_lower
.balign 0x80
serr_lower_64:
current_exception_spx serr_lower
.balign 0x80
sync_lower_32:
current_exception_spx sync_lower
.balign 0x80
irq_lower_32:
current_exception_spx irq_lower
.balign 0x80
fiq_lower_32:
current_exception_spx fiq_lower
.balign 0x80
serr_lower_32:
current_exception_spx serr_lower
idmap.S (you shouldnât need to change this):
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.set .L_TT_TYPE_BLOCK, 0x1
.set .L_TT_TYPE_PAGE, 0x3
.set .L_TT_TYPE_TABLE, 0x3
/* Access flag. */
.set .L_TT_AF, 0x1 << 10
/* Not global. */
.set .L_TT_NG, 0x1 << 11
.set .L_TT_XN, 0x3 << 53
.set .L_TT_MT_DEV, 0x0 << 2 // MAIR #0 (DEV_nGnRE)
.set .L_TT_MT_MEM, (0x1 << 2) | (0x3 << 8) // MAIR #1 (MEM_WBWA), inner shareable
.set .L_BLOCK_DEV, .L_TT_TYPE_BLOCK | .L_TT_MT_DEV | .L_TT_AF | .L_TT_XN
.set .L_BLOCK_MEM, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_NG
.section ".rodata.idmap", "a", %progbits
.global idmap
.align 12
idmap:
/* level 1 */
.quad .L_BLOCK_DEV | 0x0 // 1 GiB of device mappings
.quad .L_BLOCK_MEM | 0x40000000 // 1 GiB of DRAM
.fill 254, 8, 0x0 // 254 GiB of unmapped VA space
.quad .L_BLOCK_DEV | 0x4000000000 // 1 GiB of device mappings
.fill 255, 8, 0x0 // 255 GiB of remaining VA space
image.ldïŒå€æŽããå¿ èŠã¯ãããŸããïŒ:
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Code will start running at this symbol which is placed at the start of the
* image.
*/
ENTRY(entry)
MEMORY
{
image : ORIGIN = 0x40080000, LENGTH = 2M
}
SECTIONS
{
/*
* Collect together the code.
*/
.init : ALIGN(4096) {
text_begin = .;
*(.init.entry)
*(.init.*)
} >image
.text : {
*(.text.*)
} >image
text_end = .;
/*
* Collect together read-only data.
*/
.rodata : ALIGN(4096) {
rodata_begin = .;
*(.rodata.*)
} >image
.got : {
*(.got)
} >image
rodata_end = .;
/*
* Collect together the read-write data including .bss at the end which
* will be zero'd by the entry code.
*/
.data : ALIGN(4096) {
data_begin = .;
*(.data.*)
/*
* The entry point code assumes that .data is a multiple of 32
* bytes long.
*/
. = ALIGN(32);
data_end = .;
} >image
/* Everything beyond this point will not be included in the binary. */
bin_end = .;
/* The entry point code assumes that .bss is 16-byte aligned. */
.bss : ALIGN(16) {
bss_begin = .;
*(.bss.*)
*(COMMON)
. = ALIGN(16);
bss_end = .;
} >image
.stack (NOLOAD) : ALIGN(4096) {
boot_stack_begin = .;
. += 40 * 4096;
. = ALIGN(4096);
boot_stack_end = .;
} >image
. = ALIGN(4K);
PROVIDE(dma_region = .);
/*
* Remove unused sections from the image.
*/
/DISCARD/ : {
/* The image loads itself so doesn't need these sections. */
*(.gnu.hash)
*(.hash)
*(.interp)
*(.eh_frame_hdr)
*(.eh_frame)
*(.note.gnu.build-id)
}
}
MakefileïŒå€æŽããå¿ èŠã¯ãããŸããïŒ:
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
.PHONY: build qemu_minimal qemu qemu_logger
all: rtc.bin
build:
cargo build
rtc.bin: build
cargo objcopy -- -O binary $@
qemu: rtc.bin
qemu-system-aarch64 -machine virt,gic-version=3 -cpu max -serial mon:stdio -display none -kernel $< -s
clean:
cargo clean
rm -f *.bin
.cargo/config.toml (å€æŽã¯äžèŠãªã¯ãã§ã):
[build]
target = "aarch64-unknown-none"
rustflags = ["-C", "link-arg=-Timage.ld"]
make qemu
ã«ããQEMU ã§ã³ãŒããå®è¡ããŸãã
ãã¢ã¡ã¿ã«Rust PM
RTC ãã©ã€ã
ïŒæŒç¿ã«æ»ãïŒ
main.rs:
#![no_main]
#![no_std]
mod exceptions;
mod logger;
mod pl011;
mod pl031;
use crate::pl031::Rtc;
use arm_gic::gicv3::{IntId, Trigger};
use arm_gic::{irq_enable, wfi};
use chrono::{TimeZone, Utc};
use core::hint::spin_loop;
use crate::pl011::Uart;
use arm_gic::gicv3::GicV3;
use core::panic::PanicInfo;
use log::{error, info, trace, LevelFilter};
use smccc::psci::system_off;
use smccc::Hvc;
/// GICv3 ã®ããŒã¹ã¢ãã¬ã¹ã
const GICD_BASE_ADDRESS: *mut u64 = 0x800_0000 as _;
const GICR_BASE_ADDRESS: *mut u64 = 0x80A_0000 as _;
/// ãã©ã€ã㪠PL011 UART ã®ããŒã¹ã¢ãã¬ã¹ã
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
/// PL031 RTC ã®ããŒã¹ã¢ãã¬ã¹ã
const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;
/// PL031 RTC ã䜿çšãã IRQã
const PL031_IRQ: IntId = IntId::spi(2);
// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
// nothing else accesses that address range.
let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };
logger::init(uart, LevelFilter::Trace).unwrap();
info!("main({:#x}, {:#x}, {:#x}, {:#x})", x0, x1, x2, x3);
// SAFETY: `GICD_BASE_ADDRESS` and `GICR_BASE_ADDRESS` are the base
// addresses of a GICv3 distributor and redistributor respectively, and
// nothing else accesses those address ranges.
let mut gic = unsafe { GicV3::new(GICD_BASE_ADDRESS, GICR_BASE_ADDRESS) };
gic.setup();
// SAFETY: `PL031_BASE_ADDRESS` is the base address of a PL031 device, and
// nothing else accesses that address range.
let mut rtc = unsafe { Rtc::new(PL031_BASE_ADDRESS) };
let timestamp = rtc.read();
let time = Utc.timestamp_opt(timestamp.into(), 0).unwrap();
info!("RTC: {time}");
GicV3::set_priority_mask(0xff);
gic.set_interrupt_priority(PL031_IRQ, 0x80);
gic.set_trigger(PL031_IRQ, Trigger::Level);
irq_enable();
gic.enable_interrupt(PL031_IRQ, true);
// å²ã蟌ã¿ãªã㧠3 ç§éåŸ
æ©ããŸãã
let target = timestamp + 3;
rtc.set_match(target);
info!("Waiting for {}", Utc.timestamp_opt(target.into(), 0).unwrap());
trace!(
"matched={}, interrupt_pending={}",
rtc.matched(),
rtc.interrupt_pending()
);
while !rtc.matched() {
spin_loop();
}
trace!(
"matched={}, interrupt_pending={}",
rtc.matched(),
rtc.interrupt_pending()
);
info!("Finished waiting");
// å²ã蟌ã¿ãŸã§ããã« 3 ç§åŸ
ã¡ãŸãã
let target = timestamp + 6;
info!("Waiting for {}", Utc.timestamp_opt(target.into(), 0).unwrap());
rtc.set_match(target);
rtc.clear_interrupt();
rtc.enable_interrupt(true);
trace!(
"matched={}, interrupt_pending={}",
rtc.matched(),
rtc.interrupt_pending()
);
while !rtc.interrupt_pending() {
wfi();
}
trace!(
"matched={}, interrupt_pending={}",
rtc.matched(),
rtc.interrupt_pending()
);
info!("Finished waiting");
system_off::<Hvc>().unwrap();
}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
error!("{info}");
system_off::<Hvc>().unwrap();
loop {}
}
pl031.rs:
Rustã§ã®äžŠè¡æ§ãžãããã
Rustã¯ãã¥ãŒããã¯ã¹ãšãã£ãã«ãçšããŠOSã¹ã¬ãããæ±ã䞊è¡æ§ãååã«ãµããŒãããŠããŸãã
Rustã®åã·ã¹ãã ã¯å€ãã®äžŠè¡æ§ã«ãŸã€ãããã°ãã³ã³ãã€ã«æã®ãã°ã«ãšã©ãããšããç¹ã§ãéèŠãªåœ¹å²ãæãããŸããããã¯æã« fearless concurrency ïŒãæããªã䞊è¡æ§ãïŒ ãšåŒã°ããŸãããªããªããã³ã³ãã€ã©ã«å®è¡æã§ã®æ£ãããä¿èšŒããããšããŸãããŠããããã§ãã
ã¹ã±ãžã¥ãŒã«
Including 10 minute breaks, this session should take about 3 hours and 20 minutes. It contains:
Segment | Duration |
---|---|
ã¹ã¬ãã | 30 minutes |
ãã£ãã« | 20 minutes |
SendãšSync | 15 minutes |
ç¶æ å ±æ | 30 minutes |
ç·Žç¿åé¡ | 1 hour and 10 minutes |
Speaker Notes
- Rust lets us access OS concurrency toolkit: threads, sync. primitives, etc.
- The type system gives us safety for concurrency without any special features.
- The same tools that help with âconcurrentâ access in a single thread (e.g., a called function that might mutate an argument or save references to it to read later) save us from multi-threading issues.
ã¹ã¬ãã
This segment should take about 30 minutes. It contains:
Slide | Duration |
---|---|
ãã¬ãŒã³ãªã¹ã¬ãã | 15 minutes |
ã¹ã³ãŒãä»ãã¹ã¬ãã | 15 minutes |
ãã¬ãŒã³ãªã¹ã¬ãã
Rustã®ã¹ã¬ããã¯ä»ã®èšèªã®ã¹ã¬ãããšäŒŒãæåãããŸã:
- Spawning new threads does not automatically delay program termination at the end of
main
. - ã¹ã¬ãããããã¯ã¯äºãã«ç¬ç«ã§ãã
- Panics can carry a payload, which can be unpacked with
Any::downcast_ref
.
- Panics can carry a payload, which can be unpacked with
Speaker Notes
This slide should take about 15 minutes.
-
Run the example.
- 5ms timing is loose enough that main and spawned threads stay mostly in lockstep.
- Notice that the program ends before the spawned thread reaches 10!
- This is because
main
ends the program and spawned threads do not make it persist.- Compare to
pthreads
/C++std::thread
/boost::thread
if desired.
- Compare to
-
How do we wait around for the spawned thread to complete?
-
thread::spawn
returns aJoinHandle
. Look at the docs.JoinHandle
has a.join()
method that blocks.
-
Use
let handle = thread::spawn(...)
and laterhandle.join()
to wait for the thread to finish and have the program count all the way to 10. -
Now what if we want to return a value?
-
Look at docs again:
thread::spawn
âs closure returnsT
JoinHandle
.join()
returnsthread::Result<T>
-
Use the
Result
return value fromhandle.join()
to get access to the returned value. -
Ok, what about the other case?
- Trigger a panic in the thread. Note that this doesnât panic
main
. - Access the panic payload. This is a good time to talk about
Any
.
- Trigger a panic in the thread. Note that this doesnât panic
-
Now we can return values from threads! What about taking inputs?
- Capture something by reference in the thread closure.
- An error message indicates we must move it.
- Move it in, see we can compute and then return a derived value.
-
If we want to borrow?
- Main kills child threads when it returns, but another function would just return and leave them running.
- That would be stack use-after-return, which violates memory safety!
- How do we avoid this? See next slide.
ã¹ã³ãŒãä»ãã¹ã¬ãã
éåžžã®ã¹ã¬ããã¯ãããã®ç°å¢ããåçšããããšã¯ã§ããŸãã:
ãããããã®ããã«ã¹ã³ãŒãä»ãã¹ã¬ããã䜿ãããšãã§ããŸã:
Speaker Notes
This slide should take about 13 minutes.
- ãã®çç±ã¯ãé¢æ°
thread::scope
ãå®äºãããšããå šãŠã®ã¹ã¬ããã¯joinãããããšãä¿èšŒãããŠããã®ã§ãã¹ã¬ãããåçšããããŒã¿ãè¿ãããšãã§ããããã§ãã - éåžžã®Rustã®åçšã®ã«ãŒã«ãé©çšãããŸã:ãäžã€ã®ã¹ã¬ããããã¥ãŒã¿ãã«ã§åçšããããšããŸãã¯ä»»æã®æ°ã®ã¹ã¬ããããã€ãã¥ãŒã¿ãã«ã§åçšããããšã
ãã£ãã«
This segment should take about 20 minutes. It contains:
Slide | Duration |
---|---|
éä¿¡åŽ(Senders)ãšåä¿¡åŽ(Receivers) | 10 minutes |
Unboundedãã£ãã« | 2 minutes |
Boundedãã£ãã« | 10 minutes |
éä¿¡åŽ(Senders)ãšåä¿¡åŽ(Receivers)
Rust channels have two parts: a Sender<T>
and a Receiver<T>
. The two parts are connected via the channel, but you only see the end-points.
Speaker Notes
This slide should take about 9 minutes.
Unboundedãã£ãã«
You get an unbounded and asynchronous channel with mpsc::channel()
:
Boundedãã£ãã«
With bounded (synchronous) channels, send()
can block the current thread:
Speaker Notes
This slide should take about 8 minutes.
- 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. - A call to
send()
will abort with an error (that is why it returnsResult
) if the channel is closed. A channel is closed when the receiver is dropped. - A bounded channel with a size of zero is called a ârendezvous channelâ. Every send will block the current thread until another thread calls
recv()
.
Send
ãšSync
This segment should take about 15 minutes. It contains:
Slide | Duration |
---|---|
ããŒã«ãŒãã¬ã€ã | 2 minutes |
Send | 2 minutes |
Sync | 2 minutes |
äŸ | 10 minutes |
ããŒã«ãŒãã¬ã€ã
How does Rust know to forbid shared access across threads? The answer is in two traits:
Send
: ã¹ã¬ããå¢çããŸããã§ã®åT
ã®ã ãŒããå®å šã«è¡ããå ŽåãåT
ã¯Send
ã§ãããSync
: ã¹ã¬ããå¢çããŸããã§&T
ã®ã ãŒããå®å šã«è¡ããå ŽåãåT
ã¯Sync
ã§ããã
Send
and Sync
are unsafe traits. The compiler will automatically derive them for your types as long as they only contain Send
and Sync
types. You can also implement them manually when you know it is valid.
Speaker Notes
This slide should take about 2 minutes.
- ãããã®ãã¬ã€ãã¯ãããåãç¹å®ã®ã¹ã¬ããã»ãŒãã®ç¹æ§ãæã£ãŠããããšã瀺ãããŒã«ãŒãšèããããšãã§ããŸãã
- ãããã¯éåžžã®ãã¬ã€ããšåãããã«ããžã§ããªãã¯å¢çã®äžã§å©çšããããšãã§ããŸãã
Send
å
T
ã®å€ãå®å šã«å¥ã®ã¹ã¬ããã«ã ãŒãã§ããå ŽåãåT
ã¯Send
ã§ããã
æææš©ãå¥ã®ã¹ã¬ããã«ã ãŒããããšããããšã¯ããã¹ãã©ã¯ã¿ ããã®ã¹ã¬ããã§å®è¡ããããšããããšã§ããã€ãŸããããã¹ã¬ããã§ã¢ãã±ãŒããããå€ãå¥ã®ã¹ã¬ããã§è§£æŸããŠãè¯ãããšããã®ãå€æåºæºã«ãªããŸãã
Speaker Notes
This slide should take about 2 minutes.
äŸãæãããšãSQLiteã©ã€ãã©ãªãžã®ã³ãã¯ã·ã§ã³ã¯ãäžã€ã®ã¹ã¬ããããã®ã¿ã¢ã¯ã»ã¹ãããå¿ èŠããããŸãã
Sync
å
T
ã®å€ãè€æ°ã®ã¹ã¬ããããåæã«ã¢ã¯ã»ã¹ããŠãå®å šãªå ŽåãåT
ã¯Sync
ã§ããã
ããæ£ç¢ºã«ã¯ã以äžã®ãããªå®çŸ©ã§ãïŒ
&T
ãSend
ã§ããå Žåããã€ãã®å Žåã«éããT
ã¯Sync
ã§ãã
Speaker Notes
This slide should take about 2 minutes.
ããã¯ã€ãŸãããããåã®å ±æãã¹ã¬ããã»ãŒãã§ããã°ããã®åç §ãã¹ã¬ããéã§åãæž¡ãããšãã¹ã¬ããã»ãŒãã§ããããšããããšãæçã«è¡šãããã®ã§ãã
ãªããªããããåãSyncã§ããå ŽåãããŒã¿ç«¶åãä»ã®åæã®åé¡ãªã©ã®ãªã¹ã¯ãªãã«ãã®åãè€æ°ã®ã¹ã¬ããéã§å ±æã§ãããã®åãå¥ã®ã¹ã¬ããã«ã ãŒãããŠãå®å šã ããã§ãããŸããåãžã®åç §ã¯å¥ã®ã¹ã¬ããã«ã ãŒãããŠãå®å šã§ããããã¯ããããåç §ããããŒã¿ã¯ä»»æã®ã¹ã¬ããããå®å šã«ã¢ã¯ã»ã¹ããããšãã§ããããã§ãã
äŸ
Send + Sync
èŠãããã»ãšãã©ã®åã¯Send + Sync
ã§ãïŒ
i8
ãf32
ãbool
ãchar
ã&str
ãªã©(T1, T2)
ã[T; N]
ã&[T]
ãstruct { x: T }
ãªã©String
ãOption<T>
ãVec<T>
ãBox<T>
ãªã©Arc<T>
: ã¢ãããã¯åç §ã«ãŠã³ãã«ãããæ瀺çã«ã¹ã¬ããã»ãŒããMutex<T>
: å éšããã¯ã«ããæ瀺çã«ã¹ã¬ããã»ãŒããmpsc::Sender<T>
: As of 1.72.0.AtomicBool
,AtomicU8
, âŠ: ç¹å¥ãªã¢ãããã¯åœä»€ãå©çšã
ãžã§ããªã¯ã¹ã¯ãåãã©ã¡ã¿ãSend + Sync
ã§ãããšããéåžžã¯Send + Sync
ã§ãã
Send + !Sync
ãããã®åã¯å¥ã®ã¹ã¬ããã«ã ãŒãããããšãã§ããŸããããã®ãããªã ãŒãã¯ã¹ã¬ããã»ãŒãã§ã¯ãããŸãããéåžžã¯å éšå¯å€æ§ããã®åå ã§ãïŒ
mpsc::Receiver<T>
Cell<T>
RefCell<T>
!Send + Sync
These types are safe to access (via shared references) from multiple threads, but they cannot be moved to another thread:
MutexGuard<T: Sync>
: Uses OS level primitives which must be deallocated on the thread which created them. However, an already-locked mutex can have its guarded variable read by any thread with which the guard is shared.
!Send + !Sync
ãã®ãããªåã¯ã¹ã¬ããã»ãŒãã§ã¯ãªããããå¥ã®ã¹ã¬ããã«ã ãŒãããããšã¯ã§ããŸããïŒ
Rc<T>
: ããããã®Rc<T>
ã¯RcBox<T>
ãžã®åç §ãæã£ãŠããŸããããã¯ãã¢ãããã¯ã§ãªãåç §ã«ãŠã³ããæã£ãŠããŸãã*const T
,*mut T
: Rust ã¯ãçãã€ã³ã¿ãŒã¯åæå®è¡æ§ã«é¢ããç¹å¥ãªèæ ®äºé ãããå¯èœæ§ãããããšãä»®å®ããŠããŸãã
ç¶æ å ±æ
This segment should take about 30 minutes. It contains:
Slide | Duration |
---|---|
Arc | 5 minutes |
Mutex | 15 minutes |
äŸ | 10 minutes |
Arc
Arc<T>
ã¯èªã¿åãå°çšã®å
±æã¢ã¯ã»ã¹ãArc::clone
ã«ããå¯èœã«ããŸãïŒ
Speaker Notes
This slide should take about 5 minutes.
Arc
ã¯âAtomic Reference Countedâã®ç¥ã§ãã¢ãããã¯æäœãå©çšãããšããç¹ã§ãRc
ãã¹ã¬ããå®å šã«ãªã£ãããŒãžã§ã³ã®ãããªãã®ã§ããArc<T>
ã¯Clone
ãå®è£ ããŸãããã®ããšã¯T
ãClone
ãå®è£ ããããªãã«é¢ä¿ãããŸãããT
ãSend
ãšSync
ã®äž¡æ¹ãå®è£ ããŠããå Žåã§ããã€ãã®å Žåã«éããArc<T>
ã¯äž¡è ãå®è£ ããŸããArc::clone()
ã«ã¯ã¢ãããã¯æäœã®ã³ã¹ããããããŸãããã ããã®åŸã¯ãT
ã®å©çšã«é¢ããã³ã¹ãã¯ããããŸããã- åç
§ãµã€ã¯ã«ã«æ°ãã€ããŠãã ããã
Arc
ã«ã¯åç §ãµã€ã¯ã«ãæ€ç¥ããããã®ã¬ããŒãžã³ã¬ã¯ã¿ã¯ãããŸãããstd::sync::Weak
ã圹ç«ã¡ãŸãã
Mutex
Mutex<T>
ensures mutual exclusion and allows mutable access to T
behind a read-only interface (another form of interior mutability):
impl<T: Send> Sync for Mutex<T>
ã®ãã©ã³ã±ããå®è£
ãããããšã«æ³šç®ããŠãã ããã
Speaker Notes
This slide should take about 14 minutes.
- Rustã«ããã
Mutex
ãšã¯ãä¿è·ãããããŒã¿ã§ããããã£ãäžã€ã®èŠçŽ ããæ§æãããã³ã¬ã¯ã·ã§ã³ã®ãããªãã®ã§ãã- ä¿è·ãããããŒã¿ã«ã¢ã¯ã»ã¹ããåã«ããã¥ãŒããã¯ã¹ã確ä¿ãå¿ããããšã¯ãããŸããã
&Mutex<T>
ããããã¯ãååŸããããšã§ã&mut T
ãåŸãããšãã§ããŸãããã®MutexGuard
ã¯&mut T
ãä¿æãããŠããããã¯ãããé·ãåç¶ããªãããšãä¿èšŒããŸããMutex<T>
implements bothSend
andSync
if and only ifT
implementsSend
.- èªã¿æžãã®ããã¯ã®å Žåã«å¯Ÿå¿ãããã®ããããŸãïŒ
RwLock
ã - ãªã
lock()
ã¯Result
ãè¿ãã®ã§ãããïŒ- Mutex
ãä¿æããã¹ã¬ããããããã¯ãèµ·ãããå Žåãä¿è·ãã¹ãããŒã¿ãæŽåæ§ã®æ¬ ããç¶æ ã«ããå¯èœæ§ãäŒããããã
Mutexã¯ããã€ãŸã³ããããïŒ"poisoned"ïŒç¶æ ã«ãªããŸãããã€ãŸã³ãããMutexã«å¯ŸããŠ
lock()ãã³ãŒã«ãããšã[
PoisonError](https://doc.rust-lang.org/std/sync/struct.PoisonError.html)ãšãšãã«å€±æããŸãã
into_inner()` ãçšããããšã§ããã®ãšã©ãŒã«ãããŠããšããããããŒã¿ãå埩ããããšã¯ã§ããŸãã
- Mutex
äŸ
Arc
ãš Mutex
ã®åäœãèŠãŠã¿ãŸãããïŒ
Speaker Notes
This slide should take about 8 minutes.
èãããã察åŠæ³ïŒ
泚ç®ãããšããç®æïŒ
v
ã¯Arc
ãšMutex
ã®äž¡æ¹ã§ã©ãããããŠããŸãããªããªãããããã®é¢å¿ã¯äºãã«ç¬ç«ãªãã®ã§ããããã§ããMutex
ãArc
ã§ã©ããããããšã¯ãã¹ã¬ããéã§ãã¥ãŒã¿ãã«ãªç¶æ ãå ±æããããã«ããèŠããããã¿ãŒã³ã§ãã
v: Arc<_>
ã¯å¥ã®ã¹ã¬ããã«ã ãŒããããåã«ãv2
ãšããŠã¯ããŒã³ãããå¿ èŠããããŸããmove
ãã©ã ãåŒã«è¿œå ãããããšã«æ³šæããŠãã ããã- ãããã¯ã¯
LockGuard
ã®ã¹ã³ãŒããå¯èœãªéãçããããã«å°å ¥ãããŠããŸãã
ç·Žç¿åé¡
This segment should take about 1 hour and 10 minutes. It contains:
Slide | Duration |
---|---|
é£äºããå²åŠè | 20 minutes |
ãã«ãã¹ã¬ããã»ãªã³ã¯ãã§ãã«ãŒ | 20 minutes |
解ç | 30 minutes |
é£äºããå²åŠè
é£äºããå²åŠè ã®åé¡ã¯ã䞊è¡æ§ã«é¢ããå€å žçãªåé¡ã§ãã
5 人ã®å²åŠè ãåãããŒãã«ã§é£äºãããŠããŸããããããã®å²åŠè ãããŒãã«ã®å®äœçœ®ã«åº§ããç¿ã®éã«ã¯ãã©ãŒã¯ã 1 æ¬çœ®ãããŠããŸããæäŸãããæçã¯ã¹ãã²ããã£ã§ã2 æ¬ã®ãã©ãŒã¯ã§é£ã¹ãå¿ èŠããããŸããå²åŠè ã¯æ玢ãšé£äºã亀äºã«ç¹°ãè¿ãããšããã§ããŸãããããã«ãå²åŠè ã¯å·Šå³äž¡æ¹ã®ãã©ãŒã¯ãæã£ãŠããå Žåã«ã®ã¿ãã¹ãã²ããã£ãé£ã¹ãããšãã§ããŸãããããã£ãŠã2 ã€ã®ãã©ãŒã¯ã¯ãäž¡é£ã®å²åŠè ãé£ã¹ãã®ã§ã¯ãªãèããŠããå Žåã«ã®ã¿äœ¿çšã§ããŸããããããã®å²åŠè ã¯ãé£ã¹çµãã£ãåŸãäž¡æ¹ã®ãã©ãŒã¯ã眮ããŸãã
ãã®æŒç¿ã§ã¯ãããŒã«ã«ã® Cargo ã€ã³ã¹ããŒã«ãå¿
èŠã§ãã以äžã®ã³ãŒãã src/main.rs
ãšãããã¡ã€ã«ã«ã³ããŒãã空æ¬ãåããŠãcargo run
ããããããã¯ããªãããšã確èªããŸãã
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
use std::time::Duration;
struct Fork;
struct Philosopher {
name: String,
// left_fork: ...
// right_fork: ...
// thoughts: ...
}
impl Philosopher {
fn think(&self) {
self.thoughts
.send(format!("Eureka! {} has a new idea!", &self.name))
.unwrap();
}
fn eat(&self) {
// Pick up forks...
println!("{} is eating...", &self.name);
thread::sleep(Duration::from_millis(10));
}
}
static PHILOSOPHERS: &[&str] =
&["Socrates", "Hypatia", "Plato", "Aristotle", "Pythagoras"];
fn main() {
// ãã©ãŒã¯ãäœæãã
// å²åŠè
ãäœæãã
// ããããã®å²åŠè
ãæ玢ãšé£äºã 100 åè¡ãããã«ãã
// å²åŠè
ã®æ玢ãåºåãã
}
次㮠Cargo.toml
ã䜿çšã§ããŸãã
[package]
name = "dining-philosophers"
version = "0.1.0"
edition = "2021"
ãã«ãã¹ã¬ããã»ãªã³ã¯ãã§ãã«ãŒ
æ°ãã«èº«ã«ä»ããç¥èã掻ãããŠããã«ãã¹ã¬ãã ãªã³ã¯ ãã§ãã«ãŒãäœæããŸãããããŸãããŠã§ãããŒãžäžã®ãªã³ã¯ãæå¹ãã©ããã確èªããå¿ èŠããããŸããåããã¡ã€ã³ã®ä»ã®ããŒãžãååž°çã«ãã§ãã¯ãããã¹ãŠã®ããŒãžã®æ€èšŒãå®äºãããŸã§ãã®åŠçãç¹°ãè¿ããŸãã
For this, you will need an HTTP client such as reqwest
. You will also need a way to find links, we can use scraper
. Finally, weâll need some way of handling errors, we will use thiserror
.
Create a new Cargo project and reqwest
it as a dependency with:
cargo new link-checker
cd link-checker
cargo add --features blocking,rustls-tls reqwest
cargo add scraper
cargo add thiserror
cargo add
ãerror: no such subcommand
ã§å€±æããå Žåã¯ãCargo.toml
ãã¡ã€ã«ãæåã§ç·šéããŠãã ãããäžèšã®äŸåé¢ä¿ãè¿œå ããŸãã
cargo add
ã®åŒã³åºãã«ãããCargo.toml
ãã¡ã€ã«ã¯æ¬¡ã®ããã«æŽæ°ãããŸãã
[package]
name = "link-checker"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
reqwest = { version = "0.11.12", features = ["blocking", "rustls-tls"] }
scraper = "0.13.0"
thiserror = "1.0.37"
ããã§ãã¹ã¿ãŒãããŒãžãããŠã³ããŒãã§ããããã«ãªããŸãããhttps://www.google.org/
ã®ãããªå°èŠæš¡ãªãµã€ãã§è©ŠããŠã¿ãŸãããã
src/main.rs
ãã¡ã€ã«ã¯æ¬¡ã®ããã«ãªããŸãã
use reqwest::blocking::Client;
use reqwest::Url;
use scraper::{Html, Selector};
use thiserror::Error;
#[derive(Error, Debug)]
enum Error {
#[error("request error: {0}")]
ReqwestError(#[from] reqwest::Error),
#[error("bad http response: {0}")]
BadResponse(String),
}
#[derive(Debug)]
struct CrawlCommand {
url: Url,
extract_links: bool,
}
fn visit_page(client: &Client, command: &CrawlCommand) -> Result<Vec<Url>, Error> {
println!("Checking {:#}", command.url);
let response = client.get(command.url.clone()).send()?;
if !response.status().is_success() {
return Err(Error::BadResponse(response.status().to_string()));
}
let mut link_urls = Vec::new();
if !command.extract_links {
return Ok(link_urls);
}
let base_url = response.url().to_owned();
let body_text = response.text()?;
let document = Html::parse_document(&body_text);
let selector = Selector::parse("a").unwrap();
let href_values = document
.select(&selector)
.filter_map(|element| element.value().attr("href"));
for href in href_values {
match base_url.join(href) {
Ok(link_url) => {
link_urls.push(link_url);
}
Err(err) => {
println!("On {base_url:#}: ignored unparsable {href:?}: {err}");
}
}
}
Ok(link_urls)
}
fn main() {
let client = Client::new();
let start_url = Url::parse("https://www.google.org").unwrap();
let crawl_command = CrawlCommand{ url: start_url, extract_links: true };
match visit_page(&client, &crawl_command) {
Ok(links) => println!("Links: {links:#?}"),
Err(err) => println!("Could not extract links: {err:#}"),
}
}
src/main.rs
å
ã®ã³ãŒããã次ã®ã³ãã³ãã§å®è¡ããŸãã
cargo run
ã¿ã¹ã¯
- ã¹ã¬ããã䜿çšããŠãªã³ã¯ãåæã«ãã§ãã¯ããŸããã€ãŸãããã§ãã¯ãã URL ããã£ã³ãã«ã«éä¿¡ããããã€ãã®ã¹ã¬ããã§åæã« URL ã確èªããŸãã
- ãããæ¡åŒµããŠã
www.google.org
ãã¡ã€ã³ã®ãã¹ãŠã®ããŒãžãããªã³ã¯ãååž°çã«æœåºããŸãããµã€ãããããã¯ãããªãããã«ãããŒãžæ°ã®äžéã 100 çšåºŠã«èšå®ããŸãã
解ç
é£äºããå²åŠè
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
use std::time::Duration;
struct Fork;
struct Philosopher {
name: String,
left_fork: Arc<Mutex<Fork>>,
right_fork: Arc<Mutex<Fork>>,
thoughts: mpsc::SyncSender<String>,
}
impl Philosopher {
fn think(&self) {
self.thoughts
.send(format!("Eureka! {} has a new idea!", &self.name))
.unwrap();
}
fn eat(&self) {
println!("{} is trying to eat", &self.name);
let _left = self.left_fork.lock().unwrap();
let _right = self.right_fork.lock().unwrap();
println!("{} is eating...", &self.name);
thread::sleep(Duration::from_millis(10));
}
}
static PHILOSOPHERS: &[&str] =
&["Socrates", "Hypatia", "Plato", "Aristotle", "Pythagoras"];
fn main() {
let (tx, rx) = mpsc::sync_channel(10);
let forks = (0..PHILOSOPHERS.len())
.map(|_| Arc::new(Mutex::new(Fork)))
.collect::<Vec<_>>();
for i in 0..forks.len() {
let tx = tx.clone();
let mut left_fork = Arc::clone(&forks[i]);
let mut right_fork = Arc::clone(&forks[(i + 1) % forks.len()]);
// ãããããã¯ãé¿ããããã«ãã©ããã§å¯Ÿç§°æ§ã
// 厩ãå¿
èŠããããŸããäžèšã®ã³ãŒãã§ã¯ã
// é åãéæŸããããšãªã2ã€ã®ãã©ãŒã¯ã亀æããŸãã
if i == forks.len() - 1 {
std::mem::swap(&mut left_fork, &mut right_fork);
}
let philosopher = Philosopher {
name: PHILOSOPHERS[i].to_string(),
thoughts: tx,
left_fork,
right_fork,
};
thread::spawn(move || {
for _ in 0..100 {
philosopher.eat();
philosopher.think();
}
});
}
drop(tx);
for thought in rx {
println!("{thought}");
}
}
Link Checker
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
use reqwest::blocking::Client;
use reqwest::Url;
use scraper::{Html, Selector};
use thiserror::Error;
#[derive(Error, Debug)]
enum Error {
#[error("request error: {0}")]
ReqwestError(#[from] reqwest::Error),
#[error("bad http response: {0}")]
BadResponse(String),
}
#[derive(Debug)]
struct CrawlCommand {
url: Url,
extract_links: bool,
}
fn visit_page(client: &Client, command: &CrawlCommand) -> Result<Vec<Url>, Error> {
println!("Checking {:#}", command.url);
let response = client.get(command.url.clone()).send()?;
if !response.status().is_success() {
return Err(Error::BadResponse(response.status().to_string()));
}
let mut link_urls = Vec::new();
if !command.extract_links {
return Ok(link_urls);
}
let base_url = response.url().to_owned();
let body_text = response.text()?;
let document = Html::parse_document(&body_text);
let selector = Selector::parse("a").unwrap();
let href_values = document
.select(&selector)
.filter_map(|element| element.value().attr("href"));
for href in href_values {
match base_url.join(href) {
Ok(link_url) => {
link_urls.push(link_url);
}
Err(err) => {
println!("On {base_url:#}: ignored unparsable {href:?}: {err}");
}
}
}
Ok(link_urls)
}
struct CrawlState {
domain: String,
visited_pages: std::collections::HashSet<String>,
}
impl CrawlState {
fn new(start_url: &Url) -> CrawlState {
let mut visited_pages = std::collections::HashSet::new();
visited_pages.insert(start_url.as_str().to_string());
CrawlState { domain: start_url.domain().unwrap().to_string(), visited_pages }
}
/// æå®ãããããŒãžå
ã®ãªã³ã¯ãæœåºãããã©ããã決å®ããŸãã
fn should_extract_links(&self, url: &Url) -> bool {
let Some(url_domain) = url.domain() else {
return false;
};
url_domain == self.domain
}
/// æå®ãããããŒãžã蚪åæžã¿ãšããŠããŒã¯ãããã§ã«èšªåæžã¿ã§ããã°
/// false ãè¿ããŸãã
fn mark_visited(&mut self, url: &Url) -> bool {
self.visited_pages.insert(url.as_str().to_string())
}
}
type CrawlResult = Result<Vec<Url>, (Url, Error)>;
fn spawn_crawler_threads(
command_receiver: mpsc::Receiver<CrawlCommand>,
result_sender: mpsc::Sender<CrawlResult>,
thread_count: u32,
) {
let command_receiver = Arc::new(Mutex::new(command_receiver));
for _ in 0..thread_count {
let result_sender = result_sender.clone();
let command_receiver = command_receiver.clone();
thread::spawn(move || {
let client = Client::new();
loop {
let command_result = {
let receiver_guard = command_receiver.lock().unwrap();
receiver_guard.recv()
};
let Ok(crawl_command) = command_result else {
// éä¿¡è
ããããããããŸãããä»åŸã³ãã³ãã¯åä¿¡ãããŸããã
break;
};
let crawl_result = match visit_page(&client, &crawl_command) {
Ok(link_urls) => Ok(link_urls),
Err(error) => Err((crawl_command.url, error)),
};
result_sender.send(crawl_result).unwrap();
}
});
}
}
fn control_crawl(
start_url: Url,
command_sender: mpsc::Sender<CrawlCommand>,
result_receiver: mpsc::Receiver<CrawlResult>,
) -> Vec<Url> {
let mut crawl_state = CrawlState::new(&start_url);
let start_command = CrawlCommand { url: start_url, extract_links: true };
command_sender.send(start_command).unwrap();
let mut pending_urls = 1;
let mut bad_urls = Vec::new();
while pending_urls > 0 {
let crawl_result = result_receiver.recv().unwrap();
pending_urls -= 1;
match crawl_result {
Ok(link_urls) => {
for url in link_urls {
if crawl_state.mark_visited(&url) {
let extract_links = crawl_state.should_extract_links(&url);
let crawl_command = CrawlCommand { url, extract_links };
command_sender.send(crawl_command).unwrap();
pending_urls += 1;
}
}
}
Err((url, error)) => {
bad_urls.push(url);
println!("Got crawling error: {:#}", error);
continue;
}
}
}
bad_urls
}
fn check_links(start_url: Url) -> Vec<Url> {
let (result_sender, result_receiver) = mpsc::channel::<CrawlResult>();
let (command_sender, command_receiver) = mpsc::channel::<CrawlCommand>();
spawn_crawler_threads(command_receiver, result_sender, 16);
control_crawl(start_url, command_sender, result_receiver)
}
fn main() {
let start_url = reqwest::Url::parse("https://www.google.org").unwrap();
let bad_urls = check_links(start_url);
println!("Bad URLs: {:#?}", bad_urls);
}
ãããã
ãAsyncãã¯è€æ°ã®ã¿ã¹ã¯ã䞊è¡åŠçããã䞊è¡æ§ã¢ãã«ã§ããããããã®ã¿ã¹ã¯ã¯ãããã¯ããããŸã§å®è¡ããããããŠæ¬¡ã«é²ãããšã®ã§ããä»ã®ã¿ã¹ã¯ã«åãæ¿ããããšã«ããå®çŸãããŸãããã®ã¢ãã«ã¯éãããæ°ã®ã¹ã¬ããäžã§ããå€ãã®ã¿ã¹ã¯ãå®è¡ããããšãå¯èœã«ããŸãããªããªããã¿ã¹ã¯ããšã®ãªãŒããŒãããã¯éåžžã¯ãšãŠãäœããå¹ççã«å®è¡å¯èœãªI/Oãç¹å®ããããã«å¿ èŠãªããªããã£ããOSãæäŸããŠãããããã§ãã
Rustã®éåæçãªæäœã¯ãfutureãã«åºã¥ããŠããŠãããã¯å°æ¥ã«å®äºãããããããªãäœæ¥ãè¡šããŠããŸããFutureã¯ãã¿ã¹ã¯ãå®äºããããšãç¥ãããã·ã°ãã«ãåŸããããŸã§ããŒãªã³ã°ãããŸãã
Futureã¯éåæçãªã©ã³ã¿ã€ã ã«ããããŒãªã³ã°ãããŸããã©ã³ã¿ã€ã ã«ã¯ããã€ãã®éžæè¢ããããŸãã
ä»ã®èšèªãšã®æ¯èŒ
-
Pythonã«ã¯äŒŒããããªã¢ãã«ã
asyncio
ãšããŠæèŒãããŠããŸããããããããã§ã®Future
åã¯ã³ãŒã«ããã¯ã«åºã¥ããã®ã§ãã£ãŠãããŒãªã³ã°ã«ãããã®ã§ã¯ãããŸãããPythonã®éåæããã°ã©ã ã¯ãã«ãŒãããå¿ èŠãšããRustã®ã©ã³ã¿ã€ã ã«äŒŒãŠããŸãã -
JavaScriptã®
Promise
ã¯äŒŒãŠãããã®ã®ãããããŸãããã³ãŒã«ããã¯ã«åºã¥ããŸãã ãã®èšèªã®ã©ã³ã¿ã€ã ã¯ã€ãã³ãã«ãŒãã«ããå®è£ ãããŠãããããå€ãã®Promise解決ã®è©³çŽ°ã¯é ãããŠããŸãã
ã¹ã±ãžã¥ãŒã«
Including 10 minute breaks, this session should take about 3 hours and 20 minutes. It contains:
Segment | Duration |
---|---|
Asyncã®åºç€ | 30 minutes |
ãã£ãã«ãšå¶åŸ¡ãã㌠| 20 minutes |
èœãšãç©Ž | 55 minutes |
ç·Žç¿åé¡ | 1 hour and 10 minutes |
Asyncã®åºç€
This segment should take about 30 minutes. It contains:
Slide | Duration |
---|---|
async/await | 10 minutes |
Future | 4 minutes |
ã©ã³ã¿ã€ã | 10 minutes |
ã¿ã¹ã¯ | 10 minutes |
async
/await
ãããŸãã«ã¯ãRustã®éåæã³ãŒãã¯ã»ãšãã©ãéåžžã®ãé次çãªã³ãŒãã®ããã«èŠããŸã:
Speaker Notes
This slide should take about 6 minutes.
èŠç¹ïŒ
-
ããã¯æ§æã瀺ãããã®åçŽåãããäŸã§ããããšã«æ³šæããŠãã ãããé·ãå®è¡ããããæäœãæ¬ç©ã®äžŠè¡åŠçã¯ããã«ã¯å«ãŸããŸããã
-
The âasyncâ keyword is syntactic sugar. The compiler replaces the return type with a future.
-
ã³ã³ãã€ã©ã«å¯ŸããŠãè¿ãããfutureã®å€ããã®åŸã©ãæ±ãã¹ãããšãããè¿œå ã®æ瀺ãå«ããªãéãã
main
ãasyncã«ããããšã¯ã§ããŸããã -
You need an executor to run async code.
block_on
blocks the current thread until the provided future has run to completion. -
.await
ã¯éåæçã«ä»ã®æäœã®å®äºãåŸ ã¡ãŸããblock_on
ãšã¯ç°ãªãã.await
ã¯çŸåšã®ã¹ã¬ããããããã¯ããŸããã -
.await
can only be used inside anasync
function (or block; these are introduced later).
Future
Future
ã¯ãã¬ã€ãã§ããããŸã å®äºããŠãªããããããªãæäœãè¡šçŸãããªããžã§ã¯ãã«ããå®è£
ãããŸããFutureã¯ããŒãªã³ã°ãããããšããããpoll
ã¯Poll
ãè¿ããŸãã
éåæã®é¢æ°ã¯impl Future
ãè¿ããŸããèªåã§å®çŸ©ããåã«å¯ŸããŠFuture
ãå®è£
ããããšãïŒããŸããªãããšã§ããïŒå¯èœã§ããäŸãã°ãtokio::spawn
ããè¿ãããJoinHandle
ã¯Future
ãå®è£
ããããšã«ãããjoinããããšãå¯èœã«ããŠããŸãã
Futureã«é©çšããã.await
ããŒã¯ãŒãã¯ããã®Futureã®æºåãã§ãããŸã§ãçŸåšã®éåæã®é¢æ°ã®äžæåæ¢ãèµ·ããããããŠãã®åºåãè©äŸ¡ããŸãã
Speaker Notes
This slide should take about 4 minutes.
-
Future
ãšPoll
ã®åã¯ãŸãã«ç€ºãããããã«å®è£ ãããŸã; ããã¥ã¡ã³ãã®å ·äœçãªå®è£ ãèŠãã«ã¯ãªã³ã¯ãã¯ãªãã¯ããŠãã ããã -
Pin
ãšContext
ã«ã€ããŠã¯è©³ããã¯æ±ããŸããããªããªããæ°ããéåæã®ããªããã£ããäœãããããéåæã®ã³ãŒããæžãããšã«æã ã¯éç¹ã眮ãã€ããã ããã§ããç°¡æœã«ã¯ä»¥äžã§èª¬æãããŸãïŒ-
Context
ã¯ãç¹å®ã®ã€ãã³ããçºçããæã«ãFutureãèªåèªèº«ãåã³ããŒãªã³ã°ãããããã«ã¹ã±ãžã¥ãŒã«ããããšãå¯èœã«ããŸãã -
Pin
ã¯futureãžã®ãã€ã³ã¿ãæå¹ã§ããç¶ããããã«ãFutureãã¡ã¢ãªã®äžã§ç§»åãããªãããšã確å®ã«ããŸããããã¯ãåç §ã.await
ã®åŸã«æå¹ã§ããç¶ããããã«å¿ èŠã§ãã
-
ã©ã³ã¿ã€ã
_runtime_ã¯éåæãªæŒç®ïŒreactorïŒã®ãµããŒããæäŸãããŸããfutureãå®è¡ããããšïŒexecutorïŒãæ åœããŠããŸããRustã«ã¯ããã«ãã€ã³ãã®ã©ã³ã¿ã€ã ã¯ãããŸããããããã€ãã®ã©ã³ã¿ã€ã ã®éžæè¢ããããŸã:
- Tokio: performant, with a well-developed ecosystem of functionality like Hyper for HTTP or Tonic for gRPC.
- async-std: aims to be a âstd for asyncâ, and includes a basic runtime in
async::task
. - smol: simple and lightweight
ããã€ãã®ãã巚倧ãªã¢ããªã±ãŒã·ã§ã³ã¯ãç¬èªã®ã©ã³ã¿ã€ã ãåããŠããŸããäŸãã°Fuchsiaã¯ãã®ãããªãã®ããã§ã«åããŠããŸãã
Speaker Notes
This slide and its sub-slides should take about 10 minutes.
-
äžã§æããããã©ã³ã¿ã€ã ã®ãã¡ãTokioã®ã¿ãRustãã¬ã€ã°ã©ãŠã³ãã§ãµããŒããããŠããŸãããã®ãã¬ã€ã°ã©ãŠã³ãã§ã¯ãããªãå ¥åºåæäœãèš±å¯ãããŠããªãããã倧æµã®èå³æ·±ãéåæã®ããããã¯ããã¬ã€ã°ã©ãŠã³ãã§å®è¡ããããšã¯ã§ããŸããã
-
Futureã¯ãããŒãªã³ã°ãè¡ããšã°ãŒãã¥ãŒã¿ã®ååšãªãã«ã¯äœãè¡ããªãïŒå ¥åºåæäœããå§ããªãïŒãšããç¹ã§ãæ æ°ãã§ããäŸãã°ãããã¯ããšã°ãŒãã¥ãŒã¿ããªããšãæåŸãŸã§å®è¡ãããJavaScriptã®Promiseãšã¯ç°ãªããŸãã
Tokio
Tokio provides:
- éåæã®ã³ãŒããå®è¡ããããã®ãã«ãã¹ã¬ããã®ã©ã³ã¿ã€ã ã
- æšæºã©ã€ãã©ãªã®éåæããŒãžã§ã³ã
- 倧ããªã©ã€ãã©ãªã®ãšã³ã·ã¹ãã ã
Speaker Notes
-
tokio::main
ã®ãã¯ãã«ãããmain
ã®éåæåŠçãäœãããšãã§ããŸãã -
spawn
é¢æ°ã¯æ°ãã䞊è¡ã®ãã¿ã¹ã¯ããäœæããŸãã -
泚æïŒ
spawn
ã¯Future
ãåŒæ°ã«åããããcount_to
ã«å¯ŸããŠ.await
ãåŒã¶ããšã¯ãããŸããã
ãããªãæ¢æ±:
-
ã©ãããŠ
count_to
ã¯ïŒéåžžã¯ïŒ10ã«èŸ¿ãçããªãã®ã§ããããïŒããã¯éåæåŠçã®ãã£ã³ã»ã«ã®äŸã§ããtokio::spawn
ã¯å®äºãŸã§åŸ æ©ããããã®ãã³ãã©ãè¿ããŸãã -
ããã»ã¹ãæ°ããäœã代ããã«ã
count_to(10).await
ãè©ŠããŠã¿ãŠãã ããã -
tokio::spawn
ããè¿ãããã¿ã¹ã¯ãåŸ æ©ããŠã¿ãŠãã ããã
ã¿ã¹ã¯
Rust ã«ã¯ã軜éã®ã¹ã¬ãã圢åŒã®äžçš®ã§ããã¿ã¹ã¯ã·ã¹ãã ããããŸãã
ã¿ã¹ã¯ã«ã¯ãåäžã®ãããã¬ãã«ã®futureããããããã¯ãšã°ãŒãã¥ãŒã¿ãå
ã«é²ãããã«ããŒãªã³ã°ãã察象ãšãªããŸãããã®futureã«ã¯äžã€ãŸãã¯è€æ°ã®futureããã¹ããããŠããããšãããããããã¬ãã«ã®futureã®poll
ã¡ãœãããããŒãªã³ã°ããããšã«ãªãã倧ãŸãã«ã¯ã³ãŒã«ã¹ã¿ãã¯ã«å¯Ÿå¿ãããšèšããŸããã¿ã¹ã¯ã«ããã䞊è¡åŠçã¯ãäŸãã°ç«¶åã¿ã€ããŒãå
¥åºåæäœãªã©ãè€æ°ã®åã®futureãããŒãªã³ã°ããããšã«ããå¯èœã«ãªããŸãã
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() -> io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:0").await?;
println!("listening on port {}", listener.local_addr()?.port());
loop {
let (mut socket, addr) = listener.accept().await?;
println!("connection from {addr:?}");
tokio::spawn(async move {
socket.write_all(b"Who are you?\n").await.expect("socket error");
let mut buf = vec![0; 1024];
let name_size = socket.read(&mut buf).await.expect("socket error");
let name = std::str::from_utf8(&buf[..name_size]).unwrap().trim();
let reply = format!("Thanks for dialing in, {name}!\n");
socket.write_all(reply.as_bytes()).await.expect("socket error");
});
}
}
Speaker Notes
This slide should take about 6 minutes.
ãã®äŸãæºåããsrc/main.rs
ã«ã³ããŒããŠãããããå®è¡ããŠã¿ãŸãããã
nc ã telnet ãªã©ã® TCP æ¥ç¶ããŒã«ã䜿çšããŠæ¥ç¶ããŠã¿ãŠãã ããã
-
äŸã®ãµãŒããŒãã©ã®ãããªç¶æ ã®æã«ãããã€ãã®ã¯ã©ã€ã¢ã³ããšæ¥ç¶ãããç¶æ ã«ããã®ãããå¯èŠåããããã«åè¬è ã«æ瀺ããŠãã ãããã©ããªã¿ã¹ã¯ãååšããŠããŸããïŒãããã®futureã¯äœã§ããïŒ
-
This is the first time weâve seen an
async
block. This is similar to a closure, but does not take any arguments. Its return value is a Future, similar to anasync fn
. -
mainã®asyncãããã¯ãé¢æ°ã«ãªãã¡ã¯ã¿ããŠã
?
ã䜿ã£ããšã©ãŒãã³ããªã³ã°ãæ¹åããŠã¿ãŸãããã
ãã£ãã«ãšå¶åŸ¡ãããŒ
This segment should take about 20 minutes. It contains:
Slide | Duration |
---|---|
Asyncãã£ãã« | 10 minutes |
Join | 4 minutes |
Select | 5 minutes |
Asyncãã£ãã«
Several crates have support for asynchronous channels. For instance tokio
:
Speaker Notes
This slide should take about 8 minutes.
-
ãã£ãã«ãµã€ãºã
3
ã«å€ããŠã¿ãŠããããã©ã®ããã«åŠçã«åœ±é¿ããã確èªããŠã¿ãŸãããã -
Overall, the interface is similar to the
sync
channels as seen in the morning class. -
std::mem::drop
ã®åŒã³åºããé€ããŠã¿ãŸããããäœãèµ·ããã§ããããïŒããã¯ãªãã§ããããïŒ -
Flumeã¯ã¬ãŒãã«ã¯
sync
ãšasync
ãsend
ãšrecv
ã®äž¡æ¹ãå®è£ ãããã£ãã«ããããŸãã ããã¯å ¥åºåãšéãCPUã®åŠçã®ã¿ã¹ã¯ã®äž¡æ¹ãå«ããè€éãªã¢ããªã±ãŒã·ã§ã³ã§äŸ¿å©ã§ãã -
async
ãã£ãã«ãæ±ãããšã奜ãŸããããã®ã¯ããã£ãã«ãšç¹ããããã«ããè€éãªã³ã³ãããŒã«ãããŒãäœãããã«ããã£ãã«ãä»ã®future
ãšç¹ããããããšã§ãã
Join
Joinãšããæäœã§ã¯ãfutureã®éåã®æºåãæŽããŸã§åŸ
æ©ãããã®åŸã«çµæããŸãšããŠè¿ããŸããããã¯JavaScriptã«ããã Promise.all
ãPythonã«ãããasyncio.gather
ã«äŒŒãŠããŸãã
Speaker Notes
This slide should take about 4 minutes.
ãã®äŸãæºåããsrc/main.rs
ã«ã³ããŒããŠãããããå®è¡ããŠã¿ãŸãããã
-
è€æ°ã®äºãã«çŽ ãªåã®futureã«å¯ŸããŠã¯ã
std::future::join!
ãå©çšã§ããŸããããããããã€ã®futureãã³ã³ãã€ã«æã«ååšããŠããã®ããææ¡ããŠããå¿ èŠããããŸããããã¯çŸåšfutures
ã¯ã¬ãŒãã«ãããŸãããè¿ããã¡ã«std::future
ã«çµ±åãããäºå®ã§ãã -
The risk of
join
is that one of the futures may never resolve, this would cause your program to stall. -
ãŸãã
join_all
ãšjoin!
ãçµã¿åãããããšãã§ããŸããããã¯ãäŸãã°ããŒã¿ããŒã¹ã®ã¯ãšãªãšäžç·ã«httpãµãŒãã¹ãžã®å šãŠã®ãªã¯ãšã¹ããjoinããå Žåã§ããfutureã«futures::join!
ãçšããŠãtokio::time::sleep
ãè¿œå ããŠã¿ãŠãã ãããããã¯ïŒæ¬¡ã®ãã£ãã¿ãŒã§èª¬æãããselect!
ãå¿ èŠãšããïŒã¿ã€ã ã¢ãŠãã§ã¯ãããŸããããjoin!
ã®è¯ãå®æŒãšãªã£ãŠããŸãã
Select
Selectãšããæäœã§ã¯ãfutureã®éåã®ãã¡ãããããïŒã€ã®æºåãæŽããŸã§åŸ
æ©ãããã®futureãæäŸããçµæã«å¯ŸããŠå¿çããŸããããã¯JavaScriptã«ãããPromise.race
ã«äŒŒãŠããŸãããŸããPythonã«ããã asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED)
ãšæ¯ã¹ãããšãã§ããŸãã
Similar to a match statement, the body of select!
has a number of arms, each of the form pattern = future => statement
. When a future
is ready, its return value is destructured by the pattern
. The statement
is then run with the resulting variables. The statement
result becomes the result of the select!
macro.
Speaker Notes
This slide should take about 5 minutes.
-
The
listener
async block here is a common form: wait for some async event, or for a timeout. Change thesleep
to sleep longer to see it fail. Why does thesend
also fail in this situation? -
select!
is also often used in a loop in âactorâ architectures, where a task reacts to events in a loop. That has some pitfalls, which will be discussed in the next segment.
èœãšãç©Ž
Async / await provides convenient and efficient abstraction for concurrent asynchronous programming. However, the async/await model in Rust also comes with its share of pitfalls and footguns. We illustrate some of them in this chapter.
This segment should take about 55 minutes. It contains:
Slide | Duration |
---|---|
ãšã°ãŒãã¥ãŒã¿ã®ããããã³ã° | 10 minutes |
Pin | 20 minutes |
Asyncãã¬ã€ã | 5 minutes |
ãã£ã³ã»ã« | 20 minutes |
ãšã°ãŒãã¥ãŒã¿ã®ãããã¯
ã»ãšãã©ã®éåæã©ã³ã¿ã€ã ã¯ãIO ã¿ã¹ã¯ã®åæå®è¡ã®ã¿ãèš±å¯ããŸããã€ãŸããCPU ãããã¯ã¿ã¹ã¯ã¯ãšã°ãŒãã¥ãŒã¿ããããã¯ããä»ã®ã¿ã¹ã¯ã®å®è¡ã劚ããŸããç°¡åãªåé¿çã¯ãå¯èœã§ããã°éåæã®åçã®ã¡ãœããã䜿çšããããšã§ãã
Speaker Notes
This slide should take about 10 minutes.
-
ã³ãŒããç¶ããŠãã¹ãªãŒããåæã§ã¯ãªãé£ç¶ããŠçºçããããšã確èªããŸãã
-
"current_thread"
ãã¬ãŒããŒã¯ããã¹ãŠã®ã¿ã¹ã¯ã 1 ã€ã®ã¹ã¬ããã«é 眮ããŸããããã«ããã圱é¿ã¯ããæ確ã«ãªããŸããããã°ã¯ãŸã ãã«ãã¹ã¬ãã ãã¬ãŒããŒã«ååšããŸãã -
std::thread::sleep
ãtokio::time::sleep
ã«åãæ¿ããŠããã®çµæãåŸ ã¡ãŸãã -
ãã 1 ã€ã®ä¿®æ£çã¯ã
tokio::task::spawn_blocking
ã䜿çšããããšã§ããããã¯ãå®éã®ã¹ã¬ãããçæãããšã°ãŒãã¥ãŒã¿ããããã¯ããã«ãã®ãã³ãã«ã Future ã«å€æããŸãã -
ã¿ã¹ã¯ã¯ OS ã¹ã¬ãããšã¯ã¿ãªãã¹ãã§ã¯ãããŸãããããã㯠1 察 1 ã«å¯Ÿå¿ããŠããããã»ãšãã©ã®ãšã°ãŒãã¥ãŒã¿ã¯ãåäžã® OS ã¹ã¬ããã§å€ãã®ã¿ã¹ã¯ãå®è¡ããããšãèš±å¯ããŸããããã¯ãFFI ãä»ããŠä»ã®ã©ã€ãã©ãªãšããåãããå Žåã«ç¹ã«åé¡ãšãªããŸããFFI ã§ã¯ããã®ã©ã€ãã©ãªã¯ã¹ã¬ãã ããŒã«ã« ã¹ãã¬ãŒãžã«äŸåããŠããããç¹å®ã® OS ã¹ã¬ããïŒCUDA ãªã©ïŒã«ãããã³ã°ãããŠããå¯èœæ§ãããããã§ãããã®ãããªå Žåã¯
tokio::task::spawn_blocking
ã䜿çšããããšãããããããŸãã -
åæãã¥ãŒããã¯ã¹ã¯æ éã«äœ¿çšããŠãã ããã
.await
ã§ãã¥ãŒããã¯ã¹ãä¿æãããšãå¥ã®ã¿ã¹ã¯ããããã¯ããããã®ã¿ã¹ã¯ãåãã¹ã¬ããã§å®è¡ãããå¯èœæ§ããããŸãã
Pin
éåæãããã¯ãšé¢æ°ã¯ãFuture
ãã¬ã€ããå®è£
ããåãè¿ããŸããè¿ãããåã¯ãããŒã«ã«å€æ°ã Future ã®å
éšã«æ ŒçŽãããããŒã¿ã«å€æããã³ã³ãã€ã©å€æã®çµæã§ãã
ãããã®å€æ°ã®äžéšã¯ãä»ã®ããŒã«ã«å€æ°ãžã®ãã€ã³ã¿ãä¿æã§ããŸãããããã®ãã€ã³ã¿ãç¡å¹ã«ãªããããFutureãå¥ã®ã¡ã¢ãªäœçœ®ã«ç§»åããªãã§ãã ããã
ã¡ã¢ãªå
ã® Future åã移åããã®ãé²ãã«ã¯ãåºå®ããããã€ã³ã¿ã®ã¿ãä»ããŠããŒãªã³ã°ããããã«ããŸããPin
ã¯åç
§ã®ã©ãããŒã§ãåç
§å
ã®ã€ã³ã¹ã¿ã³ã¹ãå¥ã®ã¡ã¢ãªäœçœ®ã«ç§»åãããªãã¬ãŒã·ã§ã³ããã¹ãŠçŠæ¢ããŸãã
Speaker Notes
This slide should take about 20 minutes.
-
ããã¯ã¢ã¯ã¿ãŒã®ãã¿ãŒã³ã®äžäŸã§ããã¢ã¯ã¿ãŒã¯éåžžãã«ãŒãå ã§
select!
ãåŒã³åºããŸãã -
ããã¯ãããŸã§ã®ã¬ãã¹ã³ã®äžéšããŸãšãããã®ã§ãã®ã§ãæéããããŠåŸ©ç¿ããŠãã ããã
-
_ = sleep(Duration::from_millis(100)) => { println!(..) }
ãselect!
ã«è¿œå ããã ãã§ã¯ãå®è¡ãããŸããããªãã§ããããïŒ -
代ããã«ã
loop
ã®å€åŽã§ããã® Future ãå«ãtimeout_fut
ãè¿œå ããŸãã -
ããã§ãããŸããããŸãããã³ã³ãã€ã«ãšã©ãŒã«ããããã«ã
select!
å ã®timeout_fut
ã«&mut
ãè¿œå ããŠç§»åãåé¿ããŠãããBox::pin
ã䜿çšããŸãã -
This compiles, but once the timeout expires it is
Poll::Ready
on every iteration (a fused future would help with this). Update to resettimeout_fut
every time it expires:
-
-
Box ã§ããŒãã«å²ãåœãŠãŸããå Žåã«ãã£ãŠã¯
std::pin::pin!
ïŒæè¿å®å®åãããã°ããã§ãå€ãã³ãŒãã§ã¯å€ãã®å Žåã«tokio::pin!
ã䜿çšããŸãïŒã䜿çšã§ããŸãããåå²ãåœãŠããã Future ã«äœ¿çšããããšã¯å°é£ã§ãã -
å¥ã®æ¹æ³ãšããŠã¯ã
pin
ããŸã£ãã䜿çšããã«ã100 ããªç§ããšã«oneshot
ãã£ãã«ã«éä¿¡ããå¥ã®ã¿ã¹ã¯ãçæãããšããæ¹æ³ããããŸãã -
ããèªäœãžã®ãã€ã³ã¿ãå«ãããŒã¿ã¯ãèªå·±åç §ãšåŒã°ããŸããéåžžãRust åçšãã§ãã«ãŒã¯ãåç §ãåç §å ã®ããŒã¿ããé·ãåç¶ã§ããªããããèªå·±åç §ããŒã¿ã®ç§»åãé²ããŸãããã ããéåæãããã¯ãšé¢æ°ã®ã³ãŒãå€æã¯ãåçšãã§ãã«ãŒã«ãã£ãŠæ€èšŒãããŸããã
-
Pin
ã¯åç §ã®ã©ãããŒã§ããåºå®ããããã€ã³ã¿ã䜿çšããŠããªããžã§ã¯ãããã®å Žæãã移åããããšã¯ã§ããŸããããã ããåºå®ãããŠããªããã€ã³ã¿ãä»ããŠç§»åããããšã¯å¯èœã§ãã -
Future
ãã¬ã€ãã®poll
ã¡ãœããã¯ã&mut Self
ã§ã¯ãªãPin<&mut Self>
ã䜿çšããŠã€ã³ã¹ã¿ã³ã¹ãåç §ããŸããåºå®ããããã€ã³ã¿ã§ã®ã¿åŒã³åºãããšãã§ããã®ã¯ãã®ããã§ãã
Asyncãã¬ã€ã
Async methods in traits are were stabilized in the 1.75 release. This required support for using return-position impl Trait
in traits, as the desugaring for async fn
includes -> impl Future<Output = ...>
.
However, even with the native support, there are some pitfalls around async fn
:
-
Return-position
impl Trait
captures all in-scope lifetimes (so some patterns of borrowing cannot be expressed). -
Async traits cannot be used with trait objects (
dyn Trait
support).
The async_trait crate provides a workaround for dyn
support through a macro, with some caveats:
Speaker Notes
This slide should take about 5 minutes.
-
async_trait
ã¯ç°¡åã«äœ¿çšã§ããŸãããããŒãå²ãåœãŠã䜿çšããŠãããå®çŸããŠããŸãããã®ããŒãå²ãåœãŠã«ã¯ãããã©ãŒãã³ã¹ ãªãŒããŒãããã䌎ããŸãã -
The challenges in language support for
async trait
are too deep to describe in-depth in this class. See this blog post by Niko Matsakis if you are interested in digging deeper. See also these keywords:- RPIT: short for return-position
impl Trait
. - RPITIT: short for return-position
impl Trait
in trait (RPIT in trait).
- RPIT: short for return-position
-
Try creating a new sleeper struct that will sleep for a random amount of time and adding it to the
Vec
.
ãã£ã³ã»ã«
Future ããããããããšããã® Future ãå床ããŒãªã³ã°ããããšã¯ã§ããŸãããããã¯ãã£ã³ã»ã«ãšåŒã°ããã©ã® await
ãã€ã³ãã§ãçºçããå¯èœæ§ããããŸãããã®ãããFuture ããã£ã³ã»ã«ãããå Žåã§ããã·ã¹ãã ãæ£åžžã«åäœããããã«ããŠããå¿
èŠããããŸããããšãã°ããããããã¯ãããŒã¿ã®æ¶å€±ããã£ãŠã¯ãªããŸããã
Speaker Notes
This slide should take about 18 minutes.
-
ã³ã³ãã€ã©ã§ã¯ãã£ã³ã»ã«å®å šæ§ã確ä¿ã§ããŸãããAPI ããã¥ã¡ã³ããèªã¿ã
async fn
ãä¿æããç¶æ ãèæ ®ããå¿ èŠããããŸãã -
panic
ã?
ãšã¯ç°ãªãããã£ã³ã»ã«ã¯ïŒãšã©ãŒåŠçã§ã¯ãªãïŒéåžžã®å¶åŸ¡ãããŒã®äžéšã§ãã -
ãã®äŸã§ã¯ãæååã®äžéšã倱ãããŠããŸãã
-
tick()
åå²ãå ã«çµäºãããã³ã«ãnext()
ãšãã®buf
ããããããããŸãã -
buf
ãæ§é äœã®äžéšã«ããããšã§ãLinesReader
ã«ãã£ã³ã»ã«å®å šæ§ãæãããããšãã§ããŸãã
-
-
Interval::tick
ã¯ããã£ãã¯ããé ä¿¡æžã¿ããã©ããã远跡ããŠãããããå®å šã«ãã£ã³ã»ã«ã§ããŸãã -
AsyncReadExt::read
ã¯ãããŒã¿ãè¿ãããããŒã¿ãèªã¿åããªããã®ããããã§ãããããå®å šã«ãã£ã³ã»ã«ã§ããŸãã -
AsyncBufReadExt::read_line
ã¯ãã®äŸãšé¡äŒŒããŠãããå®å šã«ãã£ã³ã»ã«ã§ããŸããã詳现ãšä»£æ¿æ¹æ³ã«ã€ããŠã¯ãããã¥ã¡ã³ããã芧ãã ããã
ç·Žç¿åé¡
This segment should take about 1 hour and 10 minutes. It contains:
Slide | Duration |
---|---|
é£äºããå²åŠè | 20 minutes |
ãããŒããã£ã¹ãã»ãã£ããã¢ã㪠| 30 minutes |
解ç | 20 minutes |
Dining Philosophers â Async
See dining philosophers for a description of the problem.
åãšåæ§ã«ããã®æŒç¿ã§ãããŒã«ã«ã® Cargo ã€ã³ã¹ããŒã« ãå¿
èŠã§ãã以äžã®ã³ãŒãã src/main.rs
ãšãããã¡ã€ã«ã«ã³ããŒãã空æ¬ãåããŠãcargo run
ããããããã¯ããªãããšã確èªããŸãã
use std::sync::Arc;
use tokio::sync::{mpsc, Mutex};
use tokio::time;
struct Fork;
struct Philosopher {
name: String,
// left_fork: ...
// right_fork: ...
// thoughts: ...
}
impl Philosopher {
async fn think(&self) {
self.thoughts
.send(format!("Eureka! {} has a new idea!", &self.name))
.await
.unwrap();
}
async fn eat(&self) {
// Keep trying until we have both forks
println!("{} is eating...", &self.name);
time::sleep(time::Duration::from_millis(5)).await;
}
}
static PHILOSOPHERS: &[&str] =
&["Socrates", "Hypatia", "Plato", "Aristotle", "Pythagoras"];
#[tokio::main]
async fn main() {
// ãã©ãŒã¯ãäœæãã
// å²åŠè
ãäœæãã
// å²åŠè
ãæ玢ãšé£äºãè¡ãããã«ãã
// å²åŠè
ã®æ玢ãåºåãã
}
ä»åã¯éåæ Rust ã䜿çšãããããtokio
äŸåé¢ä¿ãå¿
èŠã«ãªããŸãã次㮠Cargo.toml
ã䜿çšã§ããŸãã
[package]
name = "dining-philosophers-async-dine"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1.26.0", features = ["sync", "time", "macros", "rt-multi-thread"] }
ãŸããä»åºŠã¯ tokio
ã¯ã¬ãŒãã® Mutex
ã¢ãžã¥ãŒã«ãš mpsc
ã¢ãžã¥ãŒã«ã䜿çšããå¿
èŠãããããšã«ã泚æããŠãã ããã
Speaker Notes
This slide should take about 20 minutes.
- å®è£ ãã·ã³ã°ã«ã¹ã¬ããã«ã§ããŸããïŒ
ãããŒããã£ã¹ãã»ãã£ããã¢ããª
ãã®æŒç¿ã§ã¯ãæ°ãã«èº«ã«ä»ããç¥èã掻ãããŠãããŒããã£ã¹ã ãã£ãã ã¢ããªãå®è£ ããŸããã¯ã©ã€ã¢ã³ããæ¥ç¶ããŠã¡ãã»ãŒãžãå ¬éãããã£ãã ãµãŒããŒããããŸããã¯ã©ã€ã¢ã³ãã¯æšæºå ¥åãããŠãŒã¶ãŒ ã¡ãã»ãŒãžãèªã¿åãããµãŒããŒã«éä¿¡ããŸãããã£ãã ãµãŒããŒã¯åä¿¡ããåã¡ãã»ãŒãžããã¹ãŠã®ã¯ã©ã€ã¢ã³ãã«ãããŒããã£ã¹ãããŸãã
ãã®ããã«ããµãŒããŒäžã® ãããŒããã£ã¹ã ãã£ã³ãã« ã䜿çšããã¯ã©ã€ã¢ã³ããšãµãŒããŒéã®éä¿¡ã«ã¯ tokio_websockets
ã䜿çšããŸãã
æ°ãã Cargo ãããžã§ã¯ããäœæãã次ã®äŸåé¢ä¿ãè¿œå ããŸãã
Cargo.toml:
[package]
name = "chat-async"
version = "0.1.0"
edition = "2021"
[dependencies]
futures-util = { version = "0.3.31", features = ["sink"] }
http = "1.1.0"
tokio = { version = "1.41.0", features = ["full"] }
tokio-websockets = { version = "0.10.1", features = ["client", "fastrand", "server", "sha1_smol"] }
å¿ èŠãª API
tokio
ãš tokio_websockets
ã®ä»¥äžã®é¢æ°ãå¿
èŠã«ãªããŸããå°ãæéããã㊠API ã«å¯Ÿããç解ãæ·±ããŠãã ããã
WebSocketStream
ã«ãã£ãŠå®è£ ããã StreamExt::next(): Websocket Stream ããã®ã¡ãã»ãŒãžãéåæã§èªã¿åããŸããWebSocketStream
ã«ãã£ãŠå®è£ ããã SinkExt::send(): Websocket Stream äžã§ã¡ãã»ãŒãžãéåæã§éä¿¡ããŸãã- Lines::next_line(): æšæºå ¥åããã®ãŠãŒã¶ãŒ ã¡ãã»ãŒãžãéåæã§èªã¿åããŸãã
- Sender::subscribe(): ãããŒããã£ã¹ã ãã£ã³ãã«ããµãã¹ã¯ã©ã€ãããŸãã
2 ã€ã®ãã€ããª
éåžžãCargo ãããžã§ã¯ãã«å«ããããšãã§ããã®ã¯ 1 ã€ã®ãã€ããªãš 1 ã€ã® src/main.rs
ãã¡ã€ã«ã®ã¿ã§ãããã®ãããžã§ã¯ãã«ã¯ 2 ã€ã®ãã€ããªãå¿
èŠã§ãã1 ã€ã¯ã¯ã©ã€ã¢ã³ãçšããã 1 ã€ã¯ãµãŒããŒçšã§ãã2 ã€ã®ç¬ç«ãã Cargo ãããžã§ã¯ããäœæããããšãã§ããŸãããããã§ã¯ 1 ã€ã® Cargo ãããžã§ã¯ãã« 2 ã€ã®ãã€ããªãå
¥ããŸãããã®ããã«ã¯ãã¯ã©ã€ã¢ã³ããšãµãŒããŒã®ã³ãŒãã src/bin
ã«é
眮ããå¿
èŠããããŸãïŒããã¥ã¡ã³ã ãã芧ãã ããïŒã
次ã®ãµãŒããŒãšã¯ã©ã€ã¢ã³ãã®ã³ãŒãããããããsrc/bin/server.rs
ãš src/bin/client.rs
ã«ã³ããŒããŸããããã§ã®ã¿ã¹ã¯ã¯ã以äžã§èª¬æããããã«ããããã®ãã¡ã€ã«ãå®æãããããšã§ãã
src/bin/server.rs:
use futures_util::sink::SinkExt;
use futures_util::stream::StreamExt;
use std::error::Error;
use std::net::SocketAddr;
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::broadcast::{channel, Sender};
use tokio_websockets::{Message, ServerBuilder, WebSocketStream};
async fn handle_connection(
addr: SocketAddr,
mut ws_stream: WebSocketStream<TcpStream>,
bcast_tx: Sender<String>,
) -> Result<(), Box<dyn Error + Send + Sync>> {
// TODO: ãã³ãã«ã€ããŠã¯ã以äžã®ã¿ã¹ã¯ã®èª¬æãã芧ãã ããã
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
let (bcast_tx, _) = channel(16);
let listener = TcpListener::bind("127.0.0.1:2000").await?;
println!("listening on port 2000");
loop {
let (socket, addr) = listener.accept().await?;
println!("New connection from {addr:?}");
let bcast_tx = bcast_tx.clone();
tokio::spawn(async move {
// æªå 工㮠TCP ã¹ããªãŒã ã WebSocket ã«ã©ããããŸãã
let ws_stream = ServerBuilder::new().accept(socket).await?;
handle_connection(addr, ws_stream, bcast_tx).await
});
}
}
src/bin/client.rs:
use futures_util::stream::StreamExt;
use futures_util::SinkExt;
use http::Uri;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio_websockets::{ClientBuilder, Message};
#[tokio::main]
async fn main() -> Result<(), tokio_websockets::Error> {
let (mut ws_stream, _) =
ClientBuilder::from_uri(Uri::from_static("ws://127.0.0.1:2000"))
.connect()
.await?;
let stdin = tokio::io::stdin();
let mut stdin = BufReader::new(stdin).lines();
// TODO: ãã³ãã«ã€ããŠã¯ã以äžã®ã¿ã¹ã¯ã®èª¬æãã芧ãã ããã
}
ãã€ããªã®å®è¡
次ã®ã³ãã³ãã§ãµãŒããŒãå®è¡ããŸãã
cargo run --bin server
次ã®ã³ãã³ãã§ã¯ã©ã€ã¢ã³ããå®è¡ããŸãã
cargo run --bin client
ã¿ã¹ã¯
src/bin/server.rs
ã«handle_connection
é¢æ°ãå®è£ ããŸãã- ãã³ã: 2 ã€ã®ã¿ã¹ã¯ãé£ç¶ã«ãŒãã§åæã«å®è¡ããã«ã¯ã
tokio::select!
ã䜿çšããŸãã1 ã€ã®ã¿ã¹ã¯ã¯ãã¯ã©ã€ã¢ã³ãããã¡ãã»ãŒãžãåä¿¡ããŠãããŒããã£ã¹ãããŸãããã 1 ã€ã®ã¿ã¹ã¯ã¯ããµãŒããŒã§åä¿¡ããã¡ãã»ãŒãžãã¯ã©ã€ã¢ã³ãã«éä¿¡ããŸãã
- ãã³ã: 2 ã€ã®ã¿ã¹ã¯ãé£ç¶ã«ãŒãã§åæã«å®è¡ããã«ã¯ã
src/bin/client.rs
ã®ã¡ã€ã³é¢æ°ãå®æãããŸãã- ãã³ã: åã®äŸãšåæ§ã«ã
tokio::select!
ãé£ç¶ã«ãŒãã§äœ¿çšããïŒ1ïŒæšæºå ¥åãããŠãŒã¶ãŒ ã¡ãã»ãŒãžãèªã¿åã£ãŠãµãŒããŒã«éä¿¡ããã¿ã¹ã¯ãšãïŒ2ïŒãµãŒããŒããã¡ãã»ãŒãžãåä¿¡ããŠãŠãŒã¶ãŒã«è¡šç€ºããã¿ã¹ã¯ãåæã«å®è¡ããŸãã
- ãã³ã: åã®äŸãšåæ§ã«ã
- çç¥å¯: å®äºããããã¡ãã»ãŒãžã®éä¿¡è 以å€ã®ãã¹ãŠã®ã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžããããŒããã£ã¹ãããããã«ã³ãŒããå€æŽããŸãã
解ç
Dining Philosophers â Async
use std::sync::Arc;
use tokio::sync::{mpsc, Mutex};
use tokio::time;
struct Fork;
struct Philosopher {
name: String,
left_fork: Arc<Mutex<Fork>>,
right_fork: Arc<Mutex<Fork>>,
thoughts: mpsc::Sender<String>,
}
impl Philosopher {
async fn think(&self) {
self.thoughts
.send(format!("Eureka! {} has a new idea!", &self.name))
.await
.unwrap();
}
async fn eat(&self) {
// Keep trying until we have both forks
// Pick up forks...
let _left_fork = self.left_fork.lock().await;
let _right_fork = self.right_fork.lock().await;
println!("{} is eating...", &self.name);
time::sleep(time::Duration::from_millis(5)).await;
// ããã§ããã¯ããããããããŸãã
}
}
static PHILOSOPHERS: &[&str] =
&["Socrates", "Hypatia", "Plato", "Aristotle", "Pythagoras"];
#[tokio::main]
async fn main() {
// ãã©ãŒã¯ãäœæãã
let mut forks = vec![];
(0..PHILOSOPHERS.len()).for_each(|_| forks.push(Arc::new(Mutex::new(Fork))));
// å²åŠè
ãäœæãã
let (philosophers, mut rx) = {
let mut philosophers = vec![];
let (tx, rx) = mpsc::channel(10);
for (i, name) in PHILOSOPHERS.iter().enumerate() {
let mut left_fork = Arc::clone(&forks[i]);
let mut right_fork = Arc::clone(&forks[(i + 1) % PHILOSOPHERS.len()]);
if i == PHILOSOPHERS.len() - 1 {
std::mem::swap(&mut left_fork, &mut right_fork);
}
philosophers.push(Philosopher {
name: name.to_string(),
left_fork,
right_fork,
thoughts: tx.clone(),
});
}
(philosophers, rx)
// tx ã¯ããã§ãããããããã®ã§ãåŸã§æ瀺çã«åé€ããå¿
èŠã¯ãããŸããã
};
// å²åŠè
ãæ玢ãšé£äºãè¡ãããã«ãã
for phil in philosophers {
tokio::spawn(async move {
for _ in 0..100 {
phil.think().await;
phil.eat().await;
}
});
}
// å²åŠè
ã®æ玢ãåºåãã
while let Some(thought) = rx.recv().await {
println!("Here is a thought: {thought}");
}
}
ãããŒããã£ã¹ãã»ãã£ããã¢ããª
src/bin/server.rs:
use futures_util::sink::SinkExt;
use futures_util::stream::StreamExt;
use std::error::Error;
use std::net::SocketAddr;
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::broadcast::{channel, Sender};
use tokio_websockets::{Message, ServerBuilder, WebSocketStream};
async fn handle_connection(
addr: SocketAddr,
mut ws_stream: WebSocketStream<TcpStream>,
bcast_tx: Sender<String>,
) -> Result<(), Box<dyn Error + Send + Sync>> {
ws_stream
.send(Message::text("Welcome to chat! Type a message".to_string()))
.await?;
let mut bcast_rx = bcast_tx.subscribe();
// (1) `ws_stream` ããã¡ãã»ãŒãžãåä¿¡ããŠãããŒããã£ã¹ãããã¿ã¹ã¯ãšã
// ïŒ2ïŒ`bcast_rx` ã§ã¡ãã»ãŒãžãåä¿¡ããŠã¯ã©ã€ã¢ã³ãã«éä¿¡ãããã¿ã¹ã¯ã
// åæã«å®è¡ããããã®é£ç¶ã«ãŒãã
loop {
tokio::select! {
incoming = ws_stream.next() => {
match incoming {
Some(Ok(msg)) => {
if let Some(text) = msg.as_text() {
println!("From client {addr:?} {text:?}");
bcast_tx.send(text.into())?;
}
}
Some(Err(err)) => return Err(err.into()),
None => return Ok(()),
}
}
msg = bcast_rx.recv() => {
ws_stream.send(Message::text(msg?)).await?;
}
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
let (bcast_tx, _) = channel(16);
let listener = TcpListener::bind("127.0.0.1:2000").await?;
println!("listening on port 2000");
loop {
let (socket, addr) = listener.accept().await?;
println!("New connection from {addr:?}");
let bcast_tx = bcast_tx.clone();
tokio::spawn(async move {
// æªå 工㮠TCP ã¹ããªãŒã ã WebSocket ã«ã©ããããŸãã
let ws_stream = ServerBuilder::new().accept(socket).await?;
handle_connection(addr, ws_stream, bcast_tx).await
});
}
}
src/bin/client.rs:
use futures_util::stream::StreamExt;
use futures_util::SinkExt;
use http::Uri;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio_websockets::{ClientBuilder, Message};
#[tokio::main]
async fn main() -> Result<(), tokio_websockets::Error> {
let (mut ws_stream, _) =
ClientBuilder::from_uri(Uri::from_static("ws://127.0.0.1:2000"))
.connect()
.await?;
let stdin = tokio::io::stdin();
let mut stdin = BufReader::new(stdin).lines();
// ã¡ãã»ãŒãžã®åæéåä¿¡ã®ããã®ç¶ç¶çãªã«ãŒãã
loop {
tokio::select! {
incoming = ws_stream.next() => {
match incoming {
Some(Ok(msg)) => {
if let Some(text) = msg.as_text() {
println!("From server: {}", text);
}
},
Some(Err(err)) => return Err(err.into()),
None => return Ok(()),
}
}
res = stdin.next_line() => {
match res {
Ok(None) => return Ok(()),
Ok(Some(line)) => ws_stream.send(Message::text(line.to_string())).await?,
Err(err) => return Err(err.into()),
}
}
}
}
}
ããããšãããããŸããïŒ
Comprehensive Rust ðŠ! ãåè¬ããã ãããããšãããããŸããã
ãããŸã§å€ãã®ããšãåŠãã§ããŸãããããã®ã³ãŒã¹ã¯å®ç§ã§ã¯ãªããããééããèŠã€ããå Žåãæ¹åã®ã¢ã€ãã¢ãããå Žå㯠GitHub ã§ãç¥ãããã ãããçããããã®ãã£ãŒãããã¯ããåŸ ã¡ããŠããŸãã
çšèªé
以äžã¯ãRust ã®å€ãã®çšèªãç°¡åã«å®çŸ©ããããšãç®çãšããçšèªéã§ãã翻蚳æã«çšèªãè±èªã®åæã«é¢é£ä»ããã®ã«ã圹ç«ã¡ãŸãã
- allocate:
Dynamic memory allocation on the heap. - åŒæ°ïŒargumentïŒ:
é¢æ°ãŸãã¯ã¡ãœããã«æž¡ãããæ å ±ã - associated type:
A type associated with a specific trait. Useful for defining the relationship between types. - ãã¢ã¡ã¿ã« RustïŒBare-metal RustïŒ:
äœã¬ãã«ã® Rust éçºãå€ãã®å Žåããªãã¬ãŒãã£ã³ã° ã·ã¹ãã ã®ãªãã·ã¹ãã ã«ãããã€ãããŸãããã¢ã¡ã¿ã« Rust ãã芧ãã ããã - block:
See Blocks and scope. - borrow:
See Borrowing. - åçšãã§ãã«ãŒïŒborrow checkerïŒ:
Rust ã³ã³ãã€ã©ã®äžéšããã¹ãŠã®åçšãæå¹ãã©ããããã§ãã¯ããŸãã - äžãã£ãïŒbraceïŒ:
{
and}
ããããã¯ãåºåããŸãã - ãã«ãïŒbuildïŒ:
ãœãŒã¹ã³ãŒããå®è¡å¯èœãªã³ãŒããŸãã¯äœ¿çšå¯èœãªããã°ã©ã ã«å€æããããã»ã¹ã - åŒã³åºãïŒcallïŒ:
é¢æ°ãŸãã¯ã¡ãœãããåŒã³åºããŸãã - ãã£ã³ãã«ïŒchannelïŒ:
ã¹ã¬ããé ã§ã¡ãã»ãŒãžãå®å šã«æž¡ãããã«äœ¿çšãããŸãã - Comprehensive Rust ðŠ:
ãã®ã³ãŒã¹ã¯ããŸãšã㊠Comprehensive Rust ðŠ ãšåŒã³ãŸãã - åæå®è¡ïŒconcurrencyïŒ:
è€æ°ã®ã¿ã¹ã¯ãŸãã¯ããã»ã¹ãåæã«å®è¡ããããšãæããŸãã - Concurrency in Rust:
See Concurrency in Rust. - å®æ°ïŒconstantïŒ:
ããã°ã©ã ã®å®è¡äžã«å€æŽãããªãå€ã - å¶åŸ¡ãããŒïŒcontrol flowïŒ:
åã ã®ã¹ããŒãã¡ã³ããŸãã¯åœä»€ãããã°ã©ã å ã§å®è¡ãããé åºã - ã¯ã©ãã·ã¥ïŒcrashïŒ:
äºæããªãå¶åŸ¡äžèœãªãšã©ãŒãŸãã¯çµäºã - åæåïŒenumerationïŒ:
è€æ°ã®ååä»ãå®æ°ã®ãã¡ã® 1 ã€ãä¿æããããŒã¿åãé¢é£ããã¿ãã«ãŸãã¯æ§é äœã䌎ãå ŽåããããŸãã - ãšã©ãŒïŒerrorïŒ:
æ³å®ãããåäœããéžè±ãããäºæããªãæ¡ä»¶ãŸãã¯çµæã - ãšã©ãŒåŠçïŒerror handlingïŒ:
ããã°ã©ã ã®å®è¡äžã«çºçãããšã©ãŒã管çããããã«å¯Ÿå¿ããããã»ã¹ã - æŒç¿ïŒexercise:ïŒ:
ããã°ã©ãã³ã° ã¹ãã«ã®åäžãšãã¹ããç®çãšããã¿ã¹ã¯ãŸãã¯åé¡ã - é¢æ°ïŒfunctionïŒ:
ç¹å®ã®ã¿ã¹ã¯ãå®è¡ããåå©çšå¯èœãªã³ãŒããããã¯ã - ã¬ããŒãž ã³ã¬ã¯ã¿ïŒgarbage collectorïŒ:
䜿çšãããªããªã£ããªããžã§ã¯ããå æããŠããã¡ã¢ãªãèªåçã«è§£æŸããã¡ã«ããºã ã - ãžã§ããªã¯ã¹ïŒgenericsïŒ:
åã®ãã¬ãŒã¹ãã«ãã䜿çšããŠã³ãŒããèšè¿°ããããŸããŸãªããŒã¿åã§ã³ãŒããåå©çšã§ããããã«ããæ©èœã - äžå€ïŒimmutableïŒ:
äœæåŸã«å€æŽã§ããªãããšã - çµ±åãã¹ãïŒintegration testïŒ:
ã·ã¹ãã ã®ããŸããŸãªéšåãã³ã³ããŒãã³ãéã®çžäºäœçšãæ€èšŒãããã¹ãã®äžçš®ã - ããŒã¯ãŒãïŒkeywordïŒ:
ç¹å®ã®æå³ãæã¡ãèå¥åãšããŠäœ¿çšã§ããªããããã°ã©ãã³ã°èšèªã®äºçŽèªã - ã©ã€ãã©ãªïŒlibraryïŒ:
ããã°ã©ã ã§äœ¿çšã§ããããªã³ã³ãã€ã«æžã¿ã®ã«ãŒãã³ãŸãã¯ã³ãŒãã®ã³ã¬ã¯ã·ã§ã³ã - ãã¯ãïŒmacroïŒ:
Rust ãã¯ãã¯ååã«!
ãå«ããããšã§èªèã§ããŸãããã¯ãã¯ãéåžžã®é¢æ°ã§ã¯äžååãªå Žåã«äœ¿çšãããŸããå žåçãªäŸãformat!
ã§ããããã¯å¯å€é·åŒæ°ãåããŸãããRust é¢æ°ã§ã¯ãµããŒããããŠããŸããã main
é¢æ°ïŒmain
functionïŒ:
Rust ããã°ã©ã ã®å®è¡ã¯main
é¢æ°ã§éå§ãããŸãã- äžèŽïŒmatchïŒ:
åŒã®å€ã«å¯Ÿãããã¿ãŒã³ ãããã³ã°ãå¯èœã«ãããRust ã®å¶åŸ¡ãããŒæ§é ã - ã¡ã¢ãªãªãŒã¯ïŒmemory leakïŒ:
ããã°ã©ã ã§äžèŠã«ãªã£ãã¡ã¢ãªã®è§£æŸã«å€±æããã¡ã¢ãªäœ¿çšéãåŸã ã«å¢å ããç¶æ³ã - ã¡ãœããïŒmethodïŒ:
Rust ã®ãªããžã§ã¯ããŸãã¯åã«é¢é£ä»ããããé¢æ°ã - ã¢ãžã¥ãŒã«ïŒmoduleïŒ:
é¢æ°ãåããã¬ã€ããªã©ã®å®çŸ©ãå«ãåå空éãRust ã§ã³ãŒããæŽçããããã«äœ¿çšãããŸãã - 移åïŒmoveïŒ:
Rust ã§ããå€æ°ããå¥ã®å€æ°ã«å€ã®æææš©ã移åããããšã - å¯å€ïŒmutableïŒ:
宣èšåŸã®å€æ°ã®å€æŽãå¯èœã«ãã Rust ã®ããããã£ã - æææš©ïŒownershipïŒ:
å€ã«é¢é£ä»ããããã¡ã¢ãªã®ç®¡çãã³ãŒãã®ã©ã®éšåãæ ãããå®çŸ©ãã Rust ã®æŠå¿µã - ãããã¯ïŒpanicïŒ:
ããã°ã©ã ã®çµäºãåŒãèµ·ãããRust ã®å埩äžèœãªãšã©ãŒç¶æ ã - ãã©ã¡ãŒã¿ïŒparameterïŒ:
é¢æ°ãŸãã¯ã¡ãœãããåŒã³åºããããšãã«æž¡ãããå€ã - ãã¿ãŒã³ïŒpatternïŒ:
Rust ã®åŒãšç §åã§ããå€ããªãã©ã«ãæ§é äœã®çµã¿åããã - ãã€ããŒãïŒpayloadïŒ:
ã¡ãã»ãŒãžãã€ãã³ãããŸãã¯ããŒã¿æ§é äœã§ä¿æãããããŒã¿ãŸãã¯æ å ±ã - ããã°ã©ã ïŒprogramïŒ:
ç¹å®ã®ã¿ã¹ã¯ãå®è¡ããããç¹å®ã®åé¡ã解決ãããããããã«ã³ã³ãã¥ãŒã¿ãå®è¡ã§ããäžé£ã®åœä»€ã - ããã°ã©ãã³ã°èšèªïŒprogramming languageïŒ:
ã³ã³ãã¥ãŒã¿ã«åœä»€ãäŒããããã«äœ¿çšãããæ£åŒãªã·ã¹ãã ïŒRust ãªã©ïŒã - ã¬ã·ãŒãïŒreceiverïŒ:
ã¡ãœãããåŒã³åºãããã€ã³ã¹ã¿ã³ã¹ãè¡šã Rust ã¡ãœããã®æåã®ãã©ã¡ãŒã¿ã - åç
§ã«ãŠã³ãïŒreference countingïŒ:
ãªããžã§ã¯ããžã®åç §ã®æ°ããã©ããã³ã°ããã«ãŠã³ãããŒãã«ãªããšãªããžã§ã¯ãã®å²ãåœãŠã解é€ããã¡ã¢ãªç®¡çæè¡ã - æ»ãå€ïŒreturnïŒ:
é¢æ°ããè¿ãããå€ã瀺ãããã«äœ¿çšããã Rust ã®ããŒã¯ãŒãã - Rust:
å®å šæ§ãããã©ãŒãã³ã¹ãåæå®è¡ã«éç¹ã眮ããã·ã¹ãã ããã°ã©ãã³ã°èšèªã - Rust Fundamentals:
Days 1 to 4 of this course. - Android ã§ã® RustïŒRust in AndroidïŒ:
Android ã§ã® Rust ãã芧ãã ããã - Chromium ã§ã® RustïŒRust in ChromiumïŒ:
Chromium ã§ã® Rust ãã芧ãã ããã - å®å
šïŒsafeïŒ:
Rust ã®æææš©ãšåçšã«é¢ããã«ãŒã«ã«åŸã£ãŠãã¡ã¢ãªé¢é£ã®ãšã©ãŒãé²æ¢ããã³ãŒããæããŸãã - ã¹ã³ãŒãïŒscopeïŒ:
å€æ°ãæå¹ãã€äœ¿çšå¯èœãªããã°ã©ã ã®é åã - æšæºã©ã€ãã©ãªïŒstandard libraryïŒ:
Rust ã®å¿ é æ©èœãæäŸããã¢ãžã¥ãŒã«ã®ã³ã¬ã¯ã·ã§ã³ã - éçïŒstaticïŒ:
éçãªå€æ°ã'static
ã©ã€ãã¿ã€ã ãæã€ã¢ã€ãã ãå®çŸ©ããããã«äœ¿çšããã Rust ã®ããŒã¯ãŒãã - string:
A data type storing textual data. See Strings for more. - æ§é äœïŒstructïŒ:
ç°ãªãåã®å€æ°ã 1 ã€ã®ååã§ã°ã«ãŒãåãã Rust ã®è€åããŒã¿åã - ãã¹ãïŒtestïŒ:
ä»ã®é¢æ°ã®æ£ããããã¹ãããé¢æ°ãå«ã Rust ã¢ãžã¥ãŒã«ã - ã¹ã¬ããïŒthreadïŒ:
åæå®è¡ãå¯èœã«ãããããã°ã©ã å ã®ç¬ç«ããå®è¡ã·ãŒã±ã³ã¹ã - ã¹ã¬ããã»ãŒãïŒthread safetyïŒ:
ãã«ãã¹ã¬ããç°å¢ã§æ£ããåäœãä¿èšŒããããã°ã©ã ã®ç¹æ§ã - ãã¬ã€ãïŒtraitïŒ:
æªç¥ã®åã«å¯ŸããŠå®çŸ©ãããã¡ãœããã®ã³ã¬ã¯ã·ã§ã³ãRust ã§ããªã¢ãŒãã£ãºã ãå®çŸããæ¹æ³ãæäŸããŸãã - ãã¬ã€ãå¢çïŒtrait boundïŒ:
ç¹å®ã®ãã¬ã€ããå®è£ ããããã«åãèŠæ±ã§ããæœè±¡åã - ã¿ãã«ïŒtupleïŒ:
ããŸããŸãªåã®å€æ°ãå«ãè€åããŒã¿åãã¿ãã« ãã£ãŒã«ãã«ã¯ååããªããåºæ°ã§ã¢ã¯ã»ã¹ããŸãã - åïŒtypeïŒ:
Rust ã®ç¹å®ã®çš®é¡ã®å€ã«å¯ŸããŠã©ã®ãªãã¬ãŒã·ã§ã³ãå®è¡ã§ããããæå®ããåé¡ã - åæšè«ïŒtype inferenceïŒ:
å€æ°ãŸãã¯åŒã®åãæšæž¬ãã Rust ã³ã³ãã€ã©ã®æ©èœã - æªå®çŸ©ã®åäœïŒundefined behaviorïŒ:
çµæãæå®ãããŠããªã Rust ã®ã¢ã¯ã·ã§ã³ãŸãã¯æ¡ä»¶ãå€ãã®å Žåãããã°ã©ã ã®äºæž¬äžèœãªåäœãåŒãèµ·ãããŸãã - å
±çšäœïŒunionïŒ:
ç°ãªãåã®å€ãäžåºŠã« 1 ã€ã ãä¿æã§ããããŒã¿åã - åäœãã¹ãïŒunit testïŒ:
Rust ã«ã¯ãå°èŠæš¡ãªåäœãã¹ããšå€§èŠæš¡ãªçµ±åãã¹ããå®è¡ããããã®çµã¿èŸŒã¿ãµããŒããä»å±ããŠããŸããåäœãã¹ã ãã芧ãã ããã - ãŠãããåïŒunit typeïŒ:
ããŒã¿ãä¿æããªãåãã¡ã³ããŒã®ãªãã¿ãã«ãšããŠèšè¿°ãããŸãã - unsafe:
The subset of Rust which allows you to trigger undefined behavior. See Unsafe Rust. - å€æ°ïŒvariableïŒ:
ããŒã¿ãæ ŒçŽããã¡ã¢ãªã®å Žæãå€æ°ã¯ã¹ã³ãŒãå ã§æå¹ã§ãã
Rust ã®ãã®ä»ã®ãªãœãŒã¹
Rust ã³ãã¥ããã£ã¯ãé«å質ãªç¡æã®ãªãœãŒã¹ããªã³ã©ã€ã³ã§å€æ°æäŸããŠããŸãã
æ£åŒãªããã¥ã¡ã³ã
Rust ãããžã§ã¯ãã¯å€ãã®ãªãœãŒã¹ããã¹ãããŠãããããã㯠Rust å šè¬ã«å¯Ÿå¿ããŠããŸãã
- The Rust Programming Language: Rust ã®æšæºçãªæžç±ã§ãç¡æã§å©çšã§ããŸããRust ã«ã€ããŠè©³ãã説æãããŠããã»ãããã«ãã§ãããããžã§ã¯ããããã€ãå«ãŸããŠããŸãã
- Rust By Example: ããŸããŸãªæ§é ã瀺ãäžé£ã®ãµã³ãã«ã䜿çšããŠãRust ã®æ§æã解説ããŠããŸããå°èŠæš¡ãªæŒç¿ãããã€ãçšæãããŠãããããã§ãµã³ãã«ã®ã³ãŒããæ¡åŒµããããæ±ããããŸãã
- Rust Standard Library: Rust ã®æšæºã©ã€ãã©ãªã®å®å šãªããã¥ã¡ã³ãã§ãã
- The Rust Reference: Rust ã®ææ³ãšã¡ã¢ãªã¢ãã«ã«ã€ããŠèª¬æããŠããæªå®æã®æžç±ã§ãã
Rust ã®å ¬åŒãµã€ãã§ãã¹ããããŠãããããå°éçãªã¬ã€ã:
- The Rustonomicon: æªå å·¥ã®ãã€ã³ã¿ã®æäœããä»ã®èšèªïŒFFIïŒãšã®ããåããªã©ãå®å šã§ãªã Rust ã«ã€ããŠèª¬æããŠããŸãã
- Asynchronous Programming in Rust: Rust Book ã®å·çåŸã«å°å ¥ãããæ°ããéåæããã°ã©ãã³ã° ã¢ãã«ã«ã€ããŠèª¬æããŠããŸãã
- The Embedded Rust Book: ãªãã¬ãŒãã£ã³ã° ã·ã¹ãã ã®ãªãçµã¿èŸŒã¿ããã€ã¹ã§ Rust ã䜿çšããæ¹æ³ã玹ä»ããŠããŸãã
éå ¬åŒã®åŠç¿ææ
Rust ã«é¢ãããã®ä»ã®ã¬ã€ããšãã¥ãŒããªã¢ã«:
- Learn Rust the Dangerous Way: é«åºŠãªç¥èãæããªã C ããã°ã©ããŒã®èŠç¹ã§ Rust ã解説ããŠããŸãã
- Rust for Embedded C Programmers: covers Rust from the perspective of developers who write firmware in C.
- Rust for professionals: ä»ã®èšèªïŒCãC++ãJavaãJavaScriptãPython ãªã©ïŒãšäžŠã¹ãŠæ¯èŒããªãããRust ã®æ§æã«ã€ããŠèª¬æããŠããŸãã
- Rust on Exercism: Rust ã®åŠç¿ã«åœ¹ç«ã€ 100 以äžã®æŒç¿ãçšæãããŠããŸãã
- Ferrous Teaching Material: Rust èšèªã®åºæ¬çãªéšåãšé«åºŠãªéšåã®äž¡æ¹ãã«ããŒãããäžé£ã®ã³ã³ãã¯ããªãã¬ãŒã³ããŒã·ã§ã³ã§ããWebAssemblyãasync / await ãªã©ã®ä»ã®ãããã¯ãæ±ã£ãŠããŸãã
- Advanced testing for Rust applications: a self-paced workshop that goes beyond Rustâs built-in testing framework. It covers
googletest
, snapshot testing, mocking as well as how to write your own custom test harness. - Beginnerâs Series to Rust ããã³ [Take your first steps with Rust](https://docs.microsoft. com/en-us/learn/paths/rust-first-steps/): åå¿è ã®ããããããŒã察象ãšãã 2 ã€ã® Rust ã¬ã€ãã§ãã1 ã€ç®ã¯ 35 åã®åç»ã§æ§æããã2 ã€ç®ã¯ Rust ã®æ§æãšåºæ¬çãªæ§é ã説æãã 11 ã®ã¢ãžã¥ãŒã«ã§æ§æãããŠããŸãã
- Learn Rust With Entirely Too Many Linked Lists: ããã€ãã®ç°ãªãã¿ã€ãã®ãªã¹ãæ§é ã®å®è£ ãéããŠãRust ã®ã¡ã¢ãªç®¡çã«ãŒã«ãæ·±ãæãäžããŠããŸãã
Rust ã«é¢ãããã®ä»ã®æžç±ã«ã€ããŠã¯ãLittle Book of Rust Books ãã芧ãã ããã
ã¯ã¬ãžãã
ããã§çŽ¹ä»ããææã¯ãå€ãã®åªãã Rust ããã¥ã¡ã³ãã®ãœãŒã¹ã«åºã¥ããŠããŸãã圹ç«ã€ãªãœãŒã¹ã®äžèŠ§ã«ã€ããŠã¯ããã®ä»ã®ãªãœãŒã¹ ã®ããŒãžãã芧ãã ããã
Comprehensive Rust ã®ææã¯ãApache 2.0 ã©ã€ã»ã³ã¹ã®èŠçŽã«ãã䜿çšã蚱諟ãããŠããŸãã詳现ã«ã€ããŠã¯ãLICENSE
ãã芧ãã ããã
Rust by Example
äžéšã®äŸãšæŒç¿ã¯ãRust by Example ããã³ããŒããŠç·šéãããã®ã§ããã©ã€ã»ã³ã¹èŠçŽãªã©ã®è©³çŽ°ã«ã€ããŠã¯ãthird_party/rust-by-example/
ãã£ã¬ã¯ããªãåç
§ããŠãã ããã
Rust on Exercism
äžéšã®æŒç¿ã¯ãRust on Exercism ãã³ããŒããŠç·šéãããã®ã§ããã©ã€ã»ã³ã¹èŠçŽãªã©ã®è©³çŽ°ã«ã€ããŠã¯ãthird_party/rust-on-exercism/
ãã£ã¬ã¯ããªãåç
§ããŠãã ããã
CXX
C++ ãšã®çžäºéçšæ§ ã»ã¯ã·ã§ã³ã§ã¯ãCXX ã®ç»åã䜿çšããŠããŸããã©ã€ã»ã³ã¹èŠçŽãªã©ã®è©³çŽ°ã«ã€ããŠã¯ãthird_party/cxx/
ãã£ã¬ã¯ããªãåç
§ããŠãã ããã