You've already forked comprehensive-rust
							
							
				mirror of
				https://github.com/google/comprehensive-rust.git
				synced 2025-10-31 00:27:50 +02:00 
			
		
		
		
	Publish Comprehensive Rust 🦀
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| /book/ | ||||
| /target/ | ||||
							
								
								
									
										28
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| # How to Contribute | ||||
|  | ||||
| We'd love to accept your patches and contributions to this project. There are | ||||
| just a few small guidelines you need to follow. | ||||
|  | ||||
| ## Contributor License Agreement | ||||
|  | ||||
| Contributions to this project must be accompanied by a Contributor License | ||||
| Agreement. You (or your employer) retain the copyright to your contribution; | ||||
| this simply gives us permission to use and redistribute your contributions as | ||||
| part of the project. Head over to <https://cla.developers.google.com/> to see | ||||
| your current agreements on file or to sign a new one. | ||||
|  | ||||
| You generally only need to submit a CLA once, so if you've already submitted one | ||||
| (even if it was for a different project), you probably don't need to do it | ||||
| again. | ||||
|  | ||||
| ## Code Reviews | ||||
|  | ||||
| All submissions, including submissions by project members, require review. We | ||||
| use GitHub pull requests for this purpose. Consult | ||||
| [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more | ||||
| information on using pull requests. | ||||
|  | ||||
| ## Community Guidelines | ||||
|  | ||||
| This project follows [Google's Open Source Community | ||||
| Guidelines](https://opensource.google/conduct/). | ||||
							
								
								
									
										49
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| [package] | ||||
| name = "comprehensive-rust" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| publish = false | ||||
|  | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
|  | ||||
| [[bin]] | ||||
| name = "for-loops" | ||||
| path = "src/exercises/day-1/for-loops.rs" | ||||
|  | ||||
| [[bin]] | ||||
| name = "book-library" | ||||
| path = "src/exercises/day-1/book-library.rs" | ||||
|  | ||||
| [[bin]] | ||||
| name = "points-polygons" | ||||
| path = "src/exercises/day-2/points-polygons.rs" | ||||
|  | ||||
| [[bin]] | ||||
| name = "luhn" | ||||
| path = "src/exercises/day-2/luhn.rs" | ||||
|  | ||||
| [[bin]] | ||||
| name = "strings-iterators" | ||||
| path = "src/exercises/day-2/strings-iterators.rs" | ||||
|  | ||||
| [[bin]] | ||||
| name = "safe-ffi-wrapper" | ||||
| path = "src/exercises/day-3/safe-ffi-wrapper.rs" | ||||
|  | ||||
| [[bin]] | ||||
| name = "simple-gui" | ||||
| path = "src/exercises/day-3/simple-gui.rs" | ||||
|  | ||||
| [[bin]] | ||||
| name = "dining-philosophers" | ||||
| path = "src/exercises/day-4/dining-philosophers.rs" | ||||
|  | ||||
| [[bin]] | ||||
| name = "link-checker" | ||||
| path = "src/exercises/day-4/link-checker.rs" | ||||
|  | ||||
|  | ||||
| [dependencies] | ||||
| reqwest = { version = "0.11.12", features = ["blocking"] } | ||||
| scraper = "0.13.0" | ||||
| thiserror = "1.0.37" | ||||
							
								
								
									
										202
									
								
								LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
|  | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
|    1. Definitions. | ||||
|  | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
|    END OF TERMS AND CONDITIONS | ||||
|  | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
|  | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "[]" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
|  | ||||
|    Copyright [yyyy] [name of copyright owner] | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
							
								
								
									
										40
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| # Comprehensive Rust 🦀 | ||||
|  | ||||
| This repository has the source code for Comprehensive Rust 🦀, a four day Rust | ||||
| course developed by the Android team. The course covers all aspects of Rust, | ||||
| from basic syntax to generics and error handling. It also includes | ||||
| Android-specific content on the last day. | ||||
|  | ||||
| ## Building | ||||
|  | ||||
| The course is built using [mdBook](https://github.com/rust-lang/mdBook) and its | ||||
| [Svgbob plugin](https://github.com/boozook/mdbook-svgbob). Install both tools | ||||
| with | ||||
|  | ||||
| ```shell | ||||
| $ cargo install mdbook | ||||
| $ cargo install mdbook-svgbob | ||||
| ``` | ||||
|  | ||||
| Then run | ||||
|  | ||||
| ```shell | ||||
| $ mdbook test | ||||
| ``` | ||||
|  | ||||
| to test all included Rust snippets. Run | ||||
|  | ||||
| ```shell | ||||
| $ mdbook serve | ||||
| ``` | ||||
|  | ||||
| to start a web server with the course. You'll find the content on | ||||
| <http://localhost:3000>. You can use `mdbook build` to create a static version | ||||
| of the course in the `book/` directory. | ||||
|  | ||||
| ## Contact | ||||
|  | ||||
| For questions or comments, please contact [Martin | ||||
| Geisler](mailto:mgeisler@google.com) or start a [discussion on | ||||
| GitHub](https://github.com/google/comprehensive-rust/discussions). We would love | ||||
| to hear from you. | ||||
							
								
								
									
										23
									
								
								book.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								book.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| [book] | ||||
| authors = ["Martin Geisler"] | ||||
| language = "en" | ||||
| multilingual = false | ||||
| src = "src" | ||||
| title = "Comprehensive Rust 🦀" | ||||
|  | ||||
| [rust] | ||||
| edition = "2021" | ||||
|  | ||||
| [preprocessor.svgbob] | ||||
| class = "bob" | ||||
|  | ||||
| [output.html] | ||||
| curly-quotes = true | ||||
| additional-js = ["ga4.js"] | ||||
|  | ||||
| [output.html.fold] | ||||
| enable = true | ||||
| level = 0 | ||||
|  | ||||
| [output.html.playground] | ||||
| editable = true | ||||
							
								
								
									
										87
									
								
								ga4.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								ga4.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // Setup cookie consent banner. | ||||
| var consent = document.createElement('script'); | ||||
| consent.setAttribute('data-autoload-cookie-consent-bar', 'true'); | ||||
| consent.setAttribute('src', 'https://www.gstatic.com/brandstudio/kato/cookie_choice_component/cookie_consent_bar.v3.js'); | ||||
| document.head.appendChild(consent); | ||||
|  | ||||
| // Load and configure Google Analytics. | ||||
| var ga4 = document.createElement('script'); | ||||
| ga4.setAttribute('src', 'https://www.googletagmanager.com/gtag/js?id=G-ZN78TEJMRW'); | ||||
| document.head.appendChild(ga4); | ||||
|  | ||||
| window.dataLayer = window.dataLayer || []; | ||||
| function gtag(){dataLayer.push(arguments);} | ||||
| gtag('js', new Date()); | ||||
| gtag('config', 'G-ZN78TEJMRW'); | ||||
|  | ||||
| // Look through all Playgrounds on the page to determine if the code snippet | ||||
| // matches one of the. If the code is different from all Playgrounds, we | ||||
| // conclude that the user modified the Playground before submitting it. | ||||
| function isPlaygroundCodeModified(code) { | ||||
|   // It sounds expensive to look through every Playground, but there are | ||||
|   // normally at most two Playground instances on a page. | ||||
|   let playgrounds = Array.from(document.querySelectorAll(".playground")); | ||||
|   return playgrounds.every(playground => { | ||||
|     let code_block = playground.querySelector("code"); | ||||
|     if (window.ace && code_block.classList.contains("editable")) { | ||||
|       let editor = window.ace.edit(code_block); | ||||
|       return code != editor.originalCode; | ||||
|     } else { | ||||
|       return code != code_block.textContent; | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| // Monkey-patch the window.fetch function so we can track the Playground | ||||
| // executions. | ||||
| const playgroundUrl = 'https://play.rust-lang.org/evaluate.json'; | ||||
| const { fetch: originalFetch } = window; | ||||
| window.fetch = async (...args) => { | ||||
|   let [resource, config ] = args; | ||||
|   if (resource != playgroundUrl) { | ||||
|     return originalFetch(resource, config); | ||||
|   } | ||||
|  | ||||
|   const startTime = window.performance.now(); | ||||
|   let endTime, errorMessage; | ||||
|   try { | ||||
|     // The fetch_with_timeout function defaults to a 6000 ms timeout. We use a | ||||
|     // slightly shorter timeout so that we can catch and log the error. | ||||
|     config.signal = AbortSignal.timeout(5500); | ||||
|     let response = await originalFetch(resource, config); | ||||
|     payload = await response.json(); | ||||
|     errorMessage = (payload.error == null) ? null : 'compilation_error'; | ||||
|     // Return object compatible with the unpackign done in book.js. | ||||
|     return {'json': () => payload}; | ||||
|   } catch (error) { | ||||
|     // fetch seems to always return AbortError, despite the example on | ||||
|     // https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout. | ||||
|     if (error.name == 'AbortError' || error.name == 'TimeoutError') { | ||||
|       error = new Error('timeout'); | ||||
|     } | ||||
|     errorMessage = error.message; | ||||
|     throw error; | ||||
|   } finally { | ||||
|     endTime = window.performance.now(); | ||||
|     let code = JSON.parse(config.body).code; | ||||
|     gtag("event", "playground", { | ||||
|       "modified": isPlaygroundCodeModified(code), | ||||
|       "error": errorMessage, | ||||
|       "latency": (endTime - startTime) / 1000, | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										1
									
								
								rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| max_width = 90 | ||||
							
								
								
									
										237
									
								
								src/SUMMARY.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								src/SUMMARY.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | ||||
| # Summary | ||||
|  | ||||
| [Welcome to Comprehensive Rust 🦀](welcome.md) | ||||
| - [Using Cargo](cargo.md) | ||||
|   - [Rust Ecosystem](cargo/rust-ecosystem.md) | ||||
|   - [Code Samples](cargo/code-samples.md) | ||||
|   - [Running Cargo Locally](cargo/running-locally.md) | ||||
| - [Course Structure](structure.md) | ||||
|  | ||||
|  | ||||
| # Day 1: Morning | ||||
|  | ||||
| ---- | ||||
|  | ||||
| - [Welcome](welcome-day-1.md) | ||||
|   - [What is Rust?](welcome-day-1/what-is-rust.md) | ||||
| - [Hello World!](hello-world.md) | ||||
|   - [Small Example](hello-world/small-example.md) | ||||
| - [Why Rust?](why-rust.md) | ||||
|   - [Compile Time Guarantees](why-rust/compile-time.md) | ||||
|   - [Runtime Guarantees](why-rust/runtime.md) | ||||
|   - [Modern Features](why-rust/modern.md) | ||||
| - [Basic Syntax](basic-syntax.md) | ||||
|   - [Scalar Types](basic-syntax/scalar-types.md) | ||||
|   - [Compound Types](basic-syntax/compound-types.md) | ||||
|   - [References](basic-syntax/references.md) | ||||
|     - [Dangling References](basic-syntax/references-dangling.md) | ||||
|   - [Slices](basic-syntax/slices.md) | ||||
|     - [`String` vs `str`](basic-syntax/string-slices.md) | ||||
|   - [Functions](basic-syntax/functions.md) | ||||
|     - [Methods](basic-syntax/methods.md) | ||||
|     - [Overloading](basic-syntax/functions-interlude.md) | ||||
| - [Exercises](exercises/day-1/morning.md) | ||||
|   - [Implicit Conversions](exercises/day-1/implicit-conversions.md) | ||||
|   - [Arrays and `for` Loops](exercises/day-1/for-loops.md) | ||||
|  | ||||
| # Day 1: Afternoon | ||||
|  | ||||
| - [Variables](basic-syntax/variables.md) | ||||
|   - [Type Inference](basic-syntax/type-inference.md) | ||||
|   - [`static` & `const`](basic-syntax/static-and-const.md)) | ||||
|   - [Scopes and Shadowing](basic-syntax/scopes-shadowing.md) | ||||
| - [Memory Management](memory-management.md) | ||||
|   - [Stack vs Heap](memory-management/stack-vs-heap.md) | ||||
|   - [Stack Memory](memory-management/stack.md) | ||||
|   - [Manual Memory Management](memory-management/manual.md) | ||||
|   - [Scope-Based Memory Management](memory-management/scope-based.md) | ||||
|   - [Garbage Collection](memory-management/garbage-collection.md) | ||||
|   - [Rust Memory Management](memory-management/rust.md) | ||||
|   - [Comparison](memory-management/comparison.md) | ||||
| - [Ownership](ownership.md) | ||||
|   - [Move Semantics](ownership/move-semantics.md) | ||||
|   - [Moved Strings in Rust](ownership/moved-strings-rust.md) | ||||
|     - [Double Frees in Modern C++](ownership/double-free-modern-cpp.md) | ||||
|   - [Moves in Function Calls](ownership/moves-function-calls.md) | ||||
|   - [Copying and Cloning](ownership/copy-clone.md) | ||||
|   - [Borrowing](ownership/borrowing.md) | ||||
|     - [Shared and Unique Borrows](ownership/shared-unique-borrows.md) | ||||
|   - [Lifetimes](ownership/lifetimes.md) | ||||
|   - [Lifetimes in Function Calls](ownership/lifetimes-function-calls.md) | ||||
|   - [Lifetimes in Data Structures](ownership/lifetimes-data-structures.md) | ||||
| - [Exercises](exercises/day-1/afternoon.md) | ||||
|   - [Designing a Library](exercises/day-1/book-library.md) | ||||
|   - [Iterators and Ownership](exercises/day-1/iterators-and-ownership.md) | ||||
|  | ||||
|  | ||||
| # Day 2: Morning | ||||
|  | ||||
| ---- | ||||
|  | ||||
| - [Welcome](welcome-day-2.md) | ||||
| - [Structs](structs.md) | ||||
|   - [Tuple Structs](structs/tuple-structs.md) | ||||
|   - [Field Shorthand Syntax](structs/field-shorthand.md) | ||||
| - [Enums](enums.md) | ||||
|   - [Variant Payloads](enums/variant-payloads.md) | ||||
|   - [Enum Sizes](enums/sizes.md) | ||||
| - [Methods](methods.md) | ||||
|   - [Method Receiver](methods/receiver.md) | ||||
|   - [Example](methods/example.md) | ||||
| - [Pattern Matching](pattern-matching.md) | ||||
|   - [Destructuring Enums](pattern-matching/destructuring-enums.md) | ||||
|   - [Destructuring Structs](pattern-matching/destructuring-structs.md) | ||||
|   - [Destructuring Arrays](pattern-matching/destructuring-arrays.md) | ||||
|   - [Match Guards](pattern-matching/match-guards.md) | ||||
| - [Exercises](exercises/day-2/morning.md) | ||||
|   - [Health Statistics](exercises/day-2/health-statistics.md) | ||||
|   - [Points and Polygons](exercises/day-2/points-polygons.md) | ||||
|  | ||||
| # Day 2: Afternoon | ||||
|  | ||||
| - [Control Flow](control-flow.md) | ||||
|   - [Blocks](control-flow/blocks.md) | ||||
|   - [`if` expressions](control-flow/if-expressions.md) | ||||
|   - [`if let` expressions](control-flow/if-let-expressions.md) | ||||
|   - [`while` expressions](control-flow/while-expressions.md) | ||||
|   - [`while let` expressions](control-flow/while-let-expressions.md) | ||||
|   - [`for` expressions](control-flow/for-expressions.md) | ||||
|   - [`loop` expressions](control-flow/loop-expressions.md) | ||||
|   - [`match` expressions](control-flow/match-expressions.md) | ||||
|   - [`break` & `continue`](control-flow/break-continue.md) | ||||
| - [Standard Library](std.md) | ||||
|   - [`String`](std/string.md) | ||||
|   - [`Option` and `Result`](std/option-result.md) | ||||
|   - [`Vec`](std/vec.md) | ||||
|   - [`HashMap`](std/hashmap.md) | ||||
|   - [`Box`](std/box.md) | ||||
|     - [`Recursive Data Types`](std/box-recursive.md) | ||||
|     - [`Niche Optimization`](std/box-niche.md) | ||||
|   - [`Rc`](std/rc.md) | ||||
| - [Modules](modules.md) | ||||
|   - [Visibility](modules/visibility.md) | ||||
|   - [Paths](modules/paths.md) | ||||
|   - [Filesystem Hierarchy](modules/filesystem.md) | ||||
| - [Exercises](exercises/day-2/afternoon.md) | ||||
|   - [Luhn Algorithm](exercises/day-2/luhn.md) | ||||
|   - [Strings and Iterators](exercises/day-2/strings-iterators.md) | ||||
|  | ||||
|  | ||||
| # Day 3: Morning | ||||
|  | ||||
| ---- | ||||
|  | ||||
| - [Welcome](welcome-day-3.md) | ||||
| - [Traits](traits.md) | ||||
|   - [Deriving Traits](traits/deriving-traits.md) | ||||
|   - [Default Methods](traits/default-methods.md) | ||||
|   - [Important Traits](traits/important-traits.md) | ||||
|     - [`Iterator`](traits/iterator.md) | ||||
|     - [`From` and `Into`](traits/from-into.md) | ||||
|     - [`Read` and `Write`](traits/read-write.md) | ||||
|     - [`Add`, `Mul`, ...](traits/operators.md) | ||||
|     - [`Drop`](traits/drop.md) | ||||
| - [Generics](generics.md) | ||||
|   - [Generic Data Types](generics/data-types.md) | ||||
|   - [Generic Methods](generics/methods.md) | ||||
|   - [Trait Bounds](generics/trait-bounds.md) | ||||
|   - [`impl Trait`](generics/impl-trait.md) | ||||
|   - [Closures](generics/closures.md) | ||||
|   - [Monomorphization](generics/monomorphization.md) | ||||
|   - [Trait Objects](generics/trait-objects.md) | ||||
| - [Exercises](exercises/day-3/morning.md) | ||||
|   - [A Simple GUI Library](exercises/day-3/simple-gui.md) | ||||
|  | ||||
| # Day 3: Afternoon | ||||
|  | ||||
| - [Error Handling](error-handling.md) | ||||
|   - [Panics](error-handling/panics.md) | ||||
|     - [Catching Stack Unwinding](error-handling/panic-unwind.md) | ||||
|   - [Structured Error Handling](error-handling/result.md) | ||||
|   - [Propagating Errors with `?`](error-handling/try-operator.md) | ||||
|     - [Converting Error Types](error-handling/converting-error-types.md) | ||||
|     - [Deriving Error Enums](error-handling/deriving-error-enums.md) | ||||
|     - [Adding Context to Errors](error-handling/error-contexts.md) | ||||
| - [Testing](testing.md) | ||||
|   - [Unit Tests](testing/unit-tests.md) | ||||
|   - [Test Modules](testing/test-modules.md) | ||||
|   - [Documentation Tests](testing/doc-tests.md) | ||||
|   - [Integration Tests](testing/integration-tests.md) | ||||
| - [Unsafe Rust](unsafe.md) | ||||
|   - [Dereferencing Raw Pointers](unsafe/raw-pointers.md) | ||||
|   - [Mutable Static Variables](unsafe/mutable-static-variables.md) | ||||
|   - [Calling Unsafe Functions](unsafe/unsafe-functions.md) | ||||
|   - [Extern Functions](unsafe/extern-functions.md) | ||||
|   - [Unions](unsafe/unions.md) | ||||
| - [Exercises](exercises/day-3/afternoon.md) | ||||
|   - [Safe FFI Wrapper](exercises/day-3/safe-ffi-wrapper.md) | ||||
|  | ||||
|  | ||||
| # Day 4: Morning | ||||
|  | ||||
| ---- | ||||
|  | ||||
| - [Welcome](welcome-day-4.md) | ||||
| - [Concurrency](concurrency.md) | ||||
|   - [Threads](concurrency/threads.md) | ||||
|   - [Scoped Threads](concurrency/scoped-threads.md) | ||||
|   - [Channels](concurrency/channels.md) | ||||
|     - [Unbounded Channels](concurrency/channels/unbounded.md) | ||||
|     - [Bounded Channels](concurrency/channels/bounded.md) | ||||
|   - [Shared State](concurrency/shared_state.md) | ||||
|     - [`Arc`](concurrency/shared_state/arc.md) | ||||
|     - [`Mutex`](concurrency/shared_state/mutex.md) | ||||
|     - [Example](concurrency/shared_state/example.md) | ||||
|   - [`Send` and `Sync`](concurrency/send-sync.md) | ||||
|     - [`Send`](concurrency/send-sync/send.md) | ||||
|     - [`Sync`](concurrency/send-sync/sync.md) | ||||
|     - [Examples](concurrency/send-sync/examples.md) | ||||
| - [Exercises](exercises/day-4/morning.md) | ||||
|   - [Dining Philosophers](exercises/day-4/dining-philosophers.md) | ||||
|   - [Multi-threaded Link Checker](exercises/day-4/link-checker.md) | ||||
|  | ||||
| # Day 4: Afternoon | ||||
|  | ||||
| ---- | ||||
|  | ||||
| - [Android](android.md) | ||||
|   - [Setup](android/setup.md) | ||||
|   - [Build Rules](android/build-rules.md) | ||||
|     - [Binary](android/build-rules/binary.md) | ||||
|     - [Library](android/build-rules/library.md) | ||||
|   - [AIDL](android/aidl.md) | ||||
|     - [Interface](android/aidl/interface.md) | ||||
|     - [Implementation](android/aidl/implementation.md) | ||||
|     - [Server](android/aidl/server.md) | ||||
|     - [Deploy](android/aidl/deploy.md) | ||||
|     - [Client](android/aidl/client.md) | ||||
|     - [Changing API](android/aidl/changing.md) | ||||
|   - [Logging](android/logging.md) | ||||
|   - [Interoperability](android/interoperability.md) | ||||
|     - [With C](android/interoperability/with-c.md) | ||||
|       - [Calling C with Bindgen](android/interoperability/with-c/bindgen.md) | ||||
|       - [Calling Rust from C](android/interoperability/with-c/rust.md) | ||||
|     - [With C++](android/interoperability/cpp.md)) | ||||
|     - [With Java](android/interoperability/java.md) | ||||
| - [Exercises](exercises/day-4/afternoon.md) | ||||
|  | ||||
| # Final Words | ||||
|  | ||||
| - [Thanks!](thanks.md) | ||||
| - [Other Resources](other-resources.md) | ||||
| - [Credits](credits.md) | ||||
|  | ||||
| ---- | ||||
|  | ||||
| # Solutions | ||||
|  | ||||
| ---- | ||||
|  | ||||
| - [Solutions](exercises/solutions.md) | ||||
|   - [Day 1 Morning](exercises/day-1/solutions-morning.md) | ||||
|   - [Day 1 Afternoon](exercises/day-1/solutions-afternoon.md) | ||||
|   - [Day 2 Morning](exercises/day-2/solutions-morning.md) | ||||
|   - [Day 2 Afternoon](exercises/day-2/solutions-afternoon.md) | ||||
|   - [Day 3 Morning](exercises/day-3/solutions-morning.md) | ||||
|   - [Day 3 Afternoon](exercises/day-3/solutions-afternoon.md) | ||||
|   - [Day 4 Morning](exercises/day-4/solutions-morning.md) | ||||
							
								
								
									
										6
									
								
								src/android.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/android.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| # Android | ||||
|  | ||||
| Rust is supported for native platform development on Android. This means that | ||||
| you can write new operating system services in Rust, as well as extending | ||||
| existing services. | ||||
|  | ||||
							
								
								
									
										7
									
								
								src/android/aidl.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/android/aidl.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # AIDL | ||||
|  | ||||
| The [Android Interface Definition Language | ||||
| (AIDL)](https://developer.android.com/guide/components/aidl) is support in Rust: | ||||
|  | ||||
| * Rust code can call existing AIDL servers, | ||||
| * You can create new AIDL servers in Rust. | ||||
							
								
								
									
										38
									
								
								src/android/aidl/birthday_service/Android.bp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/android/aidl/birthday_service/Android.bp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| // ANCHOR: libbirthdayservice | ||||
| rust_library { | ||||
|     name: "libbirthdayservice", | ||||
|     srcs: ["src/lib.rs"], | ||||
|     crate_name: "birthdayservice", | ||||
|     rustlibs: [ | ||||
|         "com.example.birthdayservice-rust", | ||||
|         "libbinder_rs", | ||||
|     ], | ||||
| } | ||||
| // ANCHOR_END: libbirthdayservice | ||||
|  | ||||
| // ANCHOR: birthday_server | ||||
| rust_binary { | ||||
|     name: "birthday_server", | ||||
|     crate_name: "birthday_server", | ||||
|     srcs: ["src/server.rs"], | ||||
|     rustlibs: [ | ||||
|         "com.example.birthdayservice-rust", | ||||
|         "libbinder_rs", | ||||
|         "libbirthdayservice", | ||||
|     ], | ||||
|     prefer_rlib: true, | ||||
| } | ||||
| // ANCHOR_END: birthday_server | ||||
|  | ||||
| // ANCHOR: birthday_client | ||||
| rust_binary { | ||||
|     name: "birthday_client", | ||||
|     crate_name: "birthday_client", | ||||
|     srcs: ["src/client.rs"], | ||||
|     rustlibs: [ | ||||
|         "com.example.birthdayservice-rust", | ||||
|         "libbinder_rs", | ||||
|     ], | ||||
|     prefer_rlib: true, | ||||
| } | ||||
| // ANCHOR_END: birthday_client | ||||
							
								
								
									
										10
									
								
								src/android/aidl/birthday_service/aidl/Android.bp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/android/aidl/birthday_service/aidl/Android.bp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| aidl_interface { | ||||
|     name: "com.example.birthdayservice", | ||||
|     srcs: ["com/example/birthdayservice/*.aidl"], | ||||
|     unstable: true, | ||||
|     backend: { | ||||
|         rust: { // Rust is not enabled by default | ||||
|             enabled: true, | ||||
|         }, | ||||
|     }, | ||||
| } | ||||
| @@ -0,0 +1,22 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: IBirthdayService | ||||
| package com.example.birthdayservice; | ||||
|  | ||||
| /** Birthday service interface. */ | ||||
| interface IBirthdayService { | ||||
|     /** Generate a Happy Birthday message. */ | ||||
|     String wishHappyBirthday(String name, int years); | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/android/aidl/birthday_service/src/client.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/android/aidl/birthday_service/src/client.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: main | ||||
| //! Birthday service. | ||||
| use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::IBirthdayService; | ||||
| use com_example_birthdayservice::binder; | ||||
|  | ||||
| const SERVICE_IDENTIFIER: &str = "birthdayservice"; | ||||
|  | ||||
| /// Connect to the BirthdayService. | ||||
| pub fn connect() -> Result<binder::Strong<dyn IBirthdayService>, binder::StatusCode> { | ||||
|     binder::get_interface(SERVICE_IDENTIFIER) | ||||
| } | ||||
|  | ||||
| /// Call the birthday service. | ||||
| fn main() -> Result<(), binder::Status> { | ||||
|     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 = connect().expect("Failed to connect to BirthdayService"); | ||||
|     let msg = service.wishHappyBirthday(&name, years)?; | ||||
|     println!("{msg}"); | ||||
|     Ok(()) | ||||
| } | ||||
							
								
								
									
										31
									
								
								src/android/aidl/birthday_service/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/android/aidl/birthday_service/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: IBirthdayService | ||||
| //! Implementation of the `IBirthdayService` AIDL interface. | ||||
| use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::IBirthdayService; | ||||
| use com_example_birthdayservice::binder; | ||||
|  | ||||
| /// The `IBirthdayService` implementation. | ||||
| 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!" | ||||
|         )) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										33
									
								
								src/android/aidl/birthday_service/src/server.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/android/aidl/birthday_service/src/server.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: main | ||||
| //! Birthday service. | ||||
| use birthdayservice::BirthdayService; | ||||
| use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::BnBirthdayService; | ||||
| use com_example_birthdayservice::binder; | ||||
|  | ||||
| const SERVICE_IDENTIFIER: &str = "birthdayservice"; | ||||
|  | ||||
| /// Entry point for birthday service. | ||||
| 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() | ||||
| } | ||||
							
								
								
									
										14
									
								
								src/android/aidl/changing.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/android/aidl/changing.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| # Changing API | ||||
|  | ||||
| Let us extend the API with more functionality: we want to let clients specify a | ||||
| list of lines for the birthday card: | ||||
|  | ||||
| ```java | ||||
| package com.example.birthdayservice; | ||||
|  | ||||
| /** Birthday service interface. */ | ||||
| interface IBirthdayService { | ||||
|     /** Generate a Happy Birthday message. */ | ||||
|     String wishHappyBirthday(String name, int years, in String[] text); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										24
									
								
								src/android/aidl/client.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/android/aidl/client.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| # AIDL Client | ||||
|  | ||||
| Finally, we can create a Rust client for our new service. | ||||
|  | ||||
| *birthday_service/src/client.rs*: | ||||
|  | ||||
| ```rust,ignore | ||||
| {{#include birthday_service/src/client.rs:main}} | ||||
| ``` | ||||
|  | ||||
| *birthday_service/Android.bp*: | ||||
|  | ||||
| ```javascript | ||||
| {{#include birthday_service/Android.bp:birthday_client}} | ||||
| ``` | ||||
|  | ||||
| Notice that the client does not depend on `libbirthdayservice`. | ||||
|  | ||||
| Build, push, and run the client on your device: | ||||
|  | ||||
| ```shell | ||||
| {{#include ../build_all.sh:birthday_client}} | ||||
| Happy Birthday Charlie, congratulations with the 60 years! | ||||
| ``` | ||||
							
								
								
									
										29
									
								
								src/android/aidl/deploy.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/android/aidl/deploy.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| # Deploy | ||||
|  | ||||
| We can now build, push, and start the service: | ||||
|  | ||||
| ```shell | ||||
| {{#include ../build_all.sh:birthday_server}} | ||||
| ``` | ||||
|  | ||||
| In another terminal, check that the service runs: | ||||
|  | ||||
| ```shell | ||||
| {{#include ../build_all.sh:service_check_birthday_server}} | ||||
| Service birthdayservice: found | ||||
| ``` | ||||
|  | ||||
| You can also call the service with `service call`: | ||||
|  | ||||
| ```shell | ||||
| $ {{#include ../build_all.sh:service_call_birthday_server}} | ||||
| 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.!.....        ') | ||||
| ``` | ||||
							
								
								
									
										15
									
								
								src/android/aidl/implementation.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/android/aidl/implementation.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # Service Implementation | ||||
|  | ||||
| We can now implement the AIDL service: | ||||
|  | ||||
| *birthday_service/src/lib.rs*: | ||||
|  | ||||
| ```rust,ignore | ||||
| {{#include birthday_service/src/lib.rs:IBirthdayService}} | ||||
| ``` | ||||
|  | ||||
| *birthday_service/Android.bp*: | ||||
|  | ||||
| ```javascript | ||||
| {{#include birthday_service/Android.bp:libbirthdayservice}} | ||||
| ``` | ||||
							
								
								
									
										18
									
								
								src/android/aidl/interface.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/android/aidl/interface.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| # AIDL Interfaces | ||||
|  | ||||
| You declare the API of your service using an AIDL interface: | ||||
|  | ||||
| *birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl*: | ||||
|  | ||||
| ```java | ||||
| {{#include birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl:IBirthdayService}} | ||||
| ``` | ||||
|  | ||||
| *birthday_service/aidl/Android.bp*: | ||||
|  | ||||
| ```javascript | ||||
| {{#include birthday_service/aidl/Android.bp}} | ||||
| ``` | ||||
|  | ||||
| Add `vendor_available: true` if your AIDL file is used by a binary in the vendor | ||||
| partition. | ||||
							
								
								
									
										15
									
								
								src/android/aidl/server.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/android/aidl/server.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # AIDL Server | ||||
|  | ||||
| Finally, we can create a server which exposes the service: | ||||
|  | ||||
| *birthday_service/src/server.rs*: | ||||
|  | ||||
| ```rust,ignore | ||||
| {{#include birthday_service/src/server.rs:main}} | ||||
| ``` | ||||
|  | ||||
| *birthday_service/Android.bp*: | ||||
|  | ||||
| ```javascript | ||||
| {{#include birthday_service/Android.bp:birthday_server}} | ||||
| ``` | ||||
							
								
								
									
										27
									
								
								src/android/bpfmt.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								src/android/bpfmt.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #!/bin/zsh | ||||
| # Copyright 2022 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. | ||||
|  | ||||
| # Simple wrapper for bpfmt which will remove unnecessary newlines before the | ||||
| # mdbook anchors. | ||||
|  | ||||
| if ! type bpfmt > /dev/null; then | ||||
|   echo 'Can not find bpfmt, do you need to run "m bpfmt"?' | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| for f in comprehensive_rust/**/Android.bp; do | ||||
|   bpfmt -s -w $f | ||||
|   sed -zi 's|\n// ANCHOR_END|// ANCHOR_END|g' $f | ||||
| done | ||||
							
								
								
									
										16
									
								
								src/android/build-rules.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/android/build-rules.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| # Build Rules | ||||
|  | ||||
| The Android build system (Soong) supports Rust via a number of modules: | ||||
|  | ||||
| | Module Type       | Description                                                                                        | | ||||
| |-------------------|----------------------------------------------------------------------------------------------------| | ||||
| | `rust_binary`     | Produces a Rust binary.                                                                            | | ||||
| | `rust_library`    | Produces a Rust library, and provides both `rlib` and `dylib` variants.                            | | ||||
| | `rust_ffi`        | Produces a Rust C library usable by `cc` modules, and provides both static and shared variants.    | | ||||
| | `rust_proc_macro` | Produces a `proc-macro` Rust library. These are analogous to compiler plugins.                     | | ||||
| | `rust_test`       | Produces a Rust test binary that uses the standard Rust test harness.                              | | ||||
| | `rust_fuzz`       | Produces a Rust fuzz binary leveraging `libfuzzer`.                                                | | ||||
| | `rust_protobuf`   | Generates source and produces a Rust library that provides an interface for a particular protobuf. | | ||||
| | `rust_bindgen`    | Generates source and produces a Rust library containing Rust bindings to C libraries.              | | ||||
|  | ||||
| We will look at `rust_binary` and `rust_library` next. | ||||
							
								
								
									
										23
									
								
								src/android/build-rules/binary.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/android/build-rules/binary.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # Rust Binaries | ||||
|  | ||||
| Let us start with a simple application. At the root of an AOSP checkout, create | ||||
| the following files: | ||||
|  | ||||
| _hello_rust/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include binary/Android.bp}} | ||||
| ``` | ||||
|  | ||||
| _hello_rust/src/main.rs_: | ||||
|  | ||||
| ```rust | ||||
| {{#include binary/src/main.rs:main}} | ||||
| ``` | ||||
|  | ||||
| You can now build, push, and run the binary: | ||||
|  | ||||
| ```shell | ||||
| {{#include ../build_all.sh:hello_rust}} | ||||
| Hello from Rust! | ||||
| ``` | ||||
							
								
								
									
										5
									
								
								src/android/build-rules/binary/Android.bp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/android/build-rules/binary/Android.bp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| rust_binary { | ||||
|     name: "hello_rust", | ||||
|     crate_name: "hello_rust", | ||||
|     srcs: ["src/main.rs"], | ||||
| } | ||||
							
								
								
									
										21
									
								
								src/android/build-rules/binary/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/android/build-rules/binary/src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: main | ||||
| //! Rust demo. | ||||
|  | ||||
| /// Prints a greeting to standard output. | ||||
| fn main() { | ||||
|     println!("Hello from Rust!"); | ||||
| } | ||||
							
								
								
									
										37
									
								
								src/android/build-rules/library.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/android/build-rules/library.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| # Rust Libraries | ||||
|  | ||||
| You use `rust_library` to create a new Rust library for Android. | ||||
|  | ||||
| Here we declare a dependency on two libraries: | ||||
|  | ||||
| * `libgreeting`, which we define below, | ||||
| * `libtextwrap`, which is a crate already vendored in | ||||
|   [`external/rust/crates/`][crates]. | ||||
|  | ||||
| [crates]: https://cs.android.com/android/platform/superproject/+/master:external/rust/crates/ | ||||
|  | ||||
| _hello_rust/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include library/Android.bp}} | ||||
| ``` | ||||
|  | ||||
| _hello_rust/src/main.rs_: | ||||
|  | ||||
| ```rust,ignore | ||||
| {{#include library/src/main.rs:main}} | ||||
| ``` | ||||
|  | ||||
| _hello_rust/src/lib.rs_: | ||||
|  | ||||
| ```rust,ignore | ||||
| {{#include library/src/lib.rs:greeting}} | ||||
| ``` | ||||
|  | ||||
| You build, push, and run the binary like before: | ||||
|  | ||||
| ```shell | ||||
| {{#include ../build_all.sh:hello_rust_with_dep}} | ||||
| Hello Bob, it is very | ||||
| nice to meet you! | ||||
| ``` | ||||
							
								
								
									
										16
									
								
								src/android/build-rules/library/Android.bp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/android/build-rules/library/Android.bp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| 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"], | ||||
| } | ||||
							
								
								
									
										21
									
								
								src/android/build-rules/library/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/android/build-rules/library/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: greeting | ||||
| //! Greeting library. | ||||
|  | ||||
| /// Greet `name`. | ||||
| pub fn greeting(name: &str) -> String { | ||||
|     format!("Hello {name}, it is very nice to meet you!") | ||||
| } | ||||
							
								
								
									
										24
									
								
								src/android/build-rules/library/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/android/build-rules/library/src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: main | ||||
| //! Rust demo. | ||||
|  | ||||
| use greetings::greeting; | ||||
| use textwrap::fill; | ||||
|  | ||||
| /// Prints a greeting to standard output. | ||||
| fn main() { | ||||
|     println!("{}", fill(&greeting("Bob"), 24)); | ||||
| } | ||||
							
								
								
									
										130
									
								
								src/android/build_all.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										130
									
								
								src/android/build_all.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| #!/bin/bash | ||||
| # Copyright 2022 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. | ||||
|  | ||||
| set -e | ||||
|  | ||||
| function run_example() { | ||||
|   while read -r line; do | ||||
|     if [[ "$line" != \#* ]]; then | ||||
|       echo "$line" | ||||
|       eval "${line#$ }" | ||||
|     fi | ||||
|   done | ||||
| } | ||||
|  | ||||
| cd $ANDROID_BUILD_TOP | ||||
| source build/envsetup.sh | ||||
| lunch aosp_cf_x86_64_phone-userdebug | ||||
| #acloud reconnect --autoconnect adb | ||||
|  | ||||
| adb root | ||||
| adb shell rm -rf '/data/local/tmp/*' | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: hello_rust | ||||
| $ m hello_rust | ||||
| $ adb push $ANDROID_PRODUCT_OUT/system/bin/hello_rust /data/local/tmp | ||||
| $ adb shell /data/local/tmp/hello_rust | ||||
| # ANCHOR_END: hello_rust | ||||
| EOF | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: hello_rust_with_dep | ||||
| $ 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 | ||||
| # ANCHOR_END: hello_rust_with_dep | ||||
| EOF | ||||
|  | ||||
| function birthday_server() { | ||||
|   run_example <<EOF | ||||
| # ANCHOR: birthday_server | ||||
| $ m birthday_server | ||||
| $ adb push $ANDROID_PRODUCT_OUT/system/bin/birthday_server /data/local/tmp | ||||
| $ adb shell /data/local/tmp/birthday_server | ||||
| # ANCHOR_END: birthday_server | ||||
| EOF | ||||
| } | ||||
|  | ||||
| pkill -f birthday_server || true | ||||
| birthday_server & | ||||
| BIRTHDAY_SERVER_PID=$! | ||||
|  | ||||
| while adb shell service check birthdayservice | grep -q 'not found'; do | ||||
|   echo "Waiting on birthdayservice..." | ||||
|   sleep 3 | ||||
| done | ||||
| echo "Found birthdayservice..." | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: service_check_birthday_server | ||||
| $ adb shell service check birthdayservice | ||||
| # ANCHOR_END: service_check_birthday_server | ||||
| EOF | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: service_call_birthday_server | ||||
| $ adb shell service call birthdayservice 1 s16 Bob i32 24 | ||||
| # ANCHOR_END: service_call_birthday_server | ||||
| EOF | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: birthday_client | ||||
| $ m birthday_client | ||||
| $ adb push $ANDROID_PRODUCT_OUT/system/bin/birthday_client /data/local/tmp | ||||
| $ adb shell /data/local/tmp/birthday_client Charlie 60 | ||||
| # ANCHOR_END: birthday_client | ||||
| EOF | ||||
|  | ||||
| pkill -f birthday_server | ||||
|  | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: hello_rust_logs | ||||
| $ 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 | ||||
| # ANCHOR_END: hello_rust_logs | ||||
| EOF | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: print_birthday_card | ||||
| $ 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 | ||||
| # ANCHOR_END: print_birthday_card | ||||
| EOF | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: libbirthday_bindgen_test | ||||
| $ atest libbirthday_bindgen_test | ||||
| # ANCHOR_END: libbirthday_bindgen_test | ||||
| EOF | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: analyze_numbers | ||||
| $ m analyze_numbers | ||||
| $ adb push $ANDROID_PRODUCT_OUT/system/bin/analyze_numbers /data/local/tmp | ||||
| $ adb shell /data/local/tmp/analyze_numbers | ||||
| # ANCHOR_END: analyze_numbers | ||||
| EOF | ||||
|  | ||||
| run_example <<EOF | ||||
| # ANCHOR: helloworld_jni | ||||
| $ m helloworld_jni | ||||
| $ adb sync  # requires adb root && adb remount | ||||
| $ adb shell /system/bin/helloworld_jni | ||||
| # ANCHOR_END: helloworld_jni | ||||
| EOF | ||||
							
								
								
									
										10
									
								
								src/android/interoperability.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/android/interoperability.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| # Interoperability | ||||
|  | ||||
| Rust has excellent support for interoperability with other languages. This means | ||||
| that you can | ||||
|  | ||||
| * Call Rust functions from other languages | ||||
| * Call functions written in other languages from Rust | ||||
|  | ||||
| When you call functions in a foreign language we say that you're using a | ||||
| _foreign function interface_, also known as FFI. | ||||
							
								
								
									
										13
									
								
								src/android/interoperability/cpp.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/android/interoperability/cpp.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| # With C++ | ||||
|  | ||||
| The [CXX crate][1] makes it possible to do safe interoperability between Rust | ||||
| and C++. | ||||
|  | ||||
| The overall approach looks like this: | ||||
|  | ||||
| <img src="cpp/overview.svg"> | ||||
|  | ||||
| See the [CXX tutorial][2] for an full example of using this. | ||||
|  | ||||
| [1]: https://cxx.rs/ | ||||
| [2]: https://cxx.rs/tutorial.html | ||||
							
								
								
									
										1
									
								
								src/android/interoperability/cpp/overview.svg
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								src/android/interoperability/cpp/overview.svg
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | ||||
| ../../../../third_party/cxx/overview.svg | ||||
							
								
								
									
										39
									
								
								src/android/interoperability/java.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/android/interoperability/java.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| # Interoperability with Java | ||||
|  | ||||
| Java can load shared objects via [Java Native Interface | ||||
| (JNI)](https://en.wikipedia.org/wiki/Java_Native_Interface). The [`jni` | ||||
| crate](https://docs.rs/jni/) allows you to create a compatible library. | ||||
|  | ||||
| First, we create a Rust function to export to Java: | ||||
|  | ||||
| _interoperability/java/src/lib.rs_: | ||||
|  | ||||
| ```rust,compile_fail | ||||
| {{#include java/src/lib.rs:hello}} | ||||
| ``` | ||||
|  | ||||
| _interoperability/java/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include java/Android.bp:libhello_jni}} | ||||
| ``` | ||||
|  | ||||
| Finally, we can call this function from Java: | ||||
|  | ||||
| _interoperability/java/HelloWorld.java_: | ||||
|  | ||||
| ```java | ||||
| {{#include java/HelloWorld.java:HelloWorld}} | ||||
| ``` | ||||
|  | ||||
| _interoperability/java/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include java/Android.bp:helloworld_jni}} | ||||
| ``` | ||||
|  | ||||
| Finally, you can build, sync, and run the binary: | ||||
|  | ||||
| ```shell | ||||
| {{#include ../build_all.sh:helloworld_jni}} | ||||
| ``` | ||||
							
								
								
									
										17
									
								
								src/android/interoperability/java/Android.bp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/android/interoperability/java/Android.bp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| // ANCHOR: libhello_jni | ||||
| rust_ffi_shared { | ||||
|     name: "libhello_jni", | ||||
|     crate_name: "hello_jni", | ||||
|     srcs: ["src/lib.rs"], | ||||
|     rustlibs: ["libjni"], | ||||
| } | ||||
| // ANCHOR_END: libhello_jni | ||||
|  | ||||
| // ANCHOR: helloworld_jni | ||||
| java_binary { | ||||
|     name: "helloworld_jni", | ||||
|     srcs: ["HelloWorld.java"], | ||||
|     main_class: "HelloWorld", | ||||
|     required: ["libhello_jni"], | ||||
| } | ||||
| // ANCHOR_END: helloworld_jni | ||||
							
								
								
									
										29
									
								
								src/android/interoperability/java/HelloWorld.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/android/interoperability/java/HelloWorld.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| /* | ||||
|  * Copyright 2022 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. | ||||
|  */ | ||||
|  | ||||
| // ANCHOR: HelloWorld | ||||
| 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); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										33
									
								
								src/android/interoperability/java/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/android/interoperability/java/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: hello | ||||
| //! Rust <-> Java FFI demo. | ||||
|  | ||||
| use jni::objects::{JClass, JString}; | ||||
| use jni::sys::jstring; | ||||
| use jni::JNIEnv; | ||||
|  | ||||
| /// HelloWorld::hello method implementation. | ||||
| #[no_mangle] | ||||
| pub extern "system" fn Java_HelloWorld_hello( | ||||
|     env: JNIEnv, | ||||
|     _class: JClass, | ||||
|     name: JString, | ||||
| ) -> jstring { | ||||
|     let input: String = env.get_string(name).unwrap().into(); | ||||
|     let greeting = format!("Hello, {input}!"); | ||||
|     let output = env.new_string(greeting).unwrap(); | ||||
|     output.into_inner() | ||||
| } | ||||
							
								
								
									
										26
									
								
								src/android/interoperability/with-c.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/android/interoperability/with-c.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| # Interoperability with C | ||||
|  | ||||
| Rust has full support for linking object files with a C calling convention. | ||||
| Similarly, you can export Rust functions and call them from C. | ||||
|  | ||||
| You can do it by hand if you want: | ||||
|  | ||||
| ```rust | ||||
| extern "C" { | ||||
|     fn abs(x: i32) -> i32; | ||||
| } | ||||
|  | ||||
| fn main() { | ||||
|     let x = -42; | ||||
|     let abs_x = unsafe { abs(x) }; | ||||
|     println!("{x}, {abs_x}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| We already saw this in the [Safe FFI Wrapper | ||||
| exercise](../../exercises/day-3/safe-ffi-wrapper.md). | ||||
|  | ||||
| > This assumes full knowledge of the target platform. Not recommended for | ||||
| > production. | ||||
|  | ||||
| We will look at better options next. | ||||
							
								
								
									
										75
									
								
								src/android/interoperability/with-c/bindgen.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/android/interoperability/with-c/bindgen.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| # Using Bindgen | ||||
|  | ||||
| The [bindgen](https://rust-lang.github.io/rust-bindgen/introduction.html) tool | ||||
| can auto-generate bindings from a C header file. | ||||
|  | ||||
| First create a small C library: | ||||
|  | ||||
| _interoperability/bindgen/libbirthday.h_: | ||||
|  | ||||
| ```c | ||||
| {{#include bindgen/libbirthday.h:card}} | ||||
| ``` | ||||
|  | ||||
| _interoperability/bindgen/libbirthday.c_: | ||||
|  | ||||
| ```c | ||||
| {{#include bindgen/libbirthday.c:print_card}} | ||||
| ``` | ||||
|  | ||||
| Add this to your `Android.bp` file: | ||||
|  | ||||
| _interoperability/bindgen/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include bindgen/Android.bp:libbirthday}} | ||||
| ``` | ||||
|  | ||||
| Create a wrapper header file for the library (not strictly needed in this | ||||
| example): | ||||
|  | ||||
| _interoperability/bindgen/libbirthday_wrapper.h_: | ||||
|  | ||||
| ```c | ||||
| {{#include bindgen/libbirthday_wrapper.h:include}} | ||||
| ``` | ||||
|  | ||||
| You can now auto-generate the bindings: | ||||
|  | ||||
| _interoperability/bindgen/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include bindgen/Android.bp:libbirthday_bindgen}} | ||||
| ``` | ||||
|  | ||||
| Finally, we can use the bindings in our Rust program: | ||||
|  | ||||
| _interoperability/bindgen/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include bindgen/Android.bp:print_birthday_card}} | ||||
| ``` | ||||
|  | ||||
| _interoperability/bindgen/main.rs_: | ||||
|  | ||||
| ```rust,compile_fail | ||||
| {{#include bindgen/main.rs:main}} | ||||
| ``` | ||||
|  | ||||
| Build, push, and run the binary on your device: | ||||
|  | ||||
| ```shell | ||||
| {{#include ../../build_all.sh:print_birthday_card}} | ||||
| ``` | ||||
|  | ||||
| Finally, we can run auto-generated tests to ensure the bindings work: | ||||
|  | ||||
| _interoperability/bindgen/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include bindgen/Android.bp:libbirthday_bindgen_test}} | ||||
| ``` | ||||
|  | ||||
| ```shell | ||||
| {{#include ../../build_all.sh:libbirthday_bindgen_test}} | ||||
| ``` | ||||
							
								
								
									
										36
									
								
								src/android/interoperability/with-c/bindgen/Android.bp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/android/interoperability/with-c/bindgen/Android.bp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| // ANCHOR: libbirthday | ||||
| cc_library { | ||||
|     name: "libbirthday", | ||||
|     srcs: ["libbirthday.c"], | ||||
| } | ||||
| // ANCHOR_END: libbirthday | ||||
|  | ||||
| // ANCHOR: libbirthday_bindgen | ||||
| rust_bindgen { | ||||
|     name: "libbirthday_bindgen", | ||||
|     crate_name: "birthday_bindgen", | ||||
|     wrapper_src: "libbirthday_wrapper.h", | ||||
|     source_stem: "bindings", | ||||
|     static_libs: ["libbirthday"], | ||||
| } | ||||
| // ANCHOR_END: libbirthday_bindgen | ||||
|  | ||||
| // ANCHOR: libbirthday_bindgen_test | ||||
| 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", // Generated file, skip linting | ||||
|     lints: "none", | ||||
| } | ||||
| // ANCHOR_END: libbirthday_bindgen_test | ||||
|  | ||||
| // ANCHOR: print_birthday_card | ||||
| rust_binary { | ||||
|     name: "print_birthday_card", | ||||
|     srcs: ["main.rs"], | ||||
|     rustlibs: ["libbirthday_bindgen"], | ||||
| } | ||||
| // ANCHOR_END: print_birthday_card | ||||
							
								
								
									
										20
									
								
								src/android/interoperability/with-c/bindgen/c-library.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/android/interoperability/with-c/bindgen/c-library.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| # Create a C library | ||||
|  | ||||
| _interoperability/c/libbirthday/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include c/libbirthday/Android.bp:libbirthday}} | ||||
| ``` | ||||
|  | ||||
| _interoperability/c/libbirthday/libbirthday.h_: | ||||
|  | ||||
| ```c | ||||
| {{#include c/libbirthday/libbirthday.h}} | ||||
| ``` | ||||
|  | ||||
| _interoperability/c/libbirthday/libbirthday.c_: | ||||
|  | ||||
| ```c | ||||
| {{#include c/libbirthday/libbirthday.c}} | ||||
| ``` | ||||
|  | ||||
							
								
								
									
										26
									
								
								src/android/interoperability/with-c/bindgen/libbirthday.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/android/interoperability/with-c/bindgen/libbirthday.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| /* | ||||
|  * Copyright 2022 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. | ||||
|  */ | ||||
|  | ||||
| // ANCHOR: print_card | ||||
| #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"); | ||||
| } | ||||
							
								
								
									
										23
									
								
								src/android/interoperability/with-c/bindgen/libbirthday.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/android/interoperability/with-c/bindgen/libbirthday.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * Copyright 2022 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. | ||||
|  */ | ||||
|  | ||||
| // ANCHOR: card | ||||
| typedef struct card { | ||||
|   const char* name; | ||||
|   int years; | ||||
| } card; | ||||
|  | ||||
| void print_card(const card* card); | ||||
| @@ -0,0 +1,18 @@ | ||||
| /* | ||||
|  * Copyright 2022 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. | ||||
|  */ | ||||
|  | ||||
| // ANCHOR: include | ||||
| #include "libbirthday.h" | ||||
							
								
								
									
										29
									
								
								src/android/interoperability/with-c/bindgen/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/android/interoperability/with-c/bindgen/main.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: main | ||||
| //! Bindgen demo. | ||||
|  | ||||
| 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, | ||||
|     }; | ||||
|     unsafe { | ||||
|         print_card(&card as *const card); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								src/android/interoperability/with-c/calling-rust.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/android/interoperability/with-c/calling-rust.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| # Calling Rust from C | ||||
							
								
								
									
										21
									
								
								src/android/interoperability/with-c/hand-written.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/android/interoperability/with-c/hand-written.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| # Handwritten FFI | ||||
|  | ||||
| We can declare external functions by hand: | ||||
|  | ||||
| ```rust | ||||
| extern "C" { | ||||
|     fn abs(x: i32) -> i32; | ||||
| } | ||||
|  | ||||
| fn main() { | ||||
|     let x = -42; | ||||
|     let abs_x = unsafe { abs(x) }; | ||||
|     println!("{x}, {abs_x}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| We already saw this in the [Safe FFI Wrapper | ||||
| exercise](../../exercises/day-3/safe-ffi-wrapper.md). | ||||
|  | ||||
| > This assumes full knowledge of the target platform. Not recommended for | ||||
| > production. | ||||
							
								
								
									
										42
									
								
								src/android/interoperability/with-c/rust.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/android/interoperability/with-c/rust.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| # Calling Rust | ||||
|  | ||||
| Exporting Rust functions and types to C is easy: | ||||
|  | ||||
| _interoperability/rust/libanalyze/analyze.rs_ | ||||
|  | ||||
| ```rust,editable | ||||
| {{#include rust/libanalyze/analyze.rs:analyze_numbers}} | ||||
| ``` | ||||
|  | ||||
| _interoperability/rust/libanalyze/analyze.h_ | ||||
|  | ||||
| ```c | ||||
| {{#include rust/libanalyze/analyze.h:analyze_numbers}} | ||||
| ``` | ||||
|  | ||||
| _interoperability/rust/libanalyze/Android.bp_ | ||||
|  | ||||
| ```javascript | ||||
| {{#include rust/libanalyze/Android.bp}} | ||||
| ``` | ||||
|  | ||||
| We can now call this from a C binary: | ||||
|  | ||||
| _interoperability/rust/analyze/main.c_ | ||||
|  | ||||
| ```c | ||||
| {{#include rust/analyze/main.c:main}} | ||||
| ``` | ||||
|  | ||||
| _interoperability/rust/analyze/Android.bp_ | ||||
|  | ||||
| ```javascript | ||||
| {{#include rust/analyze/Android.bp}} | ||||
| ``` | ||||
|  | ||||
|  | ||||
| Build, push, and run the binary on your device: | ||||
|  | ||||
| ```shell | ||||
| {{#include ../../build_all.sh:analyze_numbers}} | ||||
| ``` | ||||
| @@ -0,0 +1,5 @@ | ||||
| cc_binary { | ||||
|     name: "analyze_numbers", | ||||
|     srcs: ["main.c"], | ||||
|     static_libs: ["libanalyze_ffi"], | ||||
| } | ||||
							
								
								
									
										24
									
								
								src/android/interoperability/with-c/rust/analyze/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/android/interoperability/with-c/rust/analyze/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| /* | ||||
|  * Copyright 2022 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. | ||||
|  */ | ||||
|  | ||||
| // ANCHOR: main | ||||
| #include "analyze.h" | ||||
|  | ||||
| int main() { | ||||
|   analyze_numbers(10, 20); | ||||
|   analyze_numbers(123, 123); | ||||
|   return 0; | ||||
| } | ||||
| @@ -0,0 +1,6 @@ | ||||
| rust_ffi { | ||||
|     name: "libanalyze_ffi", | ||||
|     crate_name: "analyze_ffi", | ||||
|     srcs: ["analyze.rs"], | ||||
|     include_dirs: ["."], | ||||
| } | ||||
| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * Copyright 2022 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. | ||||
|  */ | ||||
|  | ||||
| // ANCHOR: analyze_numbers | ||||
| #ifndef ANALYSE_H | ||||
| #define ANALYSE_H | ||||
|  | ||||
| extern "C" { | ||||
| void analyze_numbers(int x, int y); | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -0,0 +1,29 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: analyze_numbers | ||||
| //! Rust FFI demo. | ||||
| #![deny(improper_ctypes_definitions)] | ||||
|  | ||||
| use std::os::raw::c_int; | ||||
|  | ||||
| /// Analyze the numbers. | ||||
| #[no_mangle] | ||||
| pub extern "C" fn analyze_numbers(x: c_int, y: c_int) { | ||||
|     if x < y { | ||||
|         println!("x ({x}) is smallest!"); | ||||
|     } else { | ||||
|         println!("y ({y}) is probably larger than x ({x})"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										31
									
								
								src/android/logging.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/android/logging.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| # Logging | ||||
|  | ||||
| You should use the `log` crate to automatically log to `logcat` (on-device) or | ||||
| `stdout` (on-host): | ||||
|  | ||||
| _hello_rust_logs/Android.bp_: | ||||
|  | ||||
| ```javascript | ||||
| {{#include logging/Android.bp}} | ||||
| ``` | ||||
|  | ||||
| _hello_rust_logs/src/main.rs_: | ||||
|  | ||||
| ```rust,ignore | ||||
| {{#include logging/src/main.rs:main}} | ||||
| ``` | ||||
|  | ||||
| Build, push, and run the binary on your device: | ||||
|  | ||||
| ```shell | ||||
| {{#include build_all.sh:hello_rust_logs}} | ||||
| ``` | ||||
|  | ||||
| The logs show up in `adb logcat`: | ||||
|  | ||||
| ```shell | ||||
| $ 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! | ||||
| ``` | ||||
							
								
								
									
										11
									
								
								src/android/logging/Android.bp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/android/logging/Android.bp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| rust_binary { | ||||
|     name: "hello_rust_logs", | ||||
|     crate_name: "hello_rust_logs", | ||||
|     srcs: ["src/main.rs"], | ||||
|     rustlibs: [ | ||||
|         "liblog_rust", | ||||
|         "liblogger", | ||||
|     ], | ||||
|     prefer_rlib: true, | ||||
|     host_supported: true, | ||||
| } | ||||
							
								
								
									
										29
									
								
								src/android/logging/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/android/logging/src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| // ANCHOR: main | ||||
| //! Rust logging demo. | ||||
|  | ||||
| use log::{debug, error}; | ||||
|  | ||||
| /// Logs a greeting. | ||||
| fn main() { | ||||
|     logger::init( | ||||
|         logger::Config::default() | ||||
|             .with_tag_on_device("rust") | ||||
|             .with_min_level(log::Level::Trace), | ||||
|     ); | ||||
|     debug!("Starting program."); | ||||
|     error!("Something went wrong!"); | ||||
| } | ||||
							
								
								
									
										13
									
								
								src/android/setup.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/android/setup.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| # Setup | ||||
|  | ||||
| We will be using an Android Virtual Device to test our code. Make sure you have | ||||
| access to one or create a new one with: | ||||
|  | ||||
| ```shell | ||||
| $ source build/envsetup.sh | ||||
| $ lunch aosp_cf_x86_64_phone-userdebug | ||||
| $ acloud create | ||||
| ``` | ||||
|  | ||||
| Please see the [Android Developer | ||||
| Codelab](https://source.android.com/docs/setup/start) for details. | ||||
							
								
								
									
										9
									
								
								src/basic-syntax.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/basic-syntax.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| # Basic Syntax | ||||
|  | ||||
| Much of the Rust syntax will be familiar to you from C or C++: | ||||
|  | ||||
| * Blocks and scopes are delimited by curly braces. | ||||
| * Line comments are started with `//`, block comments are delimited by `/* ... | ||||
|   */`. | ||||
| * Keywords like `if` and `while` work the same. | ||||
| * Variable assigment is done with `=`, comparison is done with `==`. | ||||
							
								
								
									
										26
									
								
								src/basic-syntax/compound-types.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/basic-syntax/compound-types.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| # Compound Types | ||||
|  | ||||
| |        | Types               | Literals                 | | ||||
| |--------|---------------------|--------------------------| | ||||
| | Arrays | `[T; N]`            | `[20, 30, 40]`, `[0; 3]` | | ||||
| | Tuples | `(T1, T2, T3, ...)` | `('x', 1.2, 0)`          | | ||||
|  | ||||
| Array assignment and access: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let mut a: [i8; 10] = [42; 10]; | ||||
|     a[5] = 0; | ||||
|     println!("a: {:?}", a); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Tuple assignment and access: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let t: (i8, bool) = (7, true); | ||||
|     println!("1st index: {}", t.0); | ||||
|     println!("2nd index: {}", t.1); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										23
									
								
								src/basic-syntax/functions-interlude.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/basic-syntax/functions-interlude.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # Function Overloading | ||||
|  | ||||
| Overloading is not supported: | ||||
|  | ||||
| * Each function has a single implementation: | ||||
|   * Always takes a fixed number of parameters. | ||||
|   * Always takes a single set of parameter types. | ||||
| * Default values are not supported: | ||||
|   * All call sites have the same number of arguments. | ||||
|   * Macros are sometimes used as an alternative. | ||||
|  | ||||
| However, function parameters can be generic: | ||||
|  | ||||
| ```rust,editable | ||||
| fn pick_one<T>(a: T, b: T) -> T { | ||||
|     if std::process::id() % 2 == 0 { a } else { b } | ||||
| } | ||||
|  | ||||
| fn main() { | ||||
|     println!("coin toss: {}", pick_one("heads", "tails")); | ||||
|     println!("cash prize: {}", pick_one(500, 1000)); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										31
									
								
								src/basic-syntax/functions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/basic-syntax/functions.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| # Functions | ||||
|  | ||||
| A Rust version of the famous FizzBuzz interview question: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     fizzbuzz_to(20);   // Defined below, no forward declaration needed | ||||
| } | ||||
|  | ||||
| fn is_divisible_by(lhs: u32, rhs: u32) -> bool { | ||||
|     if rhs == 0 { | ||||
|         return false;  // Corner case, early return | ||||
|     } | ||||
|     lhs % rhs == 0     // The last expression is the return value | ||||
| } | ||||
|  | ||||
| fn fizzbuzz(n: u32) -> () {  // No return value means returning the unit type `()` | ||||
|     match (is_divisible_by(n, 3), is_divisible_by(n, 5)) { | ||||
|         (true,  true)  => println!("fizzbuzz"), | ||||
|         (true,  false) => println!("fizz"), | ||||
|         (false, true)  => println!("buzz"), | ||||
|         (false, false) => println!("{n}"), | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn fizzbuzz_to(n: u32) {  // `-> ()` is normally omitted | ||||
|     for n in 1..=n { | ||||
|         fizzbuzz(n); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										30
									
								
								src/basic-syntax/methods.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/basic-syntax/methods.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| # Methods | ||||
|  | ||||
| Rust has methods, they are simply functions that are associated with a particular type. The | ||||
| first argument of a method is an instance of the type it is associated with: | ||||
|  | ||||
| ```rust,editable | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
| } | ||||
|  | ||||
| impl Rectangle { | ||||
|     fn area(&self) -> u32 { | ||||
|         self.width * self.height | ||||
|     } | ||||
|  | ||||
|     fn inc_width(&mut self, delta: u32) { | ||||
|         self.width += delta; | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn main() { | ||||
|     let mut rect = Rectangle { width: 10, height: 5 }; | ||||
|     println!("old area: {}", rect.area()); | ||||
|     rect.inc_width(5); | ||||
|     println!("new area: {}", rect.area()); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| * We will look much more at methods in today's exercise and in tomorrow's class. | ||||
							
								
								
									
										19
									
								
								src/basic-syntax/references-dangling.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/basic-syntax/references-dangling.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # Dangling References | ||||
|  | ||||
| Rust will statically forbid dangling references: | ||||
|  | ||||
| ```rust,editable,compile_fail | ||||
| fn main() { | ||||
|     let ref_x: &i32; | ||||
|     { | ||||
|         let x: i32 = 10; | ||||
|         ref_x = &x; | ||||
|     } | ||||
|     println!("ref_x: {ref_x}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| * A reference is said to "borrow" the value is refers to. | ||||
| * Rust is tracking the lifetimes of all references to ensure they live long | ||||
|   enough. | ||||
| * We will talk more about borrowing when we get to ownership. | ||||
							
								
								
									
										18
									
								
								src/basic-syntax/references.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/basic-syntax/references.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| # References | ||||
|  | ||||
| Like C++, Rust has references: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let mut x: i32 = 10; | ||||
|     let ref_x: &mut i32 = &mut x; | ||||
|     *ref_x = 20; | ||||
|     println!("x: {x}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Some differences from C++: | ||||
|  | ||||
| * We must dereference `ref_x` when assigning to it, similar to C pointers, | ||||
| * Rust will auto-dereference in some cases, in particular when invoking | ||||
|   methods (try `count_ones`). | ||||
							
								
								
									
										18
									
								
								src/basic-syntax/scalar-types.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/basic-syntax/scalar-types.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| # Scalar Types | ||||
|  | ||||
| |                        | Types                                      | Literals                      | | ||||
| |------------------------|--------------------------------------------|-------------------------------| | ||||
| | Signed integers        | `i8`, `i16`, `i32`, `i64`, `i128`, `isize` | `-10`, `0`, `1_000`, `123i64` | | ||||
| | Unsigned integers      | `u8`, `u16`, `u32`, `u64`, `u128`, `usize` | `0`, `123`, `10u16`           | | ||||
| | Floating point numbers | `f32`, `f64`                               | `3.14`, `-10.0e20`, `2f32`    | | ||||
| | Strings                | `&str`                                     | `"foo"`, `r#"\\"#`            | | ||||
| | Unicode scalar values  | `char`                                     | `'a'`, `'α'`, `'∞'`           | | ||||
| | Byte strings           | `&[u8]`                                    | `b"abc"`, `br#" " "#`           | | ||||
| | Booleans               | `bool`                                     | `true`, `false`               | | ||||
|  | ||||
| The types have widths as follows: | ||||
|  | ||||
| * `iN`, `uN`, and `fN` are _n_ bits wide, | ||||
| * `isize` and `usize` are the width of a pointer, | ||||
| * `char` is 32 bit wide, | ||||
| * `bool` is 8 bit wide. | ||||
							
								
								
									
										21
									
								
								src/basic-syntax/scopes-shadowing.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/basic-syntax/scopes-shadowing.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| # Scopes and Shadowing | ||||
|  | ||||
| You can shadow variables, both those from outer scopes and variables from the | ||||
| same scope: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let a = 10; | ||||
|     println!("before: {a}"); | ||||
|  | ||||
|     { | ||||
|         let a = "hello"; | ||||
|         println!("inner scope: {a}"); | ||||
|  | ||||
|         let a = true; | ||||
|         println!("shadowed in inner scope: {a}"); | ||||
|     } | ||||
|  | ||||
|     println!("after: {a}"); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										16
									
								
								src/basic-syntax/slices.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/basic-syntax/slices.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| # Slices | ||||
|  | ||||
| A slice gives you a view into a larger collection: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let a: [i32; 6] = [10, 20, 30, 40, 50, 60]; | ||||
|     println!("a: {a:?}"); | ||||
|  | ||||
|     let s: &[i32] = &a[2..4]; | ||||
|     println!("s: {s:?}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| * Slices borrow data from the sliced type. | ||||
| * Question: What happens if you modify `a[3]`? | ||||
							
								
								
									
										39
									
								
								src/basic-syntax/static-and-const.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/basic-syntax/static-and-const.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| # Static and Constant Variables | ||||
|  | ||||
| Global state is managed with static and constant variables | ||||
|  | ||||
| ## `const` | ||||
|  | ||||
| You can declare compile-time constants: | ||||
|  | ||||
| ```rust,editable | ||||
| const DIGEST_SIZE: usize = 3; | ||||
| const ZERO: Option<u8> = Some(42); | ||||
|  | ||||
| fn compute_digest(text: &str) -> [u8; DIGEST_SIZE] { | ||||
|     let mut digest = [ZERO.unwrap_or(0); DIGEST_SIZE]; | ||||
|     for (idx, &b) in text.as_bytes().iter().enumerate() { | ||||
|         digest[idx % DIGEST_SIZE] = digest[idx % DIGEST_SIZE].wrapping_add(b); | ||||
|     } | ||||
|     digest | ||||
| } | ||||
|  | ||||
| fn main() { | ||||
|     let digest = compute_digest("Hello"); | ||||
|     println!("Digest: {digest:?}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ## `static` | ||||
|  | ||||
| You can also declare static variables: | ||||
|  | ||||
| ```rust,editable | ||||
| static BANNER: &str = "Welcome to RustOS 3.14"; | ||||
|  | ||||
| fn main() { | ||||
|     println!("{BANNER}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| We will look at mutating static data in the chapter on Unsafe Rust. | ||||
							
								
								
									
										20
									
								
								src/basic-syntax/string-slices.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/basic-syntax/string-slices.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| # `String` vs `str` | ||||
|  | ||||
| We can now understand the two string types in Rust: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let s1: &str = "Hello"; | ||||
|     println!("s1: {s1}"); | ||||
|  | ||||
|     let mut s2: String = String::from("Hello "); | ||||
|     println!("s2: {s2}"); | ||||
|     s2.push_str(s1); | ||||
|     println!("s2: {s2}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Rust terminology: | ||||
|  | ||||
| * `&str` an immutable reference to a string slice. | ||||
| * `String` a mutable string buffer | ||||
							
								
								
									
										22
									
								
								src/basic-syntax/type-inference.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/basic-syntax/type-inference.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| # Type Inference | ||||
|  | ||||
| Rust will look at how the variable is _used_ to determine the type: | ||||
|  | ||||
| ```rust,editable | ||||
| fn takes_u32(x: u32) { | ||||
|     println!("u32: {x}"); | ||||
| } | ||||
|  | ||||
| fn takes_i8(y: i8) { | ||||
|     println!("i8: {y}"); | ||||
| } | ||||
|  | ||||
| fn main() { | ||||
|     let x = 10; | ||||
|     let y = 20; | ||||
|  | ||||
|     takes_u32(x); | ||||
|     takes_i8(y); | ||||
|     // takes_u32(y); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										13
									
								
								src/basic-syntax/variables.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/basic-syntax/variables.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| # Variables | ||||
|  | ||||
| Rust provides type safety via static typing. Variable bindings are immutable by | ||||
| default: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let x: i32 = 10; | ||||
|     println!("x: {x}"); | ||||
|     // x = 20; | ||||
|     // println!("x: {x}"); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										18
									
								
								src/cargo.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/cargo.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| # Using Cargo | ||||
|  | ||||
| When you start reading about Rust, you will soon meet Cargo, the standard tool | ||||
| used in the Rust ecosystem to build and run Rust applications. Here we want to | ||||
| give a brief overview of what Cargo is and how it fits into the wider ecosystem | ||||
| and how it fits into this training. | ||||
|  | ||||
| On Debian/Ubuntu, you can install Cargo and the Rust source with | ||||
|  | ||||
| ```shell | ||||
| $ sudo apt install cargo rust-src | ||||
| ``` | ||||
|  | ||||
| This will allow [rust-analyzer][1] to jump to the definitions. We suggest using | ||||
| [VS Code][2] to edit the code (but any LSP compatible editor works). | ||||
|  | ||||
| [1]: https://rust-analyzer.github.io/ | ||||
| [2]: https://code.visualstudio.com/ | ||||
							
								
								
									
										20
									
								
								src/cargo/code-samples.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/cargo/code-samples.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| # Code Samples in This Training | ||||
|  | ||||
| For this training, we will mostly explore the Rust language through examples | ||||
| which can be executed through your browser. This makes the setup much easier and | ||||
| ensures a consistent experience for everyone. | ||||
|  | ||||
| Installing Cargo is still encouraged: it will make it easier for you to do the | ||||
| exercises. On the last day, we will do a larger exercise which shows you how to | ||||
| work with dependencies and for that you need Cargo. | ||||
|  | ||||
| The code blocks in this course are fully interactive: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     println!("Edit me!"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| You can use <kbd>Ctrl-Enter</kbd> to execute the code when focus is in the text | ||||
| box. | ||||
							
								
								
									
										66
									
								
								src/cargo/running-locally.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/cargo/running-locally.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| # Running Code Locally with Cargo | ||||
|  | ||||
| If you want to experiment with the code on your own system, then you will need | ||||
| to first install Rust. Do this by following the [instructions in the Rust | ||||
| Book][1]. This should give you a working `rustc` and `cargo`. At the time of | ||||
| writing, the latest stable Rust release has these version numbers: | ||||
|  | ||||
| ```shell | ||||
| % rustc --version | ||||
| rustc 1.61.0 (fe5b13d68 2022-05-18) | ||||
| % cargo --version | ||||
| cargo 1.61.0 (a028ae4 2022-04-29) | ||||
| ``` | ||||
|  | ||||
| With this is in place, then follow these steps to build a Rust binary from one | ||||
| of the examples in this training: | ||||
|  | ||||
| 1. Click the "Copy to clipboard" button on the example you want to copy. | ||||
|  | ||||
| 2. Use `cargo new exercise` to create a new `exercise/` directory for your code: | ||||
|  | ||||
|     ```shell | ||||
|     $ cargo new exercise | ||||
|          Created binary (application) `exercise` package | ||||
|     ``` | ||||
|  | ||||
| 3. Navigate into `exercise/` and use `cargo run` to build and run your binary: | ||||
|  | ||||
|     ```shell | ||||
|     $ 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! | ||||
|     ``` | ||||
|  | ||||
| 4. Replace the boiler-plate code in `src/main.rs` with your own code. For | ||||
|    example, using the example on the previous page, make `src/main.rs` look like | ||||
|  | ||||
|     ```rust | ||||
|     fn main() { | ||||
|         println!("Edit me!"); | ||||
|     } | ||||
|     ``` | ||||
|  | ||||
| 5. Use `cargo run` to build and run your updated binary: | ||||
|  | ||||
|     ```shell | ||||
|     $ 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! | ||||
|     ``` | ||||
|  | ||||
| 6. Use `cargo check` to quickly check your project for errors, use `cargo build` | ||||
|    to compile it without running it. You will find the output in `target/debug/` | ||||
|    for a normal debug build. Use `cargo build --release` to produce an optimized | ||||
|    release build in `target/release/`. | ||||
|  | ||||
| 7. You can add dependencies for your project by editing `Cargo.toml`. When you | ||||
|    run `cargo` commands, it will automatically download and compile missing | ||||
|    dependencies for you. | ||||
|  | ||||
| [1]: https://doc.rust-lang.org/book/ch01-01-installation.html | ||||
							
								
								
									
										17
									
								
								src/cargo/rust-ecosystem.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/cargo/rust-ecosystem.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| # The Rust Ecosystem | ||||
|  | ||||
| The Rust ecosystem consists of a number of tools, of which the main ones are: | ||||
|  | ||||
| * `rustc`: the Rust compiler which turn `.rs` files into binaries and other | ||||
|   intermediate formats. | ||||
|  | ||||
| * `cargo`: the Rust dependency manager and build tool. Cargo knows how to | ||||
|   download dependencies hosted on <https://crates.io> and it will pass them to | ||||
|   `rustc` 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 update `rustc` and `cargo` when new versions of Rust is released. | ||||
|   In addition, `rustup` can also download documentation for the standard | ||||
|   library. You can have multiple versions of Rust installed at once and `rustup` | ||||
|   will let you switch between them as needed. | ||||
							
								
								
									
										8
									
								
								src/concurrency.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/concurrency.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| # Fearless Concurrency | ||||
|  | ||||
| Rust has full support for concurrency using OS threads with mutexes and | ||||
| channels. | ||||
|  | ||||
| The Rust type system plays an important role in making many concurrency bugs | ||||
| compile time bugs. This is often referred to a _fearless concurrency_ since you | ||||
| can rely on the compiler to ensure correctness at runtime. | ||||
							
								
								
									
										23
									
								
								src/concurrency/channels.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/concurrency/channels.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # Channels | ||||
|  | ||||
| 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. | ||||
|  | ||||
| ```rust,editable | ||||
| use std::sync::mpsc; | ||||
| use std::thread; | ||||
|  | ||||
| fn main() { | ||||
|     let (tx, rx) = mpsc::channel(); | ||||
|  | ||||
|     tx.send(10).unwrap(); | ||||
|     tx.send(20).unwrap(); | ||||
|  | ||||
|     println!("Received: {:?}", rx.recv()); | ||||
|     println!("Received: {:?}", rx.recv()); | ||||
|  | ||||
|     let tx2 = tx.clone(); | ||||
|     tx2.send(30).unwrap(); | ||||
|     println!("Received: {:?}", rx.recv()); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										27
									
								
								src/concurrency/channels/bounded.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/concurrency/channels/bounded.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| # Bounded Channels | ||||
|  | ||||
| Bounded and synchronous channels make `send` block the current thread: | ||||
|  | ||||
| ```rust,editable | ||||
| use std::sync::mpsc; | ||||
| use std::thread; | ||||
| use std::time::Duration; | ||||
|  | ||||
| fn main() { | ||||
|     let (tx, rx) = mpsc::sync_channel(3); | ||||
|  | ||||
|     thread::spawn(move || { | ||||
|         let thread_id = thread::current().id(); | ||||
|         for i in 1..10 { | ||||
|             tx.send(format!("Message {i}")).unwrap(); | ||||
|             println!("{thread_id:?}: sent Message {i}"); | ||||
|         } | ||||
|         println!("{thread_id:?}: done"); | ||||
|     }); | ||||
|     thread::sleep(Duration::from_millis(100)); | ||||
|  | ||||
|     for msg in rx.iter() { | ||||
|         println!("Main: got {}", msg); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										27
									
								
								src/concurrency/channels/unbounded.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/concurrency/channels/unbounded.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| # Unbounded Channels | ||||
|  | ||||
| You get an unbounded and asynchronous channel with `mpsc::channel()`: | ||||
|  | ||||
| ```rust,editable | ||||
| use std::sync::mpsc; | ||||
| use std::thread; | ||||
| use std::time::Duration; | ||||
|  | ||||
| fn main() { | ||||
|     let (tx, rx) = mpsc::channel(); | ||||
|  | ||||
|     thread::spawn(move || { | ||||
|         let thread_id = thread::current().id(); | ||||
|         for i in 1..10 { | ||||
|             tx.send(format!("Message {i}")).unwrap(); | ||||
|             println!("{thread_id:?}: sent Message {i}"); | ||||
|         } | ||||
|         println!("{thread_id:?}: done"); | ||||
|     }); | ||||
|     thread::sleep(Duration::from_millis(100)); | ||||
|  | ||||
|     for msg in rx.iter() { | ||||
|         println!("Main: got {}", msg); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										33
									
								
								src/concurrency/scoped-threads.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/concurrency/scoped-threads.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| # Scoped Threads | ||||
|  | ||||
| Normal threads cannot borrow from their environment: | ||||
|  | ||||
| ```rust,editable,compile_fail | ||||
| use std::thread; | ||||
|  | ||||
| fn main() { | ||||
|     let s = String::from("Hello"); | ||||
|  | ||||
|     thread::spawn(|| { | ||||
|         println!("Length: {}", s.len()); | ||||
|     }); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| However, you can use a [scoped thread][1] for this: | ||||
|  | ||||
| ```rust,editable | ||||
| use std::thread; | ||||
|  | ||||
| fn main() { | ||||
|     let s = String::from("Hello"); | ||||
|  | ||||
|     thread::scope(|scope| { | ||||
|         scope.spawn(|| { | ||||
|             println!("Length: {}", s.len()); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| [1]: https://doc.rust-lang.org/std/thread/fn.scope.html | ||||
							
								
								
									
										11
									
								
								src/concurrency/send-sync.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/concurrency/send-sync.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| # `Send` and `Sync` | ||||
|  | ||||
| How does Rust know to forbid shared access across thread? The answer is in two traits: | ||||
|  | ||||
| * [`Send`][1]: a type `T` is `Send` if it is safe to move a `T` across a thread | ||||
|   boundary. | ||||
| * [`Sync`][2]: a type `T` is `Sync` if it is safe to move a `&T` across a thread | ||||
|   boundary. | ||||
|  | ||||
| [1]: https://doc.rust-lang.org/std/marker/trait.Send.html | ||||
| [2]: https://doc.rust-lang.org/std/marker/trait.Sync.html | ||||
							
								
								
									
										41
									
								
								src/concurrency/send-sync/examples.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/concurrency/send-sync/examples.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| # Examples | ||||
|  | ||||
| ## `Send + Sync` | ||||
|  | ||||
| Most types you come across are `Send + Sync`: | ||||
|  | ||||
| * `i8`, `f32`, `bool`, `char`, `&str`, ... | ||||
| * `(T1, T2)`, `[T; N]`, `&[T]`, `struct { x: T }`, ... | ||||
| * `String`, `Option<T>`, `Vec<T>`, `Box<T>`, ... | ||||
| * `Arc<T>`: Explicitly thread-safe via atomic reference count. | ||||
| * `Mutex<T>`: Explicitly thread-safe via internal locking. | ||||
| * `AtomicBool`, `AtomicU8`, ...: Uses special atomic instructions. | ||||
|  | ||||
| The generic types are typically `Send + Sync` when the type parameters are | ||||
| `Send + Sync`. | ||||
|  | ||||
| ## `Send + !Sync` | ||||
|  | ||||
| These types can be moved to other threads, but they're not thread-safe. | ||||
| Typically because of interior mutability: | ||||
|  | ||||
| * `mpsc::Sender<T>` | ||||
| * `mpsc::Receiver<T>` | ||||
| * `Cell<T>` | ||||
| * `RefCell<T>` | ||||
|  | ||||
| ## `!Send + Sync` | ||||
|  | ||||
| These types are thread-safe, but they cannot be moved to another thread: | ||||
|  | ||||
| * `MutexGuard<T>`: Uses OS level primitives which must be deallocated on the | ||||
|   thread which created them. | ||||
|  | ||||
| ## `!Send + !Sync` | ||||
|  | ||||
| These types are not thread-safe and cannot be moved to other threads: | ||||
|  | ||||
| * `Rc<T>`: each `Rc<T>` has a reference to an `RcBox<T>`, which contains a | ||||
|   non-atomic reference count. | ||||
| * `*const T`, `*mut T`: Rust that there are special lifetime considerations for the | ||||
|   pointer. | ||||
							
								
								
									
										9
									
								
								src/concurrency/send-sync/send.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/concurrency/send-sync/send.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| # `Send` | ||||
|  | ||||
| > A type `T` is [`Send`][1] if it is safe to move a `T` value to another thread. | ||||
|  | ||||
| The effect of moving ownership to another thread is that _destructors_ will run | ||||
| in that thread. So the question is when you can allocate a value in one thread | ||||
| and deallocate it in another. | ||||
|  | ||||
| [1]: https://doc.rust-lang.org/std/marker/trait.Send.html | ||||
							
								
								
									
										10
									
								
								src/concurrency/send-sync/sync.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/concurrency/send-sync/sync.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| # `Sync` | ||||
|  | ||||
| > A type `T` is [`Sync`][1] if it is safe to access a `T` value from multiple | ||||
| > threads at the same time. | ||||
|  | ||||
| More precisely, the definitions is | ||||
|  | ||||
| > `T` is `Sync` if and only if `&T` is `Send` | ||||
|  | ||||
| [1]: https://doc.rust-lang.org/std/marker/trait.Sync.html | ||||
							
								
								
									
										11
									
								
								src/concurrency/shared_state.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/concurrency/shared_state.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| # Shared State | ||||
|  | ||||
| Rust uses the type system to enforce synchronization of shared data. This is | ||||
| primarily done via two types: | ||||
|  | ||||
| * [`Arc<T>`][1], atomic reference counted `T`: handled sharing between threads and | ||||
|   takes care to deallocate `T` when the last thread exists, | ||||
| * [`Mutex<T>`][2]: ensures mutual exclusion for to the `T` value. | ||||
|  | ||||
| [1]: https://doc.rust-lang.org/std/sync/struct.Arc.html | ||||
| [2]: https://doc.rust-lang.org/std/sync/struct.Mutex.html | ||||
							
								
								
									
										25
									
								
								src/concurrency/shared_state/arc.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/concurrency/shared_state/arc.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| # `Arc` | ||||
|  | ||||
| [`Arc<T>`][1] allows shared read-only access via its `clone` method: | ||||
|  | ||||
| ```rust,editable | ||||
| use std::thread; | ||||
| use std::sync::Arc; | ||||
|  | ||||
| fn main() { | ||||
|     let v = Arc::new(vec![10, 20, 30]); | ||||
|     let mut handles = Vec::new(); | ||||
|     for _ in 1..5 { | ||||
|         let v = v.clone(); | ||||
|         handles.push(thread::spawn(move || { | ||||
|             let thread_id = thread::current().id(); | ||||
|             println!("{thread_id:?}: {v:?}"); | ||||
|         })); | ||||
|     } | ||||
|  | ||||
|     handles.into_iter().for_each(|h| h.join().unwrap()); | ||||
|     println!("v: {v:?}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| [1]: https://doc.rust-lang.org/std/sync/struct.Arc.html | ||||
							
								
								
									
										19
									
								
								src/concurrency/shared_state/example.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/concurrency/shared_state/example.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # Example | ||||
|  | ||||
| Let us see `Arc` and `Mutex` in action: | ||||
|  | ||||
| ```rust,editable,compile_fail | ||||
| use std::thread; | ||||
| // use std::sync::{Arc, Mutex}; | ||||
|  | ||||
| fn main() { | ||||
|     let mut v = vec![10, 20, 30]; | ||||
|     let handle = thread::spawn(|| { | ||||
|         v.push(10); | ||||
|     }); | ||||
|     v.push(1000); | ||||
|  | ||||
|     handle.join().unwrap(); | ||||
|     println!("v: {v:?}"); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										28
									
								
								src/concurrency/shared_state/mutex.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/concurrency/shared_state/mutex.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| # `Mutex` | ||||
|  | ||||
| [`Mutex<T>`][1] ensures mutual exclusion _and_ allows mutable access to `T` | ||||
| behind a read-only interface: | ||||
|  | ||||
| ```rust,editable | ||||
| use std::sync::Mutex; | ||||
|  | ||||
| fn main() { | ||||
|     let v: Mutex<Vec<i32>> = Mutex::new(vec![10, 20, 30]); | ||||
|     println!("v: {:?}", v.lock().unwrap()); | ||||
|  | ||||
|     { | ||||
|         let v: &Mutex<Vec<i32>> = &v; | ||||
|         let mut guard = v.lock().unwrap(); | ||||
|         guard.push(40); | ||||
|     } | ||||
|  | ||||
|     println!("v: {:?}", v.lock().unwrap()); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Notice how we have a [`impl<T: Send> Sync for Mutex<T>`][2] blanket | ||||
| implementation. | ||||
|  | ||||
| [1]: https://doc.rust-lang.org/std/sync/struct.Mutex.html | ||||
| [2]: https://doc.rust-lang.org/std/sync/struct.Mutex.html#impl-Sync-for-Mutex%3CT%3E | ||||
| [3]: https://doc.rust-lang.org/std/sync/struct.Arc.html | ||||
							
								
								
									
										26
									
								
								src/concurrency/threads.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/concurrency/threads.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| # Threads | ||||
|  | ||||
| Rust threads work similarly to threads in other languages: | ||||
|  | ||||
| ```rust,editable | ||||
| use std::thread; | ||||
| use std::time::Duration; | ||||
|  | ||||
| fn main() { | ||||
|     thread::spawn(|| { | ||||
|         for i in 1..10 { | ||||
|             println!("Count in thread: {i}!"); | ||||
|             thread::sleep(Duration::from_millis(5)); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     for i in 1..5 { | ||||
|         println!("Main thread: {i}"); | ||||
|         thread::sleep(Duration::from_millis(5)); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| * Threads are all daemon threads, the main thread does not wait for them. | ||||
| * Thread panics are independent of each other. | ||||
|   * Panics can carry a payload, which can be unpacked with `downcast_ref`. | ||||
							
								
								
									
										6
									
								
								src/control-flow.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/control-flow.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| # Control Flow | ||||
|  | ||||
| As we have seen, `if` is an expression in Rust. It is used to conditionally | ||||
| evaluate one of two blocks, but the blocks can have a value which then becomes | ||||
| the value of the `if` expression. Other control flow expressions work similarly | ||||
| in Rust. | ||||
							
								
								
									
										36
									
								
								src/control-flow/blocks.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/control-flow/blocks.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| # Blocks | ||||
|  | ||||
| A block in Rust has a value and a type: the value is the last expression of the | ||||
| block: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let x = { | ||||
|         let y = 10; | ||||
|         println!("y: {y}"); | ||||
|         let z = { | ||||
|             let w = { | ||||
|                 3 + 4 | ||||
|             }; | ||||
|             println!("w: {w}"); | ||||
|             y * w | ||||
|         }; | ||||
|         println!("z: {z}"); | ||||
|         z - y | ||||
|     }; | ||||
|     println!("x: {x}"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The same rule is used for functions: the value of the function body is the | ||||
| return value: | ||||
|  | ||||
| ```rust,editable | ||||
| fn double(x: i32) -> i32 { | ||||
|     x + x | ||||
| } | ||||
|  | ||||
| fn main() { | ||||
|     println!("doubled: {}", double(7)); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										25
									
								
								src/control-flow/break-continue.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/control-flow/break-continue.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| # `break` and `continue` | ||||
|  | ||||
| If you want to exit a loop early, use `break`, if you want to immediately start | ||||
| the next iteration use `continue`. Both `continue` and `break` can optionally | ||||
| take a label argument which is used to break out of nested loops: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let v = vec![10, 20, 30]; | ||||
|     let mut iter = v.into_iter(); | ||||
|     'outer: while let Some(x) = iter.next() { | ||||
|         println!("x: {x}"); | ||||
|         let mut i = 0; | ||||
|         while i < x { | ||||
|             println!("x: {x}, i: {i}"); | ||||
|             i += 1; | ||||
|             if i == 3 { | ||||
|                 break 'outer; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| In this case we break the outer loop after 3 iterations of the inner loop. | ||||
							
								
								
									
										16
									
								
								src/control-flow/for-expressions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/control-flow/for-expressions.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| # `for` expressions | ||||
|  | ||||
| The `for` expression is closely related to the `while let` expression. It will | ||||
| automatically call `into_iter()` on the expression and then iterate over it: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let v = vec![10, 20, 30]; | ||||
|  | ||||
|     for x in v { | ||||
|         println!("x: {x}"); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| You can use `break` and `continue` here as usual. | ||||
							
								
								
									
										27
									
								
								src/control-flow/if-expressions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/control-flow/if-expressions.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| # `if` expressions | ||||
|  | ||||
| You use `if` very similarly to how you would in other languages: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let mut x = 10; | ||||
|     if x % 2 == 0 { | ||||
|         x = x / 2; | ||||
|     } else { | ||||
|         x = 3 * x + 1; | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| In addition, you can use it as an expression. This does the same as above: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let mut x = 10; | ||||
|     x = if x % 2 == 0 { | ||||
|         x / 2 | ||||
|     } else { | ||||
|         3 * x + 1 | ||||
|     }; | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										17
									
								
								src/control-flow/if-let-expressions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/control-flow/if-let-expressions.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| # `if let` expressions | ||||
|  | ||||
| If you want to match a value against a pattern, you can use `if let`: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let arg = std::env::args().next(); | ||||
|     if let Some(value) = arg { | ||||
|         println!("Program name: {value}"); | ||||
|     } else { | ||||
|         println!("Missing name?"); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| See [pattern matching](../pattern-matching.md) for more details on patterns in | ||||
| Rust. | ||||
							
								
								
									
										21
									
								
								src/control-flow/loop-expressions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/control-flow/loop-expressions.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| # `loop` expressions | ||||
|  | ||||
| Finally, there is a `loop` keyword which creates an endless loop. Here you must | ||||
| either `break` or `return` to stop the loop: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     let mut x = 10; | ||||
|     loop { | ||||
|         x = if x % 2 == 0 { | ||||
|             x / 2 | ||||
|         } else { | ||||
|             3 * x + 1 | ||||
|         }; | ||||
|         if x == 1 { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     println!("Final x: {x}"); | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										23
									
								
								src/control-flow/match-expressions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/control-flow/match-expressions.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # `match` expressions | ||||
|  | ||||
| The `match` keyword is used to match a value against one or more patterns. In | ||||
| that sense, it works like a series of `if let` expressions: | ||||
|  | ||||
| ```rust,editable | ||||
| fn main() { | ||||
|     match std::env::args().next().as_deref() { | ||||
|         Some("cat") => println!("Will do cat things"), | ||||
|         Some("ls")  => println!("Will ls some files"), | ||||
|         Some("mv")  => println!("Let's move some files"), | ||||
|         Some("rm")  => println!("Uh, dangerous!"), | ||||
|         None        => println!("Hmm, no program name?"), | ||||
|         _           => println!("Unknown program name!"), | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Like `if let`, each match arm must have the same type. The type is the last | ||||
| expression of the block, if any. In the example above, the type is `()`. | ||||
|  | ||||
| See [pattern matching](../pattern-matching.md) for more details on patterns in | ||||
| Rust. | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user