1{{#title std::string — Rust ♡ C++}} 2# std::string 3 4The Rust binding of std::string is called **[`CxxString`]**. See the link for 5documentation of the Rust API. 6 7[`CxxString`]: https://docs.rs/cxx/*/cxx/struct.CxxString.html 8 9### Restrictions: 10 11Rust code can never obtain a CxxString by value. C++'s string requires a move 12constructor and may hold internal pointers, which is not compatible with Rust's 13move behavior. Instead in Rust code we will only ever look at a CxxString 14through a reference or smart pointer, as in &CxxString or Pin\<&mut CxxString\> 15or UniquePtr\<CxxString\>. 16 17In order to construct a CxxString on the stack from Rust, you must use the 18[`let_cxx_string!`] macro which will pin the string properly. The code below 19uses this in one place, and the link covers the syntax. 20 21[`let_cxx_string!`]: https://docs.rs/cxx/*/cxx/macro.let_cxx_string.html 22 23## Example 24 25This example uses C++17's std::variant to build a toy JSON type. JSON can hold 26various types including strings, and JSON's object type is a map with string 27keys. The example demonstrates Rust indexing into one of those maps. 28 29```rust,noplayground 30// src/main.rs 31 32use cxx::let_cxx_string; 33 34#[cxx::bridge] 35mod ffi { 36 unsafe extern "C++" { 37 include!("example/include/json.h"); 38 39 #[cxx_name = "json"] 40 type Json; 41 #[cxx_name = "object"] 42 type Object; 43 44 fn isNull(self: &Json) -> bool; 45 fn isNumber(self: &Json) -> bool; 46 fn isString(self: &Json) -> bool; 47 fn isArray(self: &Json) -> bool; 48 fn isObject(self: &Json) -> bool; 49 50 fn getNumber(self: &Json) -> f64; 51 fn getString(self: &Json) -> &CxxString; 52 fn getArray(self: &Json) -> &CxxVector<Json>; 53 fn getObject(self: &Json) -> &Object; 54 55 #[cxx_name = "at"] 56 fn get<'a>(self: &'a Object, key: &CxxString) -> &'a Json; 57 58 fn load_config() -> UniquePtr<Json>; 59 } 60} 61 62fn main() { 63 let config = ffi::load_config(); 64 65 let_cxx_string!(key = "name"); 66 println!("{}", config.getObject().get(&key).getString()); 67} 68``` 69 70```cpp 71// include/json.h 72 73#pragma once 74#include <map> 75#include <memory> 76#include <variant> 77#include <vector> 78 79class json final { 80public: 81 static const json null; 82 using number = double; 83 using string = std::string; 84 using array = std::vector<json>; 85 using object = std::map<string, json>; 86 87 json() noexcept = default; 88 json(const json &) = default; 89 json(json &&) = default; 90 template <typename... T> 91 json(T &&...value) : value(std::forward<T>(value)...) {} 92 93 bool isNull() const; 94 bool isNumber() const; 95 bool isString() const; 96 bool isArray() const; 97 bool isObject() const; 98 99 number getNumber() const; 100 const string &getString() const; 101 const array &getArray() const; 102 const object &getObject() const; 103 104private: 105 std::variant<std::monostate, number, string, array, object> value; 106}; 107 108using object = json::object; 109 110std::unique_ptr<json> load_config(); 111``` 112 113```cpp 114// include/json.cc 115 116#include "example/include/json.h" 117#include <initializer_list> 118#include <utility> 119 120const json json::null{}; 121bool json::isNull() const { return std::holds_alternative<std::monostate>(value); } 122bool json::isNumber() const { return std::holds_alternative<number>(value); } 123bool json::isString() const { return std::holds_alternative<string>(value); } 124bool json::isArray() const { return std::holds_alternative<array>(value); } 125bool json::isObject() const { return std::holds_alternative<object>(value); } 126json::number json::getNumber() const { return std::get<number>(value); } 127const json::string &json::getString() const { return std::get<string>(value); } 128const json::array &json::getArray() const { return std::get<array>(value); } 129const json::object &json::getObject() const { return std::get<object>(value); } 130 131std::unique_ptr<json> load_config() { 132 return std::make_unique<json>( 133 std::in_place_type<json::object>, 134 std::initializer_list<std::pair<const std::string, json>>{ 135 {"name", "cxx-example"}, 136 {"edition", 2018.}, 137 {"repository", json::null}}); 138} 139``` 140