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:
+
+feature | compiler option | description |
+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++ standard | Description |
+c++17 | Enables 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});