1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-06-24 17:56:45 +02:00

Publish Comprehensive Rust 🦀

This commit is contained in:
Martin Geisler
2022-12-21 16:36:30 +01:00
commit c212a473ba
252 changed files with 8047 additions and 0 deletions

View 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

View File

@ -0,0 +1 @@
../../../../third_party/cxx/overview.svg

View 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}}
```

View 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

View 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);
}
}

View 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()
}

View 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.

View 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}}
```

View 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

View 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}}
```

View 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");
}

View 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);

View File

@ -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"

View 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);
}
}

View File

@ -0,0 +1 @@
# Calling Rust from C

View 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.

View 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}}
```

View File

@ -0,0 +1,5 @@
cc_binary {
name: "analyze_numbers",
srcs: ["main.c"],
static_libs: ["libanalyze_ffi"],
}

View 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;
}

View File

@ -0,0 +1,6 @@
rust_ffi {
name: "libanalyze_ffi",
crate_name: "analyze_ffi",
srcs: ["analyze.rs"],
include_dirs: ["."],
}

View File

@ -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

View 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: 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})");
}
}