The Rust binding of std::string is called CxxString
. See the link for
documentation of the Rust API.
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.
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.
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());
}
#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 () ;
#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}});
}