cxx icon indicating copy to clipboard operation
cxx copied to clipboard

Returning `CxxString` from Rust to C++

Open FireFragment opened this issue 1 year ago • 6 comments

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.

FireFragment avatar Apr 06 '24 11:04 FireFragment

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.

zambony avatar May 01 '24 16:05 zambony

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

FireFragment avatar May 10 '24 18:05 FireFragment

I've also just encountered this issue. Are there any updates to do this properly instead of using out parameters?

izolyomi avatar Jul 22 '24 09:07 izolyomi

@izolyomi: I've also just encountered this issue. Are there any updates to do this properly instead of using out parameters?

I managed to get around this by creating function on the C++ side for constructing new empty string and writing to it on the Rust side.

Rust:

fn str_test() -> UniquePtr<CxxString> {
    let mut s = ffi::get_empty_string();
    s.pin_mut().push_str("Hello from str_test");
    s
}

C++:

#include <string>
#include <memory>

std::unique_ptr<std::string> get_empty_string() {
    return std::make_unique<std::string>(std::string(""));
}

But this should really be supported by the library.

FireFragment avatar Jul 22 '24 19:07 FireFragment

Thank you for the detailed example. So far I was exposing Rust to C++ but had nothing in the other direction yet. I'll consider if using output parameters with C++ string, returning Rust string or involving a C++ utility function is better in my case.

izolyomi avatar Jul 24 '24 11:07 izolyomi