dtolnay / cxx

Safe interop between Rust and C++
https://cxx.rs
Apache License 2.0
5.68k stars 320 forks source link

Returning `CxxString` from Rust to C++ #1339

Open FireFragment opened 3 months ago

FireFragment commented 3 months ago

Is it possible to construct CxxString on the Rust side and return it to the C++ side?

Returning Pin<&mut CxxString> doesn't work, because it's just a reference to local variable, which is destroyed at the end of the function:

fn hello<'a>() -> std::pin::Pin<&'a mut CxxString> {
    let_cxx_string!(name = "Hello from Rust string!");
    name // ERROR: returns a value referencing data owned by the current function
}

Returning UniquePtr<CxxString> doesn't work, because I'm not able to construct it:

fn hello2<'a>() -> cxx::UniquePtr<CxxString> {
    let_cxx_string!(name = "Hello from Rust string!");
    cxx::UniquePtr::new(*name) // ERROR: type mismatch resolving `<CxxString as ExternType>::Kind == Trivial`
                               //        expected `Trivial`, found `Opaque`
}

How can I do it? I want my generated bindings to use standard C++ structs such as std::string without needing the C++ users to deal with rust::String which they might not know and might not work with other C++ libraries.

zambony commented 2 months ago

In case you're still trying to do this, I wanted to do something similar, but I don't think it's possible. What I ended up doing instead is used an out parameter.

#[cxx::bridge(namespace = "rs")]
mod ffi {
    extern "Rust" {
        fn ask(response: Pin<&mut CxxString>);
    }
}

pub fn ask(response: Pin<&mut CxxString>) {
    response.push_str("Hi!!!");
}

It would be nice to return stack-allocated C++ types, though.

FireFragment commented 1 month ago

Thanks @zambony! That's a fine option when returning a single string, but it doesn't work well for strings inside classes/structs.