Skip to content

Commit 31a4102

Browse files
committed
Added UTF-16 rust::String initialization
This patch exposes String::from_utf16 to the C++ interface for rust::String.
1 parent c59a402 commit 31a4102

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

include/cxx.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class String final {
4343
String(const std::string &);
4444
String(const char *);
4545
String(const char *, std::size_t);
46+
String(const char16_t *);
47+
String(const char16_t *, std::size_t);
4648

4749
String &operator=(const String &) &noexcept;
4850
String &operator=(String &&) &noexcept;

src/cxx.cc

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ void cxxbridge1$cxx_string$push(std::string &s, const std::uint8_t *ptr,
3131
void cxxbridge1$string$new(rust::String *self) noexcept;
3232
void cxxbridge1$string$clone(rust::String *self,
3333
const rust::String &other) noexcept;
34-
bool cxxbridge1$string$from(rust::String *self, const char *ptr,
35-
std::size_t len) noexcept;
34+
bool cxxbridge1$string$from_utf8(rust::String *self, const char *ptr,
35+
std::size_t len) noexcept;
36+
bool cxxbridge1$string$from_utf16(rust::String *self, const char16_t *ptr,
37+
std::size_t len) noexcept;
3638
void cxxbridge1$string$drop(rust::String *self) noexcept;
3739
const char *cxxbridge1$string$ptr(const rust::String *self) noexcept;
3840
std::size_t cxxbridge1$string$len(const rust::String *self) noexcept;
@@ -81,11 +83,17 @@ String::String(String &&other) noexcept : repr(other.repr) {
8183
String::~String() noexcept { cxxbridge1$string$drop(this); }
8284

8385
static void initString(String *self, const char *s, std::size_t len) {
84-
if (!cxxbridge1$string$from(self, s, len)) {
86+
if (!cxxbridge1$string$from_utf8(self, s, len)) {
8587
panic<std::invalid_argument>("data for rust::String is not utf-8");
8688
}
8789
}
8890

91+
static void initString(String *self, const char16_t *s, std::size_t len) {
92+
if (!cxxbridge1$string$from_utf16(self, s, len)) {
93+
panic<std::invalid_argument>("data for rust::String is not utf-16");
94+
}
95+
}
96+
8997
String::String(const std::string &s) { initString(this, s.data(), s.length()); }
9098

9199
String::String(const char *s) {
@@ -100,6 +108,19 @@ String::String(const char *s, std::size_t len) {
100108
len);
101109
}
102110

111+
String::String(const char16_t *s) {
112+
assert(s != nullptr);
113+
initString(this, s, std::char_traits<char16_t>::length(s));
114+
}
115+
116+
String::String(const char16_t *s, std::size_t len) {
117+
assert(s != nullptr || len == 0);
118+
initString(this,
119+
s == nullptr && len == 0 ? reinterpret_cast<const char16_t *>(2)
120+
: s,
121+
len);
122+
}
123+
103124
String &String::operator=(const String &other) &noexcept {
104125
if (this != &other) {
105126
cxxbridge1$string$drop(this);

src/symbols/rust_string.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ unsafe extern "C" fn string_clone(this: &mut MaybeUninit<String>, other: &String
1515
ptr::write(this.as_mut_ptr(), other.clone());
1616
}
1717

18-
#[export_name = "cxxbridge1$string$from"]
19-
unsafe extern "C" fn string_from(
18+
#[export_name = "cxxbridge1$string$from_utf8"]
19+
unsafe extern "C" fn string_from_utf8(
2020
this: &mut MaybeUninit<String>,
2121
ptr: *const u8,
2222
len: usize,
@@ -31,6 +31,22 @@ unsafe extern "C" fn string_from(
3131
}
3232
}
3333

34+
#[export_name = "cxxbridge1$string$from_utf16"]
35+
unsafe extern "C" fn string_from_utf16(
36+
this: &mut MaybeUninit<String>,
37+
ptr: *const u16,
38+
len: usize,
39+
) -> bool {
40+
let slice = slice::from_raw_parts(ptr, len);
41+
match String::from_utf16(slice) {
42+
Ok(s) => {
43+
ptr::write(this.as_mut_ptr(), s);
44+
true
45+
}
46+
Err(_) => false,
47+
}
48+
}
49+
3450
#[export_name = "cxxbridge1$string$drop"]
3551
unsafe extern "C" fn string_drop(this: &mut ManuallyDrop<String>) {
3652
ManuallyDrop::drop(this);

tests/ffi/tests.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,12 @@ extern "C" const char *cxx_run_test() noexcept {
841841
ASSERT(cstr == "foo");
842842
ASSERT(other_cstr == "test");
843843

844+
const char *utf8_literal = u8"Test string";
845+
const char16_t *utf16_literal = u"Test string";
846+
rust::String utf8_rstring = utf8_literal;
847+
rust::String utf16_rstring = utf16_literal;
848+
ASSERT(utf8_rstring == utf16_rstring);
849+
844850
rust::Vec<int> vec1{1, 2};
845851
rust::Vec<int> vec2{3, 4};
846852
swap(vec1, vec2);

0 commit comments

Comments
 (0)