• Home
Name
Date
Size
#Lines
LOC

..--

.devcontainer/12-May-2024-4741

.github/12-May-2024-189166

.vscode/12-May-2024-7267

book/12-May-2024-4,9174,002

demo/12-May-2024-258191

flags/12-May-2024-250205

gen/12-May-2024-6,8725,607

include/12-May-2024-1,112886

macro/12-May-2024-3,0872,766

src/12-May-2024-4,3052,879

syntax/12-May-2024-6,2175,510

tests/12-May-2024-4,5503,737

third-party/12-May-2024-2,5942,322

tools/12-May-2024-206172

.bazelignoreD12-May-202426 32

.bazelrcD12-May-2024110 32

.buckconfigD12-May-2024497 1815

.clang-formatD12-May-202461 32

.clang-tidyD12-May-2024620 1918

.clippy.tomlD12-May-202416 21

.gitattributesD12-May-202476 32

.gitignoreD12-May-2024107 1110

.gitmodulesD12-May-2024118 43

.watchmanconfigD12-May-202436 43

BUCKD12-May-20242 KiB9387

BUILDD12-May-20242.1 KiB9082

BUILD.gnD12-May-20241.5 KiB5146

Cargo.tomlD12-May-20241.5 KiB5344

LICENSE-APACHED12-May-20249.5 KiB177150

LICENSE-MITD12-May-20241,023 2421

OAT.xmlD12-May-20244.2 KiB6713

README.OpenSourceD12-May-2024357 1211

README.mdD12-May-202416.9 KiB389299

README_zh.mdD12-May-202414 KiB430338

WORKSPACED12-May-2024708 2616

build.rsD12-May-2024869 3329

compile_flags.txtD12-May-202411 21

cpp_call_rust.pngD12-May-202496.2 KiB

rust_call_cpp.pngD12-May-202411 KiB

README.OpenSource

1[
2  {
3    "Name": "cxx",
4    "License": "Apache License 2.0, MIT",
5    "License File": "LICENSE-APACHE, LICENSE-MIT",
6    "Version Number": "1.0.91",
7    "Owner": "fangting12@huawei.com",
8    "Upstream URL": "https://github.com/dtolnay/cxx",
9    "Description": "A Rust library that provides a safe and easy way to call C++ code from Rust."
10  }
11]
12

README.md

1CXX — safe FFI between Rust and C++
2=========================================
3
4[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/cxx-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/cxx)
5[<img alt="crates.io" src="https://img.shields.io/crates/v/cxx.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/cxx)
6[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-cxx-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/cxx)
7[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/cxx/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/cxx/actions?query=branch%3Amaster)
8
9This library provides a **safe** mechanism for calling C++ code from Rust and
10Rust code from C++, not subject to the many ways that things can go wrong when
11using bindgen or cbindgen to generate unsafe C-style bindings.
12
13This doesn't change the fact that 100% of C++ code is unsafe. When auditing a
14project, you would be on the hook for auditing all the unsafe Rust code and
15*all* the C++ code. The core safety claim under this new model is that auditing
16just the C++ side would be sufficient to catch all problems, i.e. the Rust side
17can be 100% safe.
18
19```toml
20[dependencies]
21cxx = "1.0"
22
23[build-dependencies]
24cxx-build = "1.0"
25```
26
27*Compiler support: requires rustc 1.60+ and c++11 or newer*<br>
28*[Release notes](https://github.com/dtolnay/cxx/releases)*
29
30<br>
31
32## Guide
33
34Please see **<https://cxx.rs>** for a tutorial, reference material, and example
35code.
36
37<br>
38
39## Overview
40
41The idea is that we define the signatures of both sides of our FFI boundary
42embedded together in one Rust module (the next section shows an example). From
43this, CXX receives a complete picture of the boundary to perform static analyses
44against the types and function signatures to uphold both Rust's and C++'s
45invariants and requirements.
46
47If everything checks out statically, then CXX uses a pair of code generators to
48emit the relevant `extern "C"` signatures on both sides together with any
49necessary static assertions for later in the build process to verify
50correctness. On the Rust side this code generator is simply an attribute
51procedural macro. On the C++ side it can be a small Cargo build script if your
52build is managed by Cargo, or for other build systems like Bazel or Buck we
53provide a command line tool which generates the header and source file and
54should be easy to integrate.
55
56The resulting FFI bridge operates at zero or negligible overhead, i.e. no
57copying, no serialization, no memory allocation, no runtime checks needed.
58
59The FFI signatures are able to use native types from whichever side they please,
60such as Rust's `String` or C++'s `std::string`, Rust's `Box` or C++'s
61`std::unique_ptr`, Rust's `Vec` or C++'s `std::vector`, etc in any combination.
62CXX guarantees an ABI-compatible signature that both sides understand, based on
63builtin bindings for key standard library types to expose an idiomatic API on
64those types to the other language. For example when manipulating a C++ string
65from Rust, its `len()` method becomes a call of the `size()` member function
66defined by C++; when manipulating a Rust string from C++, its `size()` member
67function calls Rust's `len()`.
68
69<br>
70
71## Example
72
73In this example we are writing a Rust application that wishes to take advantage
74of an existing C++ client for a large-file blobstore service. The blobstore
75supports a `put` operation for a discontiguous buffer upload. For example we
76might be uploading snapshots of a circular buffer which would tend to consist of
772 chunks, or fragments of a file spread across memory for some other reason.
78
79A runnable version of this example is provided under the *demo* directory of
80this repo. To try it out, run `cargo run` from that directory.
81
82```rust
83#[cxx::bridge]
84mod ffi {
85    // Any shared structs, whose fields will be visible to both languages.
86    struct BlobMetadata {
87        size: usize,
88        tags: Vec<String>,
89    }
90
91    extern "Rust" {
92        // Zero or more opaque types which both languages can pass around but
93        // only Rust can see the fields.
94        type MultiBuf;
95
96        // Functions implemented in Rust.
97        fn next_chunk(buf: &mut MultiBuf) -> &[u8];
98    }
99
100    unsafe extern "C++" {
101        // One or more headers with the matching C++ declarations. Our code
102        // generators don't read it but it gets #include'd and used in static
103        // assertions to ensure our picture of the FFI boundary is accurate.
104        include!("demo/include/blobstore.h");
105
106        // Zero or more opaque types which both languages can pass around but
107        // only C++ can see the fields.
108        type BlobstoreClient;
109
110        // Functions implemented in C++.
111        fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
112        fn put(&self, parts: &mut MultiBuf) -> u64;
113        fn tag(&self, blobid: u64, tag: &str);
114        fn metadata(&self, blobid: u64) -> BlobMetadata;
115    }
116}
117```
118
119Now we simply provide Rust definitions of all the things in the `extern "Rust"`
120block and C++ definitions of all the things in the `extern "C++"` block, and get
121to call back and forth safely.
122
123Here are links to the complete set of source files involved in the demo:
124
125- [demo/src/main.rs](demo/src/main.rs)
126- [demo/build.rs](demo/build.rs)
127- [demo/include/blobstore.h](demo/include/blobstore.h)
128- [demo/src/blobstore.cc](demo/src/blobstore.cc)
129
130To look at the code generated in both languages for the example by the CXX code
131generators:
132
133```console
134   # run Rust code generator and print to stdout
135   # (requires https://github.com/dtolnay/cargo-expand)
136$ cargo expand --manifest-path demo/Cargo.toml
137
138   # run C++ code generator and print to stdout
139$ cargo run --manifest-path gen/cmd/Cargo.toml -- demo/src/main.rs
140```
141
142<br>
143
144## Details
145
146As seen in the example, the language of the FFI boundary involves 3 kinds of
147items:
148
149- **Shared structs** &mdash; their fields are made visible to both languages.
150  The definition written within cxx::bridge is the single source of truth.
151
152- **Opaque types** &mdash; their fields are secret from the other language.
153  These cannot be passed across the FFI by value but only behind an indirection,
154  such as a reference `&`, a Rust `Box`, or a `UniquePtr`. Can be a type alias
155  for an arbitrarily complicated generic language-specific type depending on
156  your use case.
157
158- **Functions** &mdash; implemented in either language, callable from the other
159  language.
160
161Within the `extern "Rust"` part of the CXX bridge we list the types and
162functions for which Rust is the source of truth. These all implicitly refer to
163the `super` module, the parent module of the CXX bridge. You can think of the
164two items listed in the example above as being like `use super::MultiBuf` and
165`use super::next_chunk` except re-exported to C++. The parent module will either
166contain the definitions directly for simple things, or contain the relevant
167`use` statements to bring them into scope from elsewhere.
168
169Within the `extern "C++"` part, we list types and functions for which C++ is the
170source of truth, as well as the header(s) that declare those APIs. In the future
171it's possible that this section could be generated bindgen-style from the
172headers but for now we need the signatures written out; static assertions will
173verify that they are accurate.
174
175Your function implementations themselves, whether in C++ or Rust, *do not* need
176to be defined as `extern "C"` ABI or no\_mangle. CXX will put in the right shims
177where necessary to make it all work.
178
179<br>
180
181## Comparison vs bindgen and cbindgen
182
183Notice that with CXX there is repetition of all the function signatures: they
184are typed out once where the implementation is defined (in C++ or Rust) and
185again inside the cxx::bridge module, though compile-time assertions guarantee
186these are kept in sync. This is different from [bindgen] and [cbindgen] where
187function signatures are typed by a human once and the tool consumes them in one
188language and emits them in the other language.
189
190[bindgen]: https://github.com/rust-lang/rust-bindgen
191[cbindgen]: https://github.com/eqrion/cbindgen/
192
193This is because CXX fills a somewhat different role. It is a lower level tool
194than bindgen or cbindgen in a sense; you can think of it as being a replacement
195for the concept of `extern "C"` signatures as we know them, rather than a
196replacement for a bindgen. It would be reasonable to build a higher level
197bindgen-like tool on top of CXX which consumes a C++ header and/or Rust module
198(and/or IDL like Thrift) as source of truth and generates the cxx::bridge,
199eliminating the repetition while leveraging the static analysis safety
200guarantees of CXX.
201
202But note in other ways CXX is higher level than the bindgens, with rich support
203for common standard library types. Frequently with bindgen when we are dealing
204with an idiomatic C++ API we would end up manually wrapping that API in C-style
205raw pointer functions, applying bindgen to get unsafe raw pointer Rust
206functions, and replicating the API again to expose those idiomatically in Rust.
207That's a much worse form of repetition because it is unsafe all the way through.
208
209By using a CXX bridge as the shared understanding between the languages, rather
210than `extern "C"` C-style signatures as the shared understanding, common FFI use
211cases become expressible using 100% safe code.
212
213It would also be reasonable to mix and match, using CXX bridge for the 95% of
214your FFI that is straightforward and doing the remaining few oddball signatures
215the old fashioned way with bindgen and cbindgen, if for some reason CXX's static
216restrictions get in the way. Please file an issue if you end up taking this
217approach so that we know what ways it would be worthwhile to make the tool more
218expressive.
219
220<br>
221
222## Cargo-based setup
223
224For builds that are orchestrated by Cargo, you will use a build script that runs
225CXX's C++ code generator and compiles the resulting C++ code along with any
226other C++ code for your crate.
227
228The canonical build script is as follows. The indicated line returns a
229[`cc::Build`] instance (from the usual widely used `cc` crate) on which you can
230set up any additional source files and compiler flags as normal.
231
232[`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html
233
234```toml
235# Cargo.toml
236
237[build-dependencies]
238cxx-build = "1.0"
239```
240
241```rust
242// build.rs
243
244fn main() {
245    cxx_build::bridge("src/main.rs")  // returns a cc::Build
246        .file("src/demo.cc")
247        .flag_if_supported("-std=c++11")
248        .compile("cxxbridge-demo");
249
250    println!("cargo:rerun-if-changed=src/main.rs");
251    println!("cargo:rerun-if-changed=src/demo.cc");
252    println!("cargo:rerun-if-changed=include/demo.h");
253}
254```
255
256<br>
257
258## Non-Cargo setup
259
260For use in non-Cargo builds like Bazel or Buck, CXX provides an alternate way of
261invoking the C++ code generator as a standalone command line tool. The tool is
262packaged as the `cxxbridge-cmd` crate on crates.io or can be built from the
263*gen/cmd* directory of this repo.
264
265```bash
266$ cargo install cxxbridge-cmd
267
268$ cxxbridge src/main.rs --header > path/to/mybridge.h
269$ cxxbridge src/main.rs > path/to/mybridge.cc
270```
271
272<br>
273
274## Safety
275
276Be aware that the design of this library is intentionally restrictive and
277opinionated! It isn't a goal to be powerful enough to handle arbitrary
278signatures in either language. Instead this project is about carving out a
279reasonably expressive set of functionality about which we can make useful safety
280guarantees today and maybe extend over time. You may find that it takes some
281practice to use CXX bridge effectively as it won't work in all the ways that you
282are used to.
283
284Some of the considerations that go into ensuring safety are:
285
286- By design, our paired code generators work together to control both sides of
287  the FFI boundary. Ordinarily in Rust writing your own `extern "C"` blocks is
288  unsafe because the Rust compiler has no way to know whether the signatures
289  you've written actually match the signatures implemented in the other
290  language. With CXX we achieve that visibility and know what's on the other
291  side.
292
293- Our static analysis detects and prevents passing types by value that shouldn't
294  be passed by value from C++ to Rust, for example because they may contain
295  internal pointers that would be screwed up by Rust's move behavior.
296
297- To many people's surprise, it is possible to have a struct in Rust and a
298  struct in C++ with exactly the same layout / fields / alignment / everything,
299  and still not the same ABI when passed by value. This is a longstanding
300  bindgen bug that leads to segfaults in absolutely correct-looking code
301  ([rust-lang/rust-bindgen#778]). CXX knows about this and can insert the
302  necessary zero-cost workaround transparently where needed, so go ahead and
303  pass your structs by value without worries. This is made possible by owning
304  both sides of the boundary rather than just one.
305
306- Template instantiations: for example in order to expose a UniquePtr\<T\> type
307  in Rust backed by a real C++ unique\_ptr, we have a way of using a Rust trait
308  to connect the behavior back to the template instantiations performed by the
309  other language.
310
311[rust-lang/rust-bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778
312
313<br>
314
315## Builtin types
316
317In addition to all the primitive types (i32 &lt;=&gt; int32_t), the following
318common types may be used in the fields of shared structs and the arguments and
319returns of functions.
320
321<table>
322<tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr>
323<tr><td>String</td><td>rust::String</td><td></td></tr>
324<tr><td>&amp;str</td><td>rust::Str</td><td></td></tr>
325<tr><td>&amp;[T]</td><td>rust::Slice&lt;const T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
326<tr><td>&amp;mut [T]</td><td>rust::Slice&lt;T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
327<tr><td><a href="https://docs.rs/cxx/1.0/cxx/struct.CxxString.html">CxxString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr>
328<tr><td>Box&lt;T&gt;</td><td>rust::Box&lt;T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
329<tr><td><a href="https://docs.rs/cxx/1.0/cxx/struct.UniquePtr.html">UniquePtr&lt;T&gt;</a></td><td>std::unique_ptr&lt;T&gt;</td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
330<tr><td><a href="https://docs.rs/cxx/1.0/cxx/struct.SharedPtr.html">SharedPtr&lt;T&gt;</a></td><td>std::shared_ptr&lt;T&gt;</td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
331<tr><td>[T; N]</td><td>std::array&lt;T, N&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
332<tr><td>Vec&lt;T&gt;</td><td>rust::Vec&lt;T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
333<tr><td><a href="https://docs.rs/cxx/1.0/cxx/struct.CxxVector.html">CxxVector&lt;T&gt;</a></td><td>std::vector&lt;T&gt;</td><td><sup><i>cannot be passed by value, cannot hold opaque Rust type</i></sup></td></tr>
334<tr><td>*mut T, *const T</td><td>T*, const T*</td><td><sup><i>fn with a raw pointer argument must be declared unsafe to call</i></sup></td></tr>
335<tr><td>fn(T, U) -&gt; V</td><td>rust::Fn&lt;V(T, U)&gt;</td><td><sup><i>only passing from Rust to C++ is implemented so far</i></sup></td></tr>
336<tr><td>Result&lt;T&gt;</td><td>throw/catch</td><td><sup><i>allowed as return type only</i></sup></td></tr>
337</table>
338
339The C++ API of the `rust` namespace is defined by the *include/cxx.h* file in
340this repo. You will need to include this header in your C++ code when working
341with those types.
342
343The following types are intended to be supported "soon" but are just not
344implemented yet. I don't expect any of these to be hard to make work but it's a
345matter of designing a nice API for each in its non-native language.
346
347<table>
348<tr><th>name in Rust</th><th>name in C++</th></tr>
349<tr><td>BTreeMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
350<tr><td>HashMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
351<tr><td>Arc&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
352<tr><td>Option&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
353<tr><td><sup><i>tbd</i></sup></td><td>std::map&lt;K, V&gt;</td></tr>
354<tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map&lt;K, V&gt;</td></tr>
355</table>
356
357<br>
358
359## Remaining work
360
361This is still early days for CXX; I am releasing it as a minimum viable product
362to collect feedback on the direction and invite collaborators. Please check the
363open issues.
364
365Especially please report issues if you run into trouble building or linking any
366of this stuff. I'm sure there are ways to make the build aspects friendlier or
367more robust.
368
369Finally, I know more about Rust library design than C++ library design so I
370would appreciate help making the C++ APIs in this project more idiomatic where
371anyone has suggestions.
372
373<br>
374
375#### License
376
377<sup>
378Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
3792.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
380</sup>
381
382<br>
383
384<sub>
385Unless you explicitly state otherwise, any contribution intentionally submitted
386for inclusion in this project by you, as defined in the Apache-2.0 license,
387shall be dual licensed as above, without any additional terms or conditions.
388</sub>
389

README_zh.md

1CXX &mdash; Rust和C++之间的安全FFI
2=========================================
3
4[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/CXX-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/CXX)
5[<img alt="crates.io" src="https://img.shields.io/crates/v/CXX.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/CXX)
6[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-CXX-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/cxx)
7[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/CXX/ci.yml" height="20">](https://github.com/dtolnay/CXX)
8
9
10## 引入背景
11
12
13CXX工具提供了一种安全的互相调用机制,可以实现rust和C++的互相调用。
14
15CXX通过FFI(Foreign Function Interface)和函数签名的形式来实现接口和类型声明,并对类型和函数签名进行静态分析,以维护Rust和C++的不变量和要求。
16
17<br>
18
19## CXX工具在OH上的使用指导
20
21### C++调用Rust接口
22
231. 在Rust侧文件lib.rs里mod ffi写清楚需要调用的C++接口,并将接口包含在extern "Rust"里面,暴露给C++侧使用。
24
25   ```rust
26   //! #[cxx::bridge]
27   #[cxx::bridge]
28   mod ffi{
29       #![allow(dead_code)]
30       #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
31       struct Shared {
32           z: usize,
33       }
34       extern "Rust"{
35           fn print_message_in_rust();
36           fn r_return_primitive() -> usize;
37           fn r_return_shared() -> Shared;
38           fn r_return_rust_string() -> String;
39           fn r_return_sum(_: usize, _: usize) -> usize;
40       }
41   }
42
43   fn print_message_in_rust(){
44       println!("Here is a test for cpp call Rust.");
45   }
46   fn r_return_shared() -> ffi::Shared {
47       println!("Here is a message from Rust,test for ffi::Shared:");
48       ffi::Shared { z: 1996 }
49   }
50   fn r_return_primitive() -> usize {
51       println!("Here is a message from Rust,test for usize:");
52       1997
53   }
54   fn r_return_rust_string() -> String {
55       println!("Here is a message from Rust,test for String");
56       "Hello World!".to_owned()
57   }
58   fn r_return_sum(n1: usize, n2: usize) -> usize {
59       println!("Here is a message from Rust,test for {} + {} is:",n1 ,n2);
60       n1 + n2
61   }
62
63   ```
64
652. C++侧将cxx工具转换出来的lib.rs.h包含进来,就可以使用C++侧的接口。
66
67   ```c++
68   #include <iostream>
69   #include "build/rust/tests/test_cxx/src/lib.rs.h"
70
71   int main(int argc, const char* argv[])
72   {
73       int a = 2021;
74       int b = 4;
75       print_message_in_rust();
76       std::cout << r_return_primitive() << std::endl;
77       std::cout << r_return_shared().z << std::endl;
78       std::cout << std::string(r_return_rust_string()) << std::endl;
79       std::cout << r_return_sum(a, b) << std::endl;
80       return 0;
81   }
82   ```
83
843. 添加构建文件BUILD.gn。rust_cxx底层调用CXX工具将lib.rs文件转换成lib.rs.hlib.rs.cc文件,ohos_rust_static_ffi实现Rust侧源码的编译,ohos_executable实现C++侧代码的编译。
85
86   ```
87   import("//build/ohos.gni")
88   import("//build/templates/rust/rust_cxx.gni")
89
90   rust_cxx("test_cxx_exe_gen") {
91       sources = [ "src/lib.rs" ]
92   }
93
94   ohos_rust_static_ffi("test_cxx_examp_rust") {
95       sources = [ "src/lib.rs" ]
96       deps = [ "//build/rust:cxx_rustdeps" ]
97   }
98
99   ohos_executable("test_cxx_exe") {
100       sources = [ "main.cpp" ]
101       sources += get_target_outputs(":test_cxx_exe_gen")
102
103       include_dirs = [ "${target_gen_dir}" ]
104       deps = [
105       ":test_cxx_examp_rust",
106       ":test_cxx_exe_gen",
107       "//build/rust:cxx_cppdeps",
108       ]
109   }
110   ```
111
112**调测验证**
113![cpp_call_rust](./cpp_call_rust.png)
114
115
116### Rust调用C++
117
1181. 添加头文件client_blobstore.h119
120   ```c++
121   #ifndef BUILD_RUST_TESTS_CLIENT_BLOBSTORE_H
122   #define BUILD_RUST_TESTS_CLIENT_BLOBSTORE_H
123   #include <memory>
124   #include "third_party/rust/cxx/include/cxx.h"
125
126   namespace nsp_org {
127   namespace nsp_blobstore {
128   struct MultiBufs;
129   struct Metadata_Blob;
130
131   class client_blobstore {
132   public:
133       client_blobstore();
134       uint64_t put_buf(MultiBufs &buf) const;
135       void add_tag(uint64_t blobid, rust::Str add_tag) const;
136       Metadata_Blob get_metadata(uint64_t blobid) const;
137
138   private:
139       class impl;
140       std::shared_ptr<impl> impl;
141   };
142
143   std::unique_ptr<client_blobstore> blobstore_client_new();
144   } // namespace nsp_blobstore
145   } // namespace nsp_org
146   #endif
147   ```
148
1492. 添加cpp文件client_blobstore.cpp150
151   ```c++
152   #include <algorithm>
153   #include <functional>
154   #include <set>
155   #include <string>
156   #include <unordered_map>
157   #include "src/main.rs.h"
158   #include "build/rust/tests/test_cxx_rust/include/client_blobstore.h"
159
160   namespace nsp_org {
161   namespace nsp_blobstore {
162   // Toy implementation of an in-memory nsp_blobstore.
163   //
164   // In reality the implementation of client_blobstore could be a large complex C++
165   // library.
166   class client_blobstore::impl {
167       friend client_blobstore;
168       using Blob = struct {
169           std::string data;
170           std::set<std::string> tags;
171       };
172       std::unordered_map<uint64_t, Blob> blobs;
173   };
174
175   client_blobstore::client_blobstore() : impl(new class client_blobstore::impl) {}
176
177   // Upload a new blob and return a blobid that serves as a handle to the blob.
178   uint64_t client_blobstore::put_buf(MultiBufs &buf) const
179   {
180       std::string contents;
181
182       // Traverse the caller's res_chunk iterator.
183       //
184       // In reality there might be sophisticated batching of chunks and/or parallel
185       // upload implemented by the nsp_blobstore's C++ client.
186       while (true) {
187           auto res_chunk = next_chunk(buf);
188           if (res_chunk.size() == 0) {
189           break;
190           }
191           contents.append(reinterpret_cast<const char *>(res_chunk.data()), res_chunk.size());
192       }
193
194       // Insert into map and provide caller the handle.
195       auto res = std::hash<std::string> {} (contents);
196       impl->blobs[res] = {std::move(contents), {}};
197       return res;
198   }
199
200   // Add add_tag to an existing blob.
201   void client_blobstore::add_tag(uint64_t blobid, rust::Str add_tag) const
202   {
203       impl->blobs[blobid].tags.emplace(add_tag);
204   }
205
206   // Retrieve get_metadata about a blob.
207   Metadata_Blob client_blobstore::get_metadata(uint64_t blobid) const
208   {
209       Metadata_Blob get_metadata {};
210       auto blob = impl->blobs.find(blobid);
211       if (blob != impl->blobs.end()) {
212           get_metadata.size = blob->second.data.size();
213           std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),
214               [&](auto &t) { get_metadata.tags.emplace_back(t); });
215       }
216       return get_metadata;
217   }
218
219   std::unique_ptr<client_blobstore> blobstore_client_new()
220   {
221       return std::make_unique<client_blobstore>();
222   }
223   } // namespace nsp_blobstore
224   } // namespace nsp_org
225
226   ```
227
2283. main.rs文件,在main.rs文件的ffi里面,通过宏include!将头文件client_blobstore.h引入进来,从而在Rust的main函数里面就可以通过ffi的方式调用C++的接口。
229
230   ```rust
231   //! test_cxx_rust
232   #[cxx::bridge(namespace = "nsp_org::nsp_blobstore")]
233   mod ffi {
234       // Shared structs with fields visible to both languages.
235       struct Metadata_Blob {
236           size: usize,
237           tags: Vec<String>,
238       }
239
240       // Rust types and signatures exposed to C++.
241       extern "Rust" {
242           type MultiBufs;
243
244           fn next_chunk(buf: &mut MultiBufs) -> &[u8];
245       }
246
247       // C++ types and signatures exposed to Rust.
248       unsafe extern "C++" {
249           include!("build/rust/tests/test_cxx_rust/include/client_blobstore.h");
250
251           type client_blobstore;
252
253           fn blobstore_client_new() -> UniquePtr<client_blobstore>;
254           fn put_buf(&self, parts: &mut MultiBufs) -> u64;
255           fn add_tag(&self, blobid: u64, add_tag: &str);
256           fn get_metadata(&self, blobid: u64) -> Metadata_Blob;
257       }
258   }
259
260   // An iterator over contiguous chunks of a discontiguous file object.
261   //
262   // Toy implementation uses a Vec<Vec<u8>> but in reality this might be iterating
263   // over some more complex Rust data structure like a rope, or maybe loading
264   // chunks lazily from somewhere.
265   /// pub struct MultiBufs
266   pub struct MultiBufs {
267       chunks: Vec<Vec<u8>>,
268       pos: usize,
269   }
270   /// pub fn next_chunk
271   pub fn next_chunk(buf: &mut MultiBufs) -> &[u8] {
272       let next = buf.chunks.get(buf.pos);
273       buf.pos += 1;
274       next.map_or(&[], Vec::as_slice)
275   }
276
277   /// fn main()
278   fn main() {
279       let client = ffi::blobstore_client_new();
280
281       // Upload a blob.
282       let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];
283       let mut buf = MultiBufs { chunks, pos: 0 };
284       let blobid = client.put_buf(&mut buf);
285       println!("This is a test for Rust call cpp:");
286       println!("blobid = {}", blobid);
287
288       // Add a add_tag.
289       client.add_tag(blobid, "rust");
290
291       // Read back the tags.
292       let get_metadata = client.get_metadata(blobid);
293       println!("tags = {:?}", get_metadata.tags);
294   }
295   ```
296
2974. 添加构建文件BUILD.gn。使用CXX将main.rs转换成lib.rs.hlib.rs.cc,同时将产物作为test_cxx_rust_staticlib的源码,编译Rust源码main.rs并将test_cxx_rust_staticlib依赖进来。
298
299   ```
300   import("//build/ohos.gni")
301
302   rust_cxx("test_cxx_rust_gen") {
303     sources = [ "src/main.rs" ]
304   }
305
306   ohos_static_library("test_cxx_rust_staticlib") {
307     sources = [ "src/client_blobstore.cpp" ]
308     sources += get_target_outputs(":test_cxx_rust_gen")
309     include_dirs = [
310       "${target_gen_dir}",
311       "//third_party/rust/cxx/v1/crate/include",
312       "include",
313     ]
314     deps = [
315       ":test_cxx_rust_gen",
316       "//build/rust:cxx_cppdeps",
317     ]
318   }
319
320   ohos_rust_executable("test_cxx_rust") {
321     sources = [ "src/main.rs" ]
322     deps = [
323       ":test_cxx_rust_staticlib",
324       "//build/rust:cxx_rustdeps",
325     ]
326   }
327   ```
328
329**调测验证**
330![rust_call_cpp](./rust_call_cpp.png)
331
332<br>
333
334
335
336## 与bindgen的对比
337
338bindgen主要用来实现rust代码对c接口的单向调用;CXX工具可以实现rust和C++的互相调用。
339
340<br>
341
342## 基于cargo的构建
343
344对于由Cargo的构建,需要使用一个构建脚本来运行CXX的C++代码生成器。
345
346典型的构建脚本如下:
347
348[`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html
349
350```toml
351# Cargo.toml
352
353[build-dependencies]
354CXX-build = "1.0"
355```
356
357```rust
358// build.rs
359
360fn main() {
361    CXX_build::bridge("src/main.rs")  // returns a cc::Build
362        .file("src/demo.cc")
363        .flag_if_supported("-std=C++11")
364        .compile("cxxbridge-demo");
365
366    println!("cargo:rerun-if-changed=src/main.rs");
367    println!("cargo:rerun-if-changed=src/demo.cc");
368    println!("cargo:rerun-if-changed=include/demo.h");
369}
370```
371
372<br>
373
374## 基于非cargo的构建
375
376对于在非Cargo构建中的使用,如Bazel或Buck,CXX提供了另一种方式产生C++侧的头文件和源代码文件,作为一个独立的命令行工具使用。
377
378```bash
379$ cargo install cxxbridge-cmd
380$ cxxbridge src/main.rs --header > path/to/mybridge.h
381$ cxxbridge src/main.rs > path/to/mybridge.cc
382```
383
384<br>
385
386
387## 内置类型
388
389除了所有的原生类型(i32 &lt;=&gt; int32_t)之外,还有以下常见类型可用于共享结构的字段以及函数的参数和返回值。
390
391<table>
392<tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr>
393<tr><td>String</td><td>rust::String</td><td></td></tr>
394<tr><td>&amp;str</td><td>rust::Str</td><td></td></tr>
395<tr><td>&amp;[T]</td><td>rust::Slice&lt;const T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
396<tr><td>&amp;mut [T]</td><td>rust::Slice&lt;T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
397<tr><td><a href="https://docs.rs/cxx/1.0/CXX/struct.CXXString.html">CXXString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr>
398<tr><td>Box&lt;T&gt;</td><td>rust::Box&lt;T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
399<tr><td><a href="https://docs.rs/cxx/1.0/CXX/struct.UniquePtr.html">UniquePtr&lt;T&gt;</a></td><td>std::unique_ptr&lt;T&gt;</td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
400<tr><td><a href="https://docs.rs/cxx/1.0/CXX/struct.SharedPtr.html">SharedPtr&lt;T&gt;</a></td><td>std::shared_ptr&lt;T&gt;</td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
401<tr><td>[T; N]</td><td>std::array&lt;T, N&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
402<tr><td>Vec&lt;T&gt;</td><td>rust::Vec&lt;T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
403<tr><td><a href="https://docs.rs/cxx/1.0/CXX/struct.CXXVector.html">CXXVector&lt;T&gt;</a></td><td>std::vector&lt;T&gt;</td><td><sup><i>cannot be passed by value, cannot hold opaque Rust type</i></sup></td></tr>
404<tr><td>*mut T, *const T</td><td>T*, const T*</td><td><sup><i>fn with a raw pointer argument must be declared unsafe to call</i></sup></td></tr>
405<tr><td>fn(T, U) -&gt; V</td><td>rust::Fn&lt;V(T, U)&gt;</td><td><sup><i>only passing from Rust to C++ is implemented so far</i></sup></td></tr>
406<tr><td>Result&lt;T&gt;</td><td>throw/catch</td><td><sup><i>allowed as return type only</i></sup></td></tr>
407</table>
408
409`rust`命名空间的C++ API是由*include/CXX.h*文件定义的。使用这些类型时种类的时候,需要C++代码中包含这个头文件。
410
411以下类型很快被支持,只是还没有实现。
412
413<table>
414<tr><th>name in Rust</th><th>name in C++</th></tr>
415<tr><td>BTreeMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
416<tr><td>HashMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
417<tr><td>Arc&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
418<tr><td>Option&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
419<tr><td><sup><i>tbd</i></sup></td><td>std::map&lt;K, V&gt;</td></tr>
420<tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map&lt;K, V&gt;</td></tr>
421</table>
422
423<br>
424
425## 开发者贡献
426
427当前CXX工具还没有达到普遍使用阶段,在使用该工具的过程中有任何问题欢迎开发者在社区issue中反馈。
428
429<br>
430