1# Interactive Tool User Guide
2
3## Introduction
4
5You can use Bindgen and CXX to implement the interaction between Rust and C/C++. Bindgen enables Rust to call C by converting C interfaces into Rust interfaces. CXX implement interaction between C++ and Rust by generating bindings between C interfaces and Rust interfaces.
6
7![bindgen_and_cxx_tools](./figures/bindgen_and_cxx_tools.png)
8
9## Using Bindgen
10
11### Procedure
12The following example shows how to use Bindgen to implement invocation of C by Rust.
13
141. In the header file **lib.h**, define two interfaces **FuncAAddB** and **SayHello** in C. The **FuncAAddB** interface calculates the sum of two numbers, and the **SayHello** interface prints strings.
15
16   ```c
17   #ifndef BUILD_RUST_TESTS_BINDGEN_TEST_LIB_H_
18   #define BUILD_RUST_TESTS_BINDGEN_TEST_LIB_H_
19   #include <stdint.h>
20   #include "build/rust/tests/test_bindgen_test/test_for_hello_world/lib2.h"
21
22   uint32_t FuncAAddB(uint32_t a, uint32_t b);
23   void SayHello(const char *message);
24
25   #endif  //  BUILD_RUST_TESTS_BINDGEN_TEST_LIB_H_
26   ```
27
28
292. Add the implementation of the two interfaces to **lib.c**.
30
31   ```c
32   #include "build/rust/tests/test_bindgen_test/test_for_hello_world/lib.h"
33   #include <stdint.h>
34   #include <stdio.h>
35
36   void SayHello(const char *message)
37   {
38       printf("This is a test for bindgen hello world:\n");
39       printf("%s\n", message);
40   }
41
42   uint32_t FuncAAddB(uint32_t a, uint32_t b)
43   {
44       printf("This is a test for bindgen of a + b:\n");
45       return a + b;
46   }
47   ```
48
493. Create the **main.rs** file to call C interfaces through c_ffi using Rust. Note that insecure interfaces called by Rust must be encapsulated by using **unsafe**.
50
51   ```rust
52   //!  bindgen test for hello world
53   #![allow(clippy::approx_constant)]
54   mod c_ffi {
55       #![allow(dead_code)]
56       #![allow(non_upper_case_globals)]
57       #![allow(non_camel_case_types)]
58       include!(env!("BINDGEN_RS_FILE"));
59   }
60   /// pub fn add_two_numbers_in_c
61   pub fn add_two_numbers_in_c(a: u32, b: u32) -> u32 {
62       unsafe { c_ffi::FuncAAddB(a, b) }
63   }
64
65   use std::ffi::c_char;
66   use std::ffi::CString;
67
68   /// fn main()
69   fn main() {
70       println!("{} + {} = {}", 3, 7, add_two_numbers_in_c(3, 7));
71       let c_str = CString::new("This is a message from C").unwrap();
72       let c_world: *const c_char = c_str.as_ptr() as *const c_char;
73       unsafe {
74           c_ffi::SayHello(c_world);
75       }
76   }
77
78   ```
79
804. Create the **BUILD.gn** file to define the dependency of the Rust module on the C module.
81
82   ```GN
83   import("//build/ohos.gni")
84
85   ohos_shared_library("c_lib") {
86     sources = [ "lib.c" ]
87     defines = [ "COMPONENT_IMPLEMENTATION" ]
88   }
89
90   rust_bindgen("c_lib_bindgen") {
91     header = "lib.h"
92   }
93
94   ohos_rust_executable("bindgen_test") {
95     deps = [ ":c_lib" ]
96     deps += [ ":c_lib_bindgen" ]
97     sources = [ "main.rs" ]
98     bindgen_output = get_target_outputs(":c_lib_bindgen")
99     inputs = bindgen_output
100     rustenv = [ "BINDGEN_RS_FILE=" + rebase_path(bindgen_output[0]) ]
101     crate_root = "main.rs"
102   }
103   ```
104
105**Verification**
106
107![bindgen_test](./figures/bindgen_test.png)
108
109
110## Using CXX
111
112### Calling Rust Interfaces by C++
113
1141. In the Rust **lib.rs** file, add the C++ interfaces to be called in **mod ffi**, and add the interfaces in **extern "Rust"** to expose them to C++.
115
116   ```rust
117   //! #[cxx::bridge]
118   #[cxx::bridge]
119   mod ffi{
120       #![allow(dead_code)]
121       #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
122       struct Shared {
123           z: usize,
124       }
125       extern "Rust"{
126           fn print_message_in_rust();
127           fn r_return_primitive() -> usize;
128           fn r_return_shared() -> Shared;
129           fn r_return_rust_string() -> String;
130           fn r_return_sum(_: usize, _: usize) -> usize;
131       }
132   }
133
134   fn print_message_in_rust(){
135       println!("Here is a test for cpp call Rust.");
136   }
137   fn r_return_shared() -> ffi::Shared {
138       println!("Here is a message from Rust,test for ffi::Shared:");
139       ffi::Shared { z: 1996 }
140   }
141   fn r_return_primitive() -> usize {
142       println!("Here is a message from Rust,test for usize:");
143       1997
144   }
145   fn r_return_rust_string() -> String {
146       println!("Here is a message from Rust,test for String");
147       "Hello World!".to_owned()
148   }
149   fn r_return_sum(n1: usize, n2: usize) -> usize {
150       println!("Here is a message from Rust,test for {} + {} is:",n1 ,n2);
151       n1 + n2
152   }
153
154   ```
155
1562. Include **lib.rs.h** (converted from **lib.rs** by the CXX tool) in C++ code.
157
158   ```c++
159   #include <iostream>
160   #include "build/rust/tests/test_cxx/src/lib.rs.h"
161
162   int main(int argc, const char* argv[])
163   {
164       int a = 2021;
165       int b = 4;
166       print_message_in_rust();
167       std::cout << r_return_primitive() << std::endl;
168       std::cout << r_return_shared().z << std::endl;
169       std::cout << std::string(r_return_rust_string()) << std::endl;
170       std::cout << r_return_sum(a, b) << std::endl;
171       return 0;
172   }
173   ```
174
1753. Create the **BUILD.gn** file. The underlying rust_cxx calls the CXX tool to convert the **lib.rs** file into **lib.rs.h** and **lib.rs.cc**. **ohos_rust_static_ffi** implements compilation of the Rust source code, and **ohos_executable** implements compilation of the C++ code.
176
177   ```
178   import("//build/ohos.gni")
179   import("//build/templates/rust/rust_cxx.gni")
180
181   rust_cxx("test_cxx_exe_gen") {
182       sources = [ "src/lib.rs" ]
183   }
184
185   ohos_rust_static_ffi("test_cxx_examp_rust") {
186       sources = [ "src/lib.rs" ]
187       deps = [ "//build/rust:cxx_rustdeps" ]
188   }
189
190   ohos_executable("test_cxx_exe") {
191       sources = [ "main.cpp" ]
192       sources += get_target_outputs(":test_cxx_exe_gen")
193
194       include_dirs = [ "${target_gen_dir}" ]
195       deps = [
196       ":test_cxx_examp_rust",
197       ":test_cxx_exe_gen",
198       "//build/rust:cxx_cppdeps",
199       ]
200   }
201   ```
202
203**Verification**
204![cpp_call_rust](./figures/cpp_call_rust.png)
205
206
207### Calling C++ by Rust
208
2091. Create the header file **client_blobstore.h**.
210
211   ```c++
212   #ifndef BUILD_RUST_TESTS_CLIENT_BLOBSTORE_H
213   #define BUILD_RUST_TESTS_CLIENT_BLOBSTORE_H
214   #include <memory>
215   #include "third_party/rust/cxx/include/cxx.h"
216
217   namespace nsp_org {
218   namespace nsp_blobstore {
219   struct MultiBufs;
220   struct Metadata_Blob;
221
222   class client_blobstore {
223   public:
224       client_blobstore();
225       uint64_t put_buf(MultiBufs &buf) const;
226       void add_tag(uint64_t blobid, rust::Str add_tag) const;
227       Metadata_Blob get_metadata(uint64_t blobid) const;
228
229   private:
230       class impl;
231       std::shared_ptr<impl> impl;
232   };
233
234   std::unique_ptr<client_blobstore> blobstore_client_new();
235   } // namespace nsp_blobstore
236   } // namespace nsp_org
237   #endif
238   ```
239
2402. Create the **client_blobstore.cpp** file.
241
242   ```c++
243   #include <algorithm>
244   #include <functional>
245   #include <set>
246   #include <string>
247   #include <unordered_map>
248   #include "src/main.rs.h"
249   #include "build/rust/tests/test_cxx_rust/include/client_blobstore.h"
250
251   namespace nsp_org {
252   namespace nsp_blobstore {
253   // Toy implementation of an in-memory nsp_blobstore.
254   //
255   // The real implementation of client_blobstore could be a large complex C++
256   // library.
257   class client_blobstore::impl {
258       friend client_blobstore;
259       using Blob = struct {
260           std::string data;
261           std::set<std::string> tags;
262       };
263       std::unordered_map<uint64_t, Blob> blobs;
264   };
265
266   client_blobstore::client_blobstore() : impl(new class client_blobstore::impl) {}
267
268   // Upload a new blob and return a blobid that serves as a handle to the blob.
269   uint64_t client_blobstore::put_buf(MultiBufs &buf) const
270   {
271       std::string contents;
272
273       // Traverse the caller's res_chunk iterator.
274       //
275       // In reality there might be sophisticated batching of chunks and/or parallel
276       // upload implemented by the nsp_blobstore's C++ client.
277       while (true) {
278           auto res_chunk = next_chunk(buf);
279           if (res_chunk.size() == 0) {
280           break;
281           }
282           contents.append(reinterpret_cast<const char *>(res_chunk.data()), res_chunk.size());
283       }
284
285       // Insert into map and provide caller the handle.
286       auto res = std::hash<std::string> {} (contents);
287       impl->blobs[res] = {std::move(contents), {}};
288       return res;
289   }
290
291   // Add add_tag to an existing blob.
292   void client_blobstore::add_tag(uint64_t blobid, rust::Str add_tag) const
293   {
294       impl->blobs[blobid].tags.emplace(add_tag);
295   }
296
297   // Retrieve get_metadata about a blob.
298   Metadata_Blob client_blobstore::get_metadata(uint64_t blobid) const
299   {
300       Metadata_Blob get_metadata {};
301       auto blob = impl->blobs.find(blobid);
302       if (blob != impl->blobs.end()) {
303           get_metadata.size = blob->second.data.size();
304           std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),
305               [&](auto &t) { get_metadata.tags.emplace_back(t); });
306       }
307       return get_metadata;
308   }
309
310   std::unique_ptr<client_blobstore> blobstore_client_new()
311   {
312       return std::make_unique<client_blobstore>();
313   }
314   } // namespace nsp_blobstore
315   } // namespace nsp_org
316
317   ```
318
3193. In **ffi** of the **main.rs** file, use the macro **includes!** to import the header file **client_blobstore.h**. Then, the **main()** function of Rust can call the C++ interfaces in ffi mode.
320
321   ```rust
322   //! test_cxx_rust
323   #[cxx::bridge(namespace = "nsp_org::nsp_blobstore")]
324   mod ffi {
325       // Shared structs with fields visible to both languages.
326       struct Metadata_Blob {
327           size: usize,
328           tags: Vec<String>,
329       }
330
331       // Rust types and signatures exposed to C++.
332       extern "Rust" {
333           type MultiBufs;
334
335           fn next_chunk(buf: &mut MultiBufs) -> &[u8];
336       }
337
338       // C++ types and signatures exposed to Rust.
339       unsafe extern "C++" {
340           include!("build/rust/tests/test_cxx_rust/include/client_blobstore.h");
341
342           type client_blobstore;
343
344           fn blobstore_client_new() -> UniquePtr<client_blobstore>;
345           fn put_buf(&self, parts: &mut MultiBufs) -> u64;
346           fn add_tag(&self, blobid: u64, add_tag: &str);
347           fn get_metadata(&self, blobid: u64) -> Metadata_Blob;
348       }
349   }
350
351   // An iterator over contiguous chunks of a discontiguous file object.
352   //
353   // Toy implementation uses a Vec<Vec<u8>> but in reality this might be iterating
354   // over some more complex Rust data structure like a rope, or maybe loading
355   // chunks lazily from somewhere.
356   /// pub struct MultiBufs
357   pub struct MultiBufs {
358       chunks: Vec<Vec<u8>>,
359       pos: usize,
360   }
361   /// pub fn next_chunk
362   pub fn next_chunk(buf: &mut MultiBufs) -> &[u8] {
363       let next = buf.chunks.get(buf.pos);
364       buf.pos += 1;
365       next.map_or(&[], Vec::as_slice)
366   }
367
368   /// fn main()
369   fn main() {
370       let client = ffi::blobstore_client_new();
371
372       // Upload a blob.
373       let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];
374       let mut buf = MultiBufs { chunks, pos: 0 };
375       let blobid = client.put_buf(&mut buf);
376       println!("This is a test for Rust call cpp:");
377       println!("blobid = {}", blobid);
378
379       // Add a add_tag.
380       client.add_tag(blobid, "rust");
381
382       // Read back the tags.
383       let get_metadata = client.get_metadata(blobid);
384       println!("tags = {:?}", get_metadata.tags);
385   }
386   ```
387
3884. Create the **BUILD.gn** file. Use CXX to convert **main.rs** into **lib.rs.h** and **lib.rs.cc**, which are used as the source code of **test_cxx_rust_staticlib**. Compile Rust **main.rs**, and add the dependency **test_cxx_rust_staticlib**.
389
390   ```
391   import("//build/ohos.gni")
392
393   rust_cxx("test_cxx_rust_gen") {
394     sources = [ "src/main.rs" ]
395   }
396
397   ohos_static_library("test_cxx_rust_staticlib") {
398     sources = [ "src/client_blobstore.cpp" ]
399     sources += get_target_outputs(":test_cxx_rust_gen")
400     include_dirs = [
401       "${target_gen_dir}",
402       "//third_party/rust/cxx/v1/crate/include",
403       "include",
404     ]
405     deps = [
406       ":test_cxx_rust_gen",
407       "//build/rust:cxx_cppdeps",
408     ]
409   }
410
411   ohos_rust_executable("test_cxx_rust") {
412     sources = [ "src/main.rs" ]
413     deps = [
414       ":test_cxx_rust_staticlib",
415       "//build/rust:cxx_rustdeps",
416     ]
417   }
418   ```
419
420**Verification**
421![rust_call_cpp](./figures/rust_call_cpp.png)
422