133d722a9Sopenharmony_ci{{#title std::string — Rust ♡ C++}}
233d722a9Sopenharmony_ci# std::string
333d722a9Sopenharmony_ci
433d722a9Sopenharmony_ciThe Rust binding of std::string is called **[`CxxString`]**. See the link for
533d722a9Sopenharmony_cidocumentation of the Rust API.
633d722a9Sopenharmony_ci
733d722a9Sopenharmony_ci[`CxxString`]: https://docs.rs/cxx/*/cxx/struct.CxxString.html
833d722a9Sopenharmony_ci
933d722a9Sopenharmony_ci### Restrictions:
1033d722a9Sopenharmony_ci
1133d722a9Sopenharmony_ciRust code can never obtain a CxxString by value. C++'s string requires a move
1233d722a9Sopenharmony_ciconstructor and may hold internal pointers, which is not compatible with Rust's
1333d722a9Sopenharmony_cimove behavior. Instead in Rust code we will only ever look at a CxxString
1433d722a9Sopenharmony_cithrough a reference or smart pointer, as in &CxxString or Pin\<&mut CxxString\>
1533d722a9Sopenharmony_cior UniquePtr\<CxxString\>.
1633d722a9Sopenharmony_ci
1733d722a9Sopenharmony_ciIn order to construct a CxxString on the stack from Rust, you must use the
1833d722a9Sopenharmony_ci[`let_cxx_string!`] macro which will pin the string properly. The code below
1933d722a9Sopenharmony_ciuses this in one place, and the link covers the syntax.
2033d722a9Sopenharmony_ci
2133d722a9Sopenharmony_ci[`let_cxx_string!`]: https://docs.rs/cxx/*/cxx/macro.let_cxx_string.html
2233d722a9Sopenharmony_ci
2333d722a9Sopenharmony_ci## Example
2433d722a9Sopenharmony_ci
2533d722a9Sopenharmony_ciThis example uses C++17's std::variant to build a toy JSON type. JSON can hold
2633d722a9Sopenharmony_civarious types including strings, and JSON's object type is a map with string
2733d722a9Sopenharmony_cikeys. The example demonstrates Rust indexing into one of those maps.
2833d722a9Sopenharmony_ci
2933d722a9Sopenharmony_ci```rust,noplayground
3033d722a9Sopenharmony_ci// src/main.rs
3133d722a9Sopenharmony_ci
3233d722a9Sopenharmony_ciuse cxx::let_cxx_string;
3333d722a9Sopenharmony_ci
3433d722a9Sopenharmony_ci#[cxx::bridge]
3533d722a9Sopenharmony_cimod ffi {
3633d722a9Sopenharmony_ci    unsafe extern "C++" {
3733d722a9Sopenharmony_ci        include!("example/include/json.h");
3833d722a9Sopenharmony_ci
3933d722a9Sopenharmony_ci        #[cxx_name = "json"]
4033d722a9Sopenharmony_ci        type Json;
4133d722a9Sopenharmony_ci        #[cxx_name = "object"]
4233d722a9Sopenharmony_ci        type Object;
4333d722a9Sopenharmony_ci
4433d722a9Sopenharmony_ci        fn isNull(self: &Json) -> bool;
4533d722a9Sopenharmony_ci        fn isNumber(self: &Json) -> bool;
4633d722a9Sopenharmony_ci        fn isString(self: &Json) -> bool;
4733d722a9Sopenharmony_ci        fn isArray(self: &Json) -> bool;
4833d722a9Sopenharmony_ci        fn isObject(self: &Json) -> bool;
4933d722a9Sopenharmony_ci
5033d722a9Sopenharmony_ci        fn getNumber(self: &Json) -> f64;
5133d722a9Sopenharmony_ci        fn getString(self: &Json) -> &CxxString;
5233d722a9Sopenharmony_ci        fn getArray(self: &Json) -> &CxxVector<Json>;
5333d722a9Sopenharmony_ci        fn getObject(self: &Json) -> &Object;
5433d722a9Sopenharmony_ci
5533d722a9Sopenharmony_ci        #[cxx_name = "at"]
5633d722a9Sopenharmony_ci        fn get<'a>(self: &'a Object, key: &CxxString) -> &'a Json;
5733d722a9Sopenharmony_ci
5833d722a9Sopenharmony_ci        fn load_config() -> UniquePtr<Json>;
5933d722a9Sopenharmony_ci    }
6033d722a9Sopenharmony_ci}
6133d722a9Sopenharmony_ci
6233d722a9Sopenharmony_cifn main() {
6333d722a9Sopenharmony_ci    let config = ffi::load_config();
6433d722a9Sopenharmony_ci
6533d722a9Sopenharmony_ci    let_cxx_string!(key = "name");
6633d722a9Sopenharmony_ci    println!("{}", config.getObject().get(&key).getString());
6733d722a9Sopenharmony_ci}
6833d722a9Sopenharmony_ci```
6933d722a9Sopenharmony_ci
7033d722a9Sopenharmony_ci```cpp
7133d722a9Sopenharmony_ci// include/json.h
7233d722a9Sopenharmony_ci
7333d722a9Sopenharmony_ci#pragma once
7433d722a9Sopenharmony_ci#include <map>
7533d722a9Sopenharmony_ci#include <memory>
7633d722a9Sopenharmony_ci#include <string>
7733d722a9Sopenharmony_ci#include <variant>
7833d722a9Sopenharmony_ci#include <vector>
7933d722a9Sopenharmony_ci
8033d722a9Sopenharmony_ciclass json final {
8133d722a9Sopenharmony_cipublic:
8233d722a9Sopenharmony_ci  static const json null;
8333d722a9Sopenharmony_ci  using number = double;
8433d722a9Sopenharmony_ci  using string = std::string;
8533d722a9Sopenharmony_ci  using array = std::vector<json>;
8633d722a9Sopenharmony_ci  using object = std::map<string, json>;
8733d722a9Sopenharmony_ci
8833d722a9Sopenharmony_ci  json() noexcept = default;
8933d722a9Sopenharmony_ci  json(const json &) = default;
9033d722a9Sopenharmony_ci  json(json &&) = default;
9133d722a9Sopenharmony_ci  template <typename... T>
9233d722a9Sopenharmony_ci  json(T &&...value) : value(std::forward<T>(value)...) {}
9333d722a9Sopenharmony_ci
9433d722a9Sopenharmony_ci  bool isNull() const;
9533d722a9Sopenharmony_ci  bool isNumber() const;
9633d722a9Sopenharmony_ci  bool isString() const;
9733d722a9Sopenharmony_ci  bool isArray() const;
9833d722a9Sopenharmony_ci  bool isObject() const;
9933d722a9Sopenharmony_ci
10033d722a9Sopenharmony_ci  number getNumber() const;
10133d722a9Sopenharmony_ci  const string &getString() const;
10233d722a9Sopenharmony_ci  const array &getArray() const;
10333d722a9Sopenharmony_ci  const object &getObject() const;
10433d722a9Sopenharmony_ci
10533d722a9Sopenharmony_ciprivate:
10633d722a9Sopenharmony_ci  std::variant<std::monostate, number, string, array, object> value;
10733d722a9Sopenharmony_ci};
10833d722a9Sopenharmony_ci
10933d722a9Sopenharmony_ciusing object = json::object;
11033d722a9Sopenharmony_ci
11133d722a9Sopenharmony_cistd::unique_ptr<json> load_config();
11233d722a9Sopenharmony_ci```
11333d722a9Sopenharmony_ci
11433d722a9Sopenharmony_ci```cpp
11533d722a9Sopenharmony_ci// include/json.cc
11633d722a9Sopenharmony_ci
11733d722a9Sopenharmony_ci#include "example/include/json.h"
11833d722a9Sopenharmony_ci#include <initializer_list>
11933d722a9Sopenharmony_ci#include <utility>
12033d722a9Sopenharmony_ci
12133d722a9Sopenharmony_ciconst json json::null{};
12233d722a9Sopenharmony_cibool json::isNull() const { return std::holds_alternative<std::monostate>(value); }
12333d722a9Sopenharmony_cibool json::isNumber() const { return std::holds_alternative<number>(value); }
12433d722a9Sopenharmony_cibool json::isString() const { return std::holds_alternative<string>(value); }
12533d722a9Sopenharmony_cibool json::isArray() const { return std::holds_alternative<array>(value); }
12633d722a9Sopenharmony_cibool json::isObject() const { return std::holds_alternative<object>(value); }
12733d722a9Sopenharmony_cijson::number json::getNumber() const { return std::get<number>(value); }
12833d722a9Sopenharmony_ciconst json::string &json::getString() const { return std::get<string>(value); }
12933d722a9Sopenharmony_ciconst json::array &json::getArray() const { return std::get<array>(value); }
13033d722a9Sopenharmony_ciconst json::object &json::getObject() const { return std::get<object>(value); }
13133d722a9Sopenharmony_ci
13233d722a9Sopenharmony_cistd::unique_ptr<json> load_config() {
13333d722a9Sopenharmony_ci  return std::make_unique<json>(
13433d722a9Sopenharmony_ci      std::in_place_type<json::object>,
13533d722a9Sopenharmony_ci      std::initializer_list<std::pair<const std::string, json>>{
13633d722a9Sopenharmony_ci          {"name", "cxx-example"},
13733d722a9Sopenharmony_ci          {"edition", 2018.},
13833d722a9Sopenharmony_ci          {"repository", json::null}});
13933d722a9Sopenharmony_ci}
14033d722a9Sopenharmony_ci```
141