4 ms·
std::string and std::vector are not things that can exist by value in Rust, because it's possible for them to be implemented using internal pointers which are i
by dtolnay 6y ago
std::string and std::vector are not things that can exist by value in Rust, because it's possible for them to be implemented using internal pointers which are incompatible with how Rust does move semantics.
Some easy and efficient ways to return a vector (or similarly string) from Rust to C++ which do not involve moving it around in Rust:
1. A signature like `fn f() -> UniquePtr<CxxVector<T>>` i.e. a return type of std::unique_ptr<std::vector<T>>, which is trivially Rust-movable
2. A signature like `fn f(out: Pin<&mut CxxVector<T>>)` with a stack-allocated empty vector constructed by C++ for your Rust to write the elements into, which is pinned and never moved by Rust
3. A signature like `fn f() -> Vec<T>` returning a Rust vector i.e. rust::Vec<T> on the C++ side; rust::Vec has a fleshed out API in C++ allowing it to be used like a C++ collection, with iteration and indexing etc
- zozbot234 6y agoThere is a 'transfer' crate adding support for custom non-trivial moves of pinned objects, ala C++ move semantics. AIUI, support for "in-place" objects would also be needed, which is not yet part of Rust but there are plans to add it to the language.
- boris 6y agoI wouldn't call (1) efficient, especially for std::string which itself might omit a dynamic allocation due to small string optimization.
- yazaddaruvala 6y agoIt might not be truly zero-cost, but as a safe FFI it is efficient. Meanwhile, does it really matter? For any C++ project to integrate Rust the motivation would have to be: - The Rust code is specifically needed for the long-term. - The FFI-boundary is temporary (i.e. always moving) as more of the C++ is migrated to Rust. Ideally, checkpointing the migration at optimal FFI boundaries. As such, any "in-efficient" checkpoint should be cleaned up "soon", and dev speed is more valuable from an FFI than perfectly zero-cost. - If for any reason a C++ project integrates Rust in a way that is permanently through an FFI (I can't understand why - maybe there is a really good crate or something), then the development costs to use the unsafe non-ergonomic FFI are worth the effort for this unique situation. Very similar logic applies for any Rust project that integrates with a C++ library for the long term. If the team just needs a C++ library for the short term, the efficiency likely also doesn't matter much.
- htfy96 6y agoThe motivations in claims unfortunately don't apply to my case: 1. FFI boundary will likely to exist forever in a milions-of-line C++ codebase, especially when the behavior of this system is not possible to be formally specified / tested (e.g., depending on an unknown external system, or some behaviors specified in hundreds of pages "specs" full of jargons) 2. In the above case, when C++ code dominates the FFI cost would be signified as you need to call C++ routines frequently to achieve stuffs. For example, when every struct has some methods returning std::string the std::string needs to be targeted. In our case, the primary motivation of Rust isn't its safety - we just use it for syntax sugars and ease of extensions (with proc macros).
- yazaddaruvala 6y ago> In our case, the primary motivation of Rust isn't its safety - we just use it for syntax sugars and ease of extensions (with proc macros). Fair enough, but then "CXX — ***safe*** FFI between Rust and C++" (emphasis mine) is just not the right library for you, and that is totally ok. It has a niche and your usecase is different, both the library and your usecase are in "the right". > The motivations in claims unfortunately don't apply to my case: Is this situation different than what I called out earlier? > - If for any reason a C++ project integrates Rust in a way that is permanently through an FFI (I can't understand why - maybe there is a really good crate or something), then the development costs to use the unsafe non-ergonomic FFI are worth the effort for this unique situation.
- dtolnay 6y ago> If for any reason a C++ project integrates Rust in a way that is permanently through an FFI, then the development costs to use the unsafe non-ergonomic FFI are worth the effort for this unique situation. I don't follow this train of thought; could you elaborate? Why would I want more unsafe code in my project because it's going to be there for longer? If anything I'd want the opposite -- longevity of the unsafe code being a reason against wanting more of it sitting around. FWIW the primary use case of CXX in my work codebase is in long term hybrid-Rust-C++ projects in which dozens of libraries using CXX (in both directions) are going to be around for many years.