You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-07-03 05:27:04 +02:00
Format all Markdown files with dprint
(#1157)
This is the result of running `dprint fmt` after removing `src/` from the list of excluded directories. This also reformats the Rust code: we might want to tweak this a bit in the future since some of the changes removes the hand-formatting. Of course, this formatting can be seen as a mis-feature, so maybe this is good overall. Thanks to mdbook-i18n-helpers 0.2, the POT file is nearly unchanged after this, meaning that all existing translations remain valid! A few messages were changed because of stray whitespace characters: msgid "" "Slices always borrow from another object. In this example, `a` has to remain " -"'alive' (in scope) for at least as long as our slice. " +"'alive' (in scope) for at least as long as our slice." msgstr "" The formatting is enforced in CI and we will have to see how annoying this is in practice for the many contributors. If it becomes annoying, we should look into fixing dprint/check#11 so that `dprint` can annotate the lines that need fixing directly, then I think we can consider more strict formatting checks. I added more customization to `rustfmt.toml`. This is to better emulate the dense style used in the course: - `max_width = 85` allows lines to take up the full width available in our code blocks (when taking margins and the line numbers into account). - `wrap_comments = true` ensures that we don't show very long comments in the code examples. I edited some comments to shorten them and avoid unnecessary line breaks — please trim other unnecessarily long comments when you see them! Remember we're writing code for slides 😄 - `use_small_heuristics = "Max"` allows for things like struct literals and if-statements to take up the full line width configured above. The formatting settings apply to all our Rust code right now — I think we could improve this with https://github.com/dprint/dprint/issues/711 which lets us add per-directory `dprint` configuration files. However, the `inherit: true` setting is not yet implemented (as far as I can tell), so a nested configuration file will have to copy most or all of the top-level file.
This commit is contained in:
@ -1,7 +1,9 @@
|
||||
# AIDL
|
||||
|
||||
The [Android Interface Definition Language
|
||||
(AIDL)](https://developer.android.com/guide/components/aidl) is supported in Rust:
|
||||
The
|
||||
[Android Interface Definition Language
|
||||
(AIDL)](https://developer.android.com/guide/components/aidl) is supported in
|
||||
Rust:
|
||||
|
||||
* Rust code can call existing AIDL servers,
|
||||
* You can create new AIDL servers in Rust.
|
||||
- Rust code can call existing AIDL servers,
|
||||
- You can create new AIDL servers in Rust.
|
||||
|
@ -20,15 +20,14 @@ use com_example_birthdayservice::binder;
|
||||
const SERVICE_IDENTIFIER: &str = "birthdayservice";
|
||||
|
||||
/// Connect to the BirthdayService.
|
||||
pub fn connect() -> Result<binder::Strong<dyn IBirthdayService>, binder::StatusCode> {
|
||||
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 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())
|
||||
|
@ -24,8 +24,6 @@ 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!"
|
||||
))
|
||||
Ok(format!("Happy Birthday {name}, congratulations with the {years} years!"))
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
Finally, we can create a Rust client for our new service.
|
||||
|
||||
*birthday_service/src/client.rs*:
|
||||
_birthday_service/src/client.rs_:
|
||||
|
||||
```rust,ignore
|
||||
{{#include birthday_service/src/client.rs:main}}
|
||||
```
|
||||
|
||||
*birthday_service/Android.bp*:
|
||||
_birthday_service/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include birthday_service/Android.bp:birthday_client}}
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
We can now implement the AIDL service:
|
||||
|
||||
*birthday_service/src/lib.rs*:
|
||||
_birthday_service/src/lib.rs_:
|
||||
|
||||
```rust,ignore
|
||||
{{#include birthday_service/src/lib.rs:IBirthdayService}}
|
||||
```
|
||||
|
||||
*birthday_service/Android.bp*:
|
||||
_birthday_service/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include birthday_service/Android.bp:libbirthdayservice}}
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
You declare the API of your service using an AIDL interface:
|
||||
|
||||
*birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl*:
|
||||
_birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl_:
|
||||
|
||||
```java
|
||||
{{#include birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl:IBirthdayService}}
|
||||
```
|
||||
|
||||
*birthday_service/aidl/Android.bp*:
|
||||
_birthday_service/aidl/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include birthday_service/aidl/Android.bp}}
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
Finally, we can create a server which exposes the service:
|
||||
|
||||
*birthday_service/src/server.rs*:
|
||||
_birthday_service/src/server.rs_:
|
||||
|
||||
```rust,ignore
|
||||
{{#include birthday_service/src/server.rs:main}}
|
||||
```
|
||||
|
||||
*birthday_service/Android.bp*:
|
||||
_birthday_service/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include birthday_service/Android.bp:birthday_server}}
|
||||
|
@ -19,13 +19,20 @@ We will look at `rust_binary` and `rust_library` next.
|
||||
|
||||
Additional items speaker may mention:
|
||||
|
||||
- Cargo is not optimized for multi-language repos, and also downloads packages from the internet.
|
||||
- Cargo is not optimized for multi-language repos, and also downloads packages
|
||||
from the internet.
|
||||
|
||||
- For compliance and performance, Android must have crates in-tree. It must also interop with C/C++/Java code. Soong fills that gap.
|
||||
- For compliance and performance, Android must have crates in-tree. It must also
|
||||
interop with C/C++/Java code. Soong fills that gap.
|
||||
|
||||
- Soong has many similarities to Bazel, which is the open-source variant of Blaze (used in google3).
|
||||
- Soong has many similarities to Bazel, which is the open-source variant of
|
||||
Blaze (used in google3).
|
||||
|
||||
- There is a plan to transition [Android](https://source.android.com/docs/setup/build/bazel/introduction), [ChromeOS](https://chromium.googlesource.com/chromiumos/bazel/), and [Fuchsia](https://source.android.com/docs/setup/build/bazel/introduction) to Bazel.
|
||||
- There is a plan to transition
|
||||
[Android](https://source.android.com/docs/setup/build/bazel/introduction),
|
||||
[ChromeOS](https://chromium.googlesource.com/chromiumos/bazel/), and
|
||||
[Fuchsia](https://source.android.com/docs/setup/build/bazel/introduction) to
|
||||
Bazel.
|
||||
|
||||
- Learning Bazel-like build rules is useful for all Rust OS developers.
|
||||
|
||||
|
@ -4,8 +4,8 @@ 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
|
||||
- `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/
|
||||
|
@ -3,8 +3,8 @@
|
||||
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.
|
||||
- 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.
|
||||
|
@ -17,12 +17,12 @@ cc_library_static {
|
||||
|
||||
<details>
|
||||
|
||||
* Point out that `libcxx_test_bridge_header` and `libcxx_test_bridge_code` are
|
||||
- Point out that `libcxx_test_bridge_header` and `libcxx_test_bridge_code` are
|
||||
the dependencies for the CXX-generated C++ bindings. We'll show how these are
|
||||
setup on the next slide.
|
||||
* Note that you also need to depend on the `cxx-bridge-header` library in order
|
||||
- Note that you also need to depend on the `cxx-bridge-header` library in order
|
||||
to pull in common CXX definitions.
|
||||
* Full docs for using CXX in Android can be found in [the Android docs]. You may
|
||||
- Full docs for using CXX in Android can be found in [the Android docs]. You may
|
||||
want to share that link with the class so that students know where they can
|
||||
find these instructions again in the future.
|
||||
|
||||
|
@ -26,9 +26,9 @@ genrule {
|
||||
|
||||
<details>
|
||||
|
||||
* The `cxxbridge` tool is a standalone tool that generates the C++ side of the
|
||||
- The `cxxbridge` tool is a standalone tool that generates the C++ side of the
|
||||
bridge module. It is included in Android and available as a Soong tool.
|
||||
* By convention, if your Rust source file is `lib.rs` your header file will be
|
||||
- By convention, if your Rust source file is `lib.rs` your header file will be
|
||||
named `lib.rs.h` and your source file will be named `lib.rs.cc`. This naming
|
||||
convention isn't enforced, though.
|
||||
|
||||
|
@ -10,14 +10,14 @@ a Rust module annotated with the `#[cxx::bridge]` attribute macro.
|
||||
|
||||
<details>
|
||||
|
||||
* The bridge is generally declared in an `ffi` module within your crate.
|
||||
* From the declarations made in the bridge module, CXX will generate matching
|
||||
- The bridge is generally declared in an `ffi` module within your crate.
|
||||
- From the declarations made in the bridge module, CXX will generate matching
|
||||
Rust and C++ type/function definitions in order to expose those items to both
|
||||
languages.
|
||||
* To view the generated Rust code, use [cargo-expand] to view the expanded proc
|
||||
- To view the generated Rust code, use [cargo-expand] to view the expanded proc
|
||||
macro. For most of the examples you would use `cargo expand ::ffi` to expand
|
||||
just the `ffi` module (though this doesn't apply for Android projects).
|
||||
* To view the generated C++ code, look in `target/cxxbridge`.
|
||||
- To view the generated C++ code, look in `target/cxxbridge`.
|
||||
|
||||
[cargo-expand]: https://github.com/dtolnay/cargo-expand
|
||||
|
||||
|
@ -43,10 +43,10 @@ impl BlobstoreClient {
|
||||
|
||||
<details>
|
||||
|
||||
* The programmer does not need to promise that the signatures they have typed in
|
||||
- The programmer does not need to promise that the signatures they have typed in
|
||||
are accurate. CXX performs static assertions that the signatures exactly
|
||||
correspond with what is declared in C++.
|
||||
* `unsafe extern` blocks allow you to declare C++ functions that are safe to
|
||||
- `unsafe extern` blocks allow you to declare C++ functions that are safe to
|
||||
call from Rust.
|
||||
|
||||
</details>
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
<details>
|
||||
|
||||
* C++ functions declared to return a `Result` will catch any thrown exception on
|
||||
- C++ functions declared to return a `Result` will catch any thrown exception on
|
||||
the C++ side and return it as an `Err` value to the calling Rust function.
|
||||
* If an exception is thrown from an extern "C++" function that is not declared
|
||||
- If an exception is thrown from an extern "C++" function that is not declared
|
||||
by the CXX bridge to return `Result`, the program calls C++'s
|
||||
`std::terminate`. The behavior is equivalent to the same exception being
|
||||
thrown through a `noexcept` C++ function.
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
<details>
|
||||
|
||||
* Items declared in the `extern "Rust"` reference items that are in scope in the
|
||||
- Items declared in the `extern "Rust"` reference items that are in scope in the
|
||||
parent module.
|
||||
* The CXX code generator uses your `extern "Rust"` section(s) to produce a C++
|
||||
- The CXX code generator uses your `extern "Rust"` section(s) to produce a C++
|
||||
header file containing the corresponding C++ declarations. The generated
|
||||
header has the same path as the Rust source file containing the bridge, except
|
||||
with a .rs.h file extension.
|
||||
|
@ -6,12 +6,12 @@
|
||||
|
||||
<details>
|
||||
|
||||
* Rust functions that return `Result` are translated to exceptions on the C++
|
||||
- Rust functions that return `Result` are translated to exceptions on the C++
|
||||
side.
|
||||
* The exception thrown will always be of type `rust::Error`, which primarily
|
||||
- The exception thrown will always be of type `rust::Error`, which primarily
|
||||
exposes a way to get the error message string. The error message will come
|
||||
from the error type's `Display` impl.
|
||||
* A panic unwinding from Rust to C++ will always cause the process to
|
||||
- A panic unwinding from Rust to C++ will always cause the process to
|
||||
immediately terminate.
|
||||
|
||||
</details>
|
||||
|
@ -18,7 +18,7 @@ Generated C++:
|
||||
|
||||
<details>
|
||||
|
||||
* On the Rust side, the code generated for shared enums is actually a struct
|
||||
- On the Rust side, the code generated for shared enums is actually a struct
|
||||
wrapping a numeric value. This is because it is not UB in C++ for an enum
|
||||
class to hold a value different from all of the listed variants, and our Rust
|
||||
representation needs to have the same behavior.
|
||||
|
@ -6,8 +6,8 @@
|
||||
|
||||
<details>
|
||||
|
||||
* Only C-like (unit) enums are supported.
|
||||
* A limited number of traits are supported for `#[derive()]` on shared types.
|
||||
- Only C-like (unit) enums are supported.
|
||||
- A limited number of traits are supported for `#[derive()]` on shared types.
|
||||
Corresponding functionality is also generated for the C++ code, e.g. if you
|
||||
derive `Hash` also generates an implementation of `std::hash` for the
|
||||
corresponding C++ type.
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Additional Types
|
||||
|
||||
| Rust Type | C++ Type |
|
||||
|-------------------|----------------------|
|
||||
| ----------------- | -------------------- |
|
||||
| `String` | `rust::String` |
|
||||
| `&str` | `rust::Str` |
|
||||
| `CxxString` | `std::string` |
|
||||
@ -13,14 +13,14 @@
|
||||
|
||||
<details>
|
||||
|
||||
* These types can be used in the fields of shared structs and the arguments and
|
||||
- These types can be used in the fields of shared structs and the arguments and
|
||||
returns of extern functions.
|
||||
* Note that Rust's `String` does not map directly to `std::string`. There are a
|
||||
- Note that Rust's `String` does not map directly to `std::string`. There are a
|
||||
few reasons for this:
|
||||
* `std::string` does not uphold the UTF-8 invariant that `String` requires.
|
||||
* The two types have different layouts in memory and so can't be passed
|
||||
- `std::string` does not uphold the UTF-8 invariant that `String` requires.
|
||||
- The two types have different layouts in memory and so can't be passed
|
||||
directly between languages.
|
||||
* `std::string` requires move constructors that don't match Rust's move
|
||||
- `std::string` requires move constructors that don't match Rust's move
|
||||
semantics, so a `std::string` can't be passed by value to Rust.
|
||||
|
||||
</details>
|
||||
|
@ -1,8 +1,9 @@
|
||||
# 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.
|
||||
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:
|
||||
|
||||
|
@ -17,8 +17,8 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
We already saw this in the [Safe FFI Wrapper
|
||||
exercise](../../exercises/day-3/safe-ffi-wrapper.md).
|
||||
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.
|
||||
|
@ -17,4 +17,3 @@ _interoperability/c/libbirthday/libbirthday.c_:
|
||||
```c
|
||||
{{#include c/libbirthday/libbirthday.c}}
|
||||
```
|
||||
|
||||
|
@ -19,10 +19,7 @@ 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,
|
||||
};
|
||||
let card = card { name: name.as_ptr(), years: 42 };
|
||||
// SAFETY: `print_card` is safe to call with a valid `card` pointer.
|
||||
unsafe {
|
||||
print_card(&card as *const card);
|
||||
|
@ -14,8 +14,8 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
We already saw this in the [Safe FFI Wrapper
|
||||
exercise](../../exercises/day-3/safe-ffi-wrapper.md).
|
||||
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.
|
||||
|
@ -34,7 +34,6 @@ _interoperability/rust/analyze/Android.bp_
|
||||
{{#include rust/analyze/Android.bp}}
|
||||
```
|
||||
|
||||
|
||||
Build, push, and run the binary on your device:
|
||||
|
||||
```shell
|
||||
@ -43,7 +42,8 @@ Build, push, and run the binary on your device:
|
||||
|
||||
<details>
|
||||
|
||||
`#[no_mangle]` disables Rust's usual name mangling, so the exported symbol will just be the name of
|
||||
the function. You can also use `#[export_name = "some_name"]` to specify whatever name you want.
|
||||
`#[no_mangle]` disables Rust's usual name mangling, so the exported symbol will
|
||||
just be the name of the function. You can also use
|
||||
`#[export_name = "some_name"]` to specify whatever name you want.
|
||||
|
||||
</details>
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Setup
|
||||
|
||||
We will be using a Cuttlefish Android Virtual Device to test our code. Make sure you
|
||||
have access to one or create a new one with:
|
||||
We will be using a Cuttlefish 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
|
||||
@ -9,15 +9,18 @@ lunch aosp_cf_x86_64_phone-trunk_staging-userdebug
|
||||
acloud create
|
||||
```
|
||||
|
||||
Please see the [Android Developer
|
||||
Codelab](https://source.android.com/docs/setup/start) for details.
|
||||
Please see the
|
||||
[Android Developer Codelab](https://source.android.com/docs/setup/start) for
|
||||
details.
|
||||
|
||||
<details>
|
||||
|
||||
Key points:
|
||||
|
||||
- Cuttlefish is a reference Android device designed to work on generic Linux desktops. MacOS support is also planned.
|
||||
- Cuttlefish is a reference Android device designed to work on generic Linux
|
||||
desktops. MacOS support is also planned.
|
||||
|
||||
- The Cuttlefish system image maintains high fidelity to real devices, and is the ideal emulator to run many Rust use cases.
|
||||
- The Cuttlefish system image maintains high fidelity to real devices, and is
|
||||
the ideal emulator to run many Rust use cases.
|
||||
|
||||
</details>
|
||||
|
Reference in New Issue
Block a user