Skip to content

Commit 3044336

Browse files
committed
Add string_view API to str and String
1 parent 4092191 commit 3044336

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed

include/cxx.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,45 @@
1414
#include <basetsd.h>
1515
#endif
1616

17+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
18+
#error "string_view gets auto-detected"
19+
#endif
20+
21+
// clang-format off
22+
// detect if string_view supported (C++17 required)
23+
#ifdef __has_include
24+
#if __has_include(<version>)
25+
// gcc >= 9, clang >= 9, msvc >= 19.22
26+
#include <version>
27+
#if __cpp_lib_string_view >= 201603L
28+
#define CXXBRIDGE_HAS_STRING_VIEW
29+
#endif
30+
#else
31+
// no <version> include
32+
#if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201603L
33+
// gcc: 8, clang: 5 - 8, msvc: 19.15 - 19.21
34+
#define CXXBRIDGE_HAS_STRING_VIEW
35+
#else
36+
// only include if compiled with c++17
37+
#if (__GNUC__ >= 7 && __cplusplus >= 201703L) || (_MSVC_LANG >= 201703L)
38+
// gcc: 7, msvc: 19.14
39+
#define CXXBRIDGE_HAS_STRING_VIEW
40+
#endif
41+
#endif
42+
#endif
43+
#else
44+
// no __has_include
45+
#if _MSC_VER >= 1910L && _MSVC_LANG > 201402L
46+
// msvc: 19.10 requires c++latest (!)
47+
#define CPPBRIDGE_HAS_STRING_VIEW
48+
#endif
49+
#endif
50+
// clang-format on
51+
52+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
53+
#include <string_view>
54+
#endif
55+
1756
namespace rust {
1857
inline namespace cxxbridge1 {
1958

@@ -33,14 +72,21 @@ class String final {
3372
String(String &&) noexcept;
3473
~String() noexcept;
3574

75+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
76+
String(std::string_view);
77+
#else
3678
String(const std::string &);
79+
#endif
3780
String(const char *);
3881
String(const char *, size_t);
3982

4083
String &operator=(const String &) noexcept;
4184
String &operator=(String &&) noexcept;
4285

4386
explicit operator std::string() const;
87+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
88+
explicit operator std::string_view() const noexcept;
89+
#endif
4490

4591
// Note: no null terminator.
4692
const char *data() const noexcept;
@@ -60,13 +106,20 @@ class String final {
60106
class Str final {
61107
public:
62108
Str() noexcept;
109+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
110+
Str(std::string_view);
111+
#else
63112
Str(const std::string &);
113+
#endif
64114
Str(const char *);
65115
Str(const char *, size_t);
66116

67117
Str &operator=(const Str &) noexcept = default;
68118

69119
explicit operator std::string() const;
120+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
121+
explicit operator std::string_view() const noexcept;
122+
#endif
70123

71124
// Note: no null terminator.
72125
const char *data() const noexcept;

src/cxx.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ static void initString(String *self, const char *s, size_t len) {
7979
}
8080
}
8181

82+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
83+
String::String(std::string_view sv) : String(sv.data(), sv.length()) {}
84+
#else
8285
String::String(const std::string &s) { initString(this, s.data(), s.length()); }
86+
#endif
8387

8488
String::String(const char *s) {
8589
assert(s != nullptr);
@@ -114,6 +118,12 @@ String::operator std::string() const {
114118
return std::string(this->data(), this->size());
115119
}
116120

121+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
122+
String::operator std::string_view() const noexcept {
123+
return {this->data(), this->size()};
124+
}
125+
#endif
126+
117127
const char *String::data() const noexcept {
118128
return cxxbridge1$string$ptr(this);
119129
}
@@ -138,9 +148,13 @@ static void initStr(const char *ptr, size_t len) {
138148
}
139149
}
140150

151+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
152+
Str::Str(std::string_view sv) : Str(sv.data(), sv.length()) {}
153+
#else
141154
Str::Str(const std::string &s) : ptr(s.data()), len(s.length()) {
142155
initStr(this->ptr, this->len);
143156
}
157+
#endif
144158

145159
Str::Str(const char *s) : ptr(s), len(std::strlen(s)) {
146160
assert(s != nullptr);
@@ -158,6 +172,12 @@ Str::operator std::string() const {
158172
return std::string(this->data(), this->size());
159173
}
160174

175+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
176+
Str::operator std::string_view() const noexcept {
177+
return {this->data(), this->size()};
178+
}
179+
#endif
180+
161181
std::ostream &operator<<(std::ostream &os, const Str &s) {
162182
os.write(s.data(), s.size());
163183
return os;

tests/ffi/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,10 @@ pub mod ffi {
255255
fn r_take_ref_r(r: &R);
256256
fn r_take_ref_c(c: &C);
257257
fn r_take_str(s: &str);
258+
fn r_take_empty_str(s: &str);
258259
fn r_take_sliceu8(s: &[u8]);
259260
fn r_take_rust_string(s: String);
261+
fn r_take_empty_rust_string(s: String);
260262
fn r_take_unique_ptr_string(s: UniquePtr<CxxString>);
261263
fn r_take_ref_vector(v: &CxxVector<u8>);
262264
fn r_take_ref_empty_vector(v: &CxxVector<u64>);
@@ -439,10 +441,18 @@ fn r_take_str(s: &str) {
439441
assert_eq!(s, "2020");
440442
}
441443

444+
fn r_take_empty_str(s: &str) {
445+
assert_eq!(s.len(), 0);
446+
}
447+
442448
fn r_take_rust_string(s: String) {
443449
assert_eq!(s, "2020");
444450
}
445451

452+
fn r_take_empty_rust_string(s: String) {
453+
assert_eq!(s.len(), 0);
454+
}
455+
446456
fn r_take_sliceu8(s: &[u8]) {
447457
assert_eq!(s.len(), 5);
448458
assert_eq!(std::str::from_utf8(s).unwrap(), "2020\0");

tests/ffi/tests.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,9 +605,26 @@ extern "C" const char *cxx_run_test() noexcept {
605605
r_take_unique_ptr(std::unique_ptr<C>(new C{2020}));
606606
r_take_ref_c(C{2020});
607607
r_take_str(rust::Str("2020"));
608+
r_take_empty_str(rust::Str(""));
609+
r_take_empty_str(rust::Str(nullptr, 0));
610+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
611+
r_take_str(std::string_view("2020"));
612+
r_take_empty_str(std::string_view{});
613+
r_take_empty_str(std::string_view(""));
614+
ASSERT(static_cast<std::string_view>(rust::Str("2020")) == "2020");
615+
#endif
608616
r_take_sliceu8(rust::Slice<const uint8_t>(
609617
reinterpret_cast<const uint8_t *>(SLICE_DATA), sizeof(SLICE_DATA)));
610618
r_take_rust_string(rust::String("2020"));
619+
r_take_empty_rust_string(rust::String(""));
620+
r_take_empty_rust_string(rust::String(nullptr, 0));
621+
#ifdef CXXBRIDGE_HAS_STRING_VIEW
622+
r_take_rust_string(std::string_view("2020"));
623+
r_take_empty_rust_string(std::string_view{});
624+
r_take_empty_rust_string(std::string_view(""));
625+
const auto rustString = rust::String("2020"); // avoid lifetime issue
626+
ASSERT(static_cast<std::string_view>(rustString) == "2020");
627+
#endif
611628
r_take_unique_ptr_string(
612629
std::unique_ptr<std::string>(new std::string("2020")));
613630
r_take_ref_vector(std::vector<uint8_t>{20, 2, 0});

0 commit comments

Comments
 (0)