diff --git a/book/src/build/cargo.md b/book/src/build/cargo.md index 82ccfb500..f5e0c8ab6 100644 --- a/book/src/build/cargo.md +++ b/book/src/build/cargo.md @@ -144,6 +144,49 @@ manifest key][links]* in the Cargo reference. [links]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key +## Features + +CXX provides features to enable additional functionality such as compiling +the CXX lib with a different standard. + +Features are enabled on the CXX crate for Cargo-based setups, and with compiler +options for non-Cargo setups. + +The following features are available, see `[features]` section in [Cargo.toml](https://github.com/dtolnay/cxx/blob/master/Cargo.toml) for a full list: + + + + +
featurecompiler optiondescription
c++14-std=c++14 (gcc, clang), /std:c++14 (msvc)Compile CXX lib with c++14
c++17-std=c++17 (gcc, clang), /std:c++17 (msvc)Compile CXX lib with c++17
+ +## Additional C++ standard features +Some addition APIs are available if compiling your code with a newer C++ standard. + +Please note, that these additional APIs are automatically enabled in the `cxx.h` +header if your code is compiled with the required minimal C++ standard. They do +not depend on building the actual CXX lib against the newer standard at this time. + + + + +
Minimal C++ standardDescription
c++17Enables additional `string_view` APIs for `rust::str` and `rust::String`
+ +Example to e.g. enable the `string_view` APIs for your code, build at least with C++17: +```rust,noplayground +// build.rs + +fn main() { + cxx_build::bridge("src/main.rs") // returns a cc::Build + .file("src/demo.cc") + .flag_if_supported("-std=c++17") + .compile("cxxbridge-demo"); + + println!("cargo:rerun-if-changed=src/main.rs"); + println!("cargo:rerun-if-changed=src/demo.cc"); + println!("cargo:rerun-if-changed=include/demo.h"); +} +``` +


# Advanced features diff --git a/include/cxx.h b/include/cxx.h index 86242335f..c6b70060e 100644 --- a/include/cxx.h +++ b/include/cxx.h @@ -15,6 +15,45 @@ #include #endif +#ifdef CXXBRIDGE_HAS_STRING_VIEW +#error "string_view gets auto-detected" +#endif + +// clang-format off +// detect if string_view supported (C++17 required) +#ifdef __has_include + #if __has_include() + // gcc >= 9, clang >= 9, msvc >= 19.22 + #include + #if __cpp_lib_string_view >= 201603L + #define CXXBRIDGE_HAS_STRING_VIEW + #endif + #else + // no include + #if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201603L + // gcc: 8, clang: 5 - 8, msvc: 19.15 - 19.21 + #define CXXBRIDGE_HAS_STRING_VIEW + #else + // only include if compiled with c++17 + #if (__GNUC__ >= 7 && __cplusplus >= 201703L) || (_MSVC_LANG >= 201703L) + // gcc: 7, msvc: 19.14 + #define CXXBRIDGE_HAS_STRING_VIEW + #endif + #endif + #endif +#else + // no __has_include + #if _MSC_VER >= 1910L && _MSVC_LANG > 201402L + // msvc: 19.10 requires c++latest (!) + #define CPPBRIDGE_HAS_STRING_VIEW + #endif +#endif +// clang-format on + +#ifdef CXXBRIDGE_HAS_STRING_VIEW +#include +#endif + namespace rust { inline namespace cxxbridge1 { @@ -34,6 +73,9 @@ class String final { String(String &&) noexcept; ~String() noexcept; +#ifdef CXXBRIDGE_HAS_STRING_VIEW + String(std::string_view sv) : String(sv.data(), sv.length()) {} +#endif String(const std::string &); String(const char *); String(const char *, size_t); @@ -42,6 +84,11 @@ class String final { String &operator=(String &&) noexcept; explicit operator std::string() const; +#ifdef CXXBRIDGE_HAS_STRING_VIEW + explicit operator std::string_view() const noexcept { + return {this->data(), this->size()}; + } +#endif // Note: no null terminator. const char *data() const noexcept; @@ -71,6 +118,9 @@ class String final { class Str final { public: Str() noexcept; +#ifdef CXXBRIDGE_HAS_STRING_VIEW + Str(std::string_view sv) : Str(sv.data(), sv.length()) {} +#endif Str(const std::string &); Str(const char *); Str(const char *, size_t); @@ -78,6 +128,11 @@ class Str final { Str &operator=(const Str &) noexcept = default; explicit operator std::string() const; +#ifdef CXXBRIDGE_HAS_STRING_VIEW + explicit operator std::string_view() const noexcept { + return {this->data(), this->size()}; + } +#endif // Note: no null terminator. const char *data() const noexcept; diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs index 41f129a9a..e53a3ad3c 100644 --- a/tests/ffi/lib.rs +++ b/tests/ffi/lib.rs @@ -216,8 +216,10 @@ pub mod ffi { fn r_take_ref_r(r: &R); fn r_take_ref_c(c: &C); fn r_take_str(s: &str); + fn r_take_empty_str(s: &str); fn r_take_slice_char(s: &[c_char]); fn r_take_rust_string(s: String); + fn r_take_empty_rust_string(s: String); fn r_take_unique_ptr_string(s: UniquePtr); fn r_take_ref_vector(v: &CxxVector); fn r_take_ref_empty_vector(v: &CxxVector); @@ -470,10 +472,18 @@ fn r_take_str(s: &str) { assert_eq!(s, "2020"); } +fn r_take_empty_str(s: &str) { + assert_eq!(s.len(), 0); +} + fn r_take_rust_string(s: String) { assert_eq!(s, "2020"); } +fn r_take_empty_rust_string(s: String) { + assert_eq!(s.len(), 0); +} + fn r_take_slice_char(s: &[c_char]) { assert_eq!(s.len(), 5); let s = cast::c_char_to_unsigned(s); diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc index 7cd84b814..4889ef022 100644 --- a/tests/ffi/tests.cc +++ b/tests/ffi/tests.cc @@ -624,8 +624,24 @@ extern "C" const char *cxx_run_test() noexcept { r_take_unique_ptr(std::unique_ptr(new C{2020})); r_take_ref_c(C{2020}); r_take_str(rust::Str("2020")); + r_take_empty_str(rust::Str{""}); + r_take_empty_str(rust::Str{nullptr, 0}); +#ifdef CXXBRIDGE_HAS_STRING_VIEW + r_take_str(std::string_view{"2020"}); + r_take_empty_str(std::string_view{}); + r_take_empty_str(std::string_view{""}); + ASSERT(static_cast(rust::Str{"2020"}) == "2020"); +#endif r_take_slice_char(rust::Slice(SLICE_DATA, sizeof(SLICE_DATA))); r_take_rust_string(rust::String("2020")); + r_take_empty_rust_string(rust::String{""}); + r_take_empty_rust_string(rust::String{nullptr, 0}); +#ifdef CXXBRIDGE_HAS_STRING_VIEW + r_take_rust_string(std::string_view{"2020"}); + r_take_empty_rust_string(std::string_view{}); + r_take_empty_rust_string(std::string_view{""}); + ASSERT(static_cast(rust::String{"2020"}) == "2020"); +#endif r_take_unique_ptr_string( std::unique_ptr(new std::string("2020"))); r_take_ref_vector(std::vector{20, 2, 0});