| {{#title std::string — Rust ♡ C++}} |
| # std::string |
| |
| The Rust binding of std::string is called **[`CxxString`]**. See the link for |
| documentation of the Rust API. |
| |
| [`CxxString`]: https://docs.rs/cxx/*/cxx/struct.CxxString.html |
| |
| ### Restrictions: |
| |
| Rust code can never obtain a CxxString by value. C++'s string requires a move |
| constructor and may hold internal pointers, which is not compatible with Rust's |
| move behavior. Instead in Rust code we will only ever look at a CxxString |
| through a reference or smart pointer, as in &CxxString or Pin\<&mut CxxString\> |
| or UniquePtr\<CxxString\>. |
| |
| In order to construct a CxxString on the stack from Rust, you must use the |
| [`let_cxx_string!`] macro which will pin the string properly. The code below |
| uses this in one place, and the link covers the syntax. |
| |
| [`let_cxx_string!`]: https://docs.rs/cxx/*/cxx/macro.let_cxx_string.html |
| |
| ## Example |
| |
| This example uses C++17's std::variant to build a toy JSON type. JSON can hold |
| various types including strings, and JSON's object type is a map with string |
| keys. The example demonstrates Rust indexing into one of those maps. |
| |
| ```rust,noplayground |
| // src/main.rs |
| |
| use cxx::let_cxx_string; |
| |
| #[cxx::bridge] |
| mod ffi { |
| unsafe extern "C++" { |
| include!("example/include/json.h"); |
| |
| #[cxx_name = "json"] |
| type Json; |
| #[cxx_name = "object"] |
| type Object; |
| |
| fn isNull(self: &Json) -> bool; |
| fn isNumber(self: &Json) -> bool; |
| fn isString(self: &Json) -> bool; |
| fn isArray(self: &Json) -> bool; |
| fn isObject(self: &Json) -> bool; |
| |
| fn getNumber(self: &Json) -> f64; |
| fn getString(self: &Json) -> &CxxString; |
| fn getArray(self: &Json) -> &CxxVector<Json>; |
| fn getObject(self: &Json) -> &Object; |
| |
| #[cxx_name = "at"] |
| fn get<'a>(self: &'a Object, key: &CxxString) -> &'a Json; |
| |
| fn load_config() -> UniquePtr<Json>; |
| } |
| } |
| |
| fn main() { |
| let config = ffi::load_config(); |
| |
| let_cxx_string!(key = "name"); |
| println!("{}", config.getObject().get(&key).getString()); |
| } |
| ``` |
| |
| ```cpp |
| // include/json.h |
| |
| #pragma once |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <variant> |
| #include <vector> |
| |
| class json final { |
| public: |
| static const json null; |
| using number = double; |
| using string = std::string; |
| using array = std::vector<json>; |
| using object = std::map<string, json>; |
| |
| json() noexcept = default; |
| json(const json &) = default; |
| json(json &&) = default; |
| template <typename... T> |
| json(T &&...value) : value(std::forward<T>(value)...) {} |
| |
| bool isNull() const; |
| bool isNumber() const; |
| bool isString() const; |
| bool isArray() const; |
| bool isObject() const; |
| |
| number getNumber() const; |
| const string &getString() const; |
| const array &getArray() const; |
| const object &getObject() const; |
| |
| private: |
| std::variant<std::monostate, number, string, array, object> value; |
| }; |
| |
| using object = json::object; |
| |
| std::unique_ptr<json> load_config(); |
| ``` |
| |
| ```cpp |
| // include/json.cc |
| |
| #include "example/include/json.h" |
| #include <initializer_list> |
| #include <utility> |
| |
| const json json::null{}; |
| bool json::isNull() const { return std::holds_alternative<std::monostate>(value); } |
| bool json::isNumber() const { return std::holds_alternative<number>(value); } |
| bool json::isString() const { return std::holds_alternative<string>(value); } |
| bool json::isArray() const { return std::holds_alternative<array>(value); } |
| bool json::isObject() const { return std::holds_alternative<object>(value); } |
| json::number json::getNumber() const { return std::get<number>(value); } |
| const json::string &json::getString() const { return std::get<string>(value); } |
| const json::array &json::getArray() const { return std::get<array>(value); } |
| const json::object &json::getObject() const { return std::get<object>(value); } |
| |
| std::unique_ptr<json> load_config() { |
| return std::make_unique<json>( |
| std::in_place_type<json::object>, |
| std::initializer_list<std::pair<const std::string, json>>{ |
| {"name", "cxx-example"}, |
| {"edition", 2021.}, |
| {"repository", json::null}}); |
| } |
| ``` |