Bug 1359353 - Make the backing buffers of XPCOM strings available as mutable slices. r?Mystor.
MozReview-Commit-ID: KeJ2Qb3R5ET
--- a/xpcom/rust/nsstring/gtest/Test.cpp
+++ b/xpcom/rust/nsstring/gtest/Test.cpp
@@ -129,8 +129,29 @@ extern "C" void Rust_StringWrite();
TEST(RustNsString, StringWrite) {
Rust_StringWrite();
}
extern "C" void Rust_FromEmptyRustString();
TEST(RustNsString, FromEmptyRustString) {
Rust_FromEmptyRustString();
}
+
+extern "C" void Rust_WriteToBufferFromRust(nsACString* aCStr, nsAString* aStr, nsACString* aFallibleCStr, nsAString* aFallibleStr);
+TEST(RustNsString, WriteToBufferFromRust) {
+ nsAutoCString cStr;
+ nsAutoString str;
+ nsAutoCString fallibleCStr;
+ nsAutoString fallibleStr;
+
+ cStr.AssignLiteral("abc");
+ str.AssignLiteral("abc");
+ fallibleCStr.AssignLiteral("abc");
+ fallibleStr.AssignLiteral("abc");
+
+ Rust_WriteToBufferFromRust(&cStr, &str, &fallibleCStr, &fallibleStr);
+
+ EXPECT_TRUE(cStr.EqualsASCII("ABC"));
+ EXPECT_TRUE(str.EqualsASCII("ABC"));
+ EXPECT_TRUE(fallibleCStr.EqualsASCII("ABC"));
+ EXPECT_TRUE(fallibleStr.EqualsASCII("ABC"));
+}
+
--- a/xpcom/rust/nsstring/gtest/test.rs
+++ b/xpcom/rust/nsstring/gtest/test.rs
@@ -111,8 +111,31 @@ pub extern fn Rust_StringWrite() {
}
#[no_mangle]
pub extern fn Rust_FromEmptyRustString() {
let mut test = nsString::from("Blah");
test.assign_utf8(&nsCString::from(String::new()));
assert!(test.is_empty());
}
+
+#[no_mangle]
+pub extern fn Rust_WriteToBufferFromRust(cs: *mut nsACString, s: *mut nsAString, fallible_cs: *mut nsACString, fallible_s: *mut nsAString) {
+ unsafe {
+ let cs_buf = (*cs).to_mut();
+ let s_buf = (*s).to_mut();
+ let fallible_cs_buf = (*fallible_cs).fallible_to_mut().unwrap();
+ let fallible_s_buf = (*fallible_s).fallible_to_mut().unwrap();
+
+ cs_buf[0] = b'A';
+ cs_buf[1] = b'B';
+ cs_buf[2] = b'C';
+ s_buf[0] = b'A' as u16;
+ s_buf[1] = b'B' as u16;
+ s_buf[2] = b'C' as u16;
+ fallible_cs_buf[0] = b'A';
+ fallible_cs_buf[1] = b'B';
+ fallible_cs_buf[2] = b'C';
+ fallible_s_buf[0] = b'A' as u16;
+ fallible_s_buf[1] = b'B' as u16;
+ fallible_s_buf[2] = b'C' as u16;
+ }
+}
--- a/xpcom/rust/nsstring/src/lib.rs
+++ b/xpcom/rust/nsstring/src/lib.rs
@@ -160,16 +160,17 @@ macro_rules! define_string_types {
StringAdapter = $StringAdapter: ident;
StringRepr = $StringRepr: ident;
drop = $drop: ident;
assign = $assign: ident, $fallible_assign: ident;
append = $append: ident, $fallible_append: ident;
set_length = $set_length: ident, $fallible_set_length: ident;
+ begin_writing = $begin_writing: ident, $fallible_begin_writing: ident;
} => {
/// The representation of a ns[C]String type in C++. This type is
/// used internally by our definition of ns[C]String to ensure layout
/// compatibility with the C++ ns[C]String type.
///
/// This type may also be used in place of a C++ ns[C]String inside of
/// struct definitions which are shared with C++, as it has identical
/// layout to our ns[C]String type.
@@ -278,16 +279,55 @@ macro_rules! define_string_types {
}
}
pub fn truncate(&mut self) {
unsafe {
self.set_length(0);
}
}
+
+ /// Get a `&mut` reference to the backing data for this string.
+ /// This method will allocate and copy if the current backing buffer
+ /// is immutable or shared.
+ pub fn to_mut(&mut self) -> &mut [$char_t] {
+ unsafe {
+ let len = self.len();
+ if len == 0 {
+ // Use an arbitrary non-null value as the pointer
+ slice::from_raw_parts_mut(0x1 as *mut $char_t, 0)
+ } else {
+ slice::from_raw_parts_mut($begin_writing(self), len)
+ }
+ }
+ }
+
+ /// Get a `&mut` reference to the backing data for this string.
+ /// This method will allocate and copy if the current backing buffer
+ /// is immutable or shared.
+ ///
+ /// Returns `Ok(&mut [T])` on success, and `Err(())` if the
+ /// allocation failed.
+ pub fn fallible_to_mut(&mut self) -> Result<&mut [$char_t], ()> {
+ unsafe {
+ let len = self.len();
+ if len == 0 {
+ // Use an arbitrary non-null value as the pointer
+ Ok(slice::from_raw_parts_mut(0x1 as *mut $char_t, 0))
+ } else {
+ let ptr = $fallible_begin_writing(self);
+ if ptr.is_null() {
+ Err(())
+ } else {
+ Ok(slice::from_raw_parts_mut(ptr, len))
+ }
+ }
+ }
+ }
+
}
impl Deref for $AString {
type Target = [$char_t];
fn deref(&self) -> &[$char_t] {
unsafe {
// All $AString values point to a struct prefix which is
// identical to $StringRepr, this we can transmute `self`
@@ -701,16 +741,17 @@ define_string_types! {
StringAdapter = nsCStringAdapter;
StringRepr = nsCStringRepr;
drop = Gecko_FinalizeCString;
assign = Gecko_AssignCString, Gecko_FallibleAssignCString;
append = Gecko_AppendCString, Gecko_FallibleAppendCString;
set_length = Gecko_SetLengthCString, Gecko_FallibleSetLengthCString;
+ begin_writing = Gecko_BeginWritingCString, Gecko_FallibleBeginWritingCString;
}
impl nsACString {
pub fn assign_utf16<T: nsStringLike + ?Sized>(&mut self, other: &T) {
self.truncate();
self.append_utf16(other);
}
@@ -823,16 +864,17 @@ define_string_types! {
StringAdapter = nsStringAdapter;
StringRepr = nsStringRepr;
drop = Gecko_FinalizeString;
assign = Gecko_AssignString, Gecko_FallibleAssignString;
append = Gecko_AppendString, Gecko_FallibleAppendString;
set_length = Gecko_SetLengthString, Gecko_FallibleSetLengthString;
+ begin_writing = Gecko_BeginWritingString, Gecko_FallibleBeginWritingString;
}
impl nsAString {
pub fn assign_utf8<T: nsCStringLike + ?Sized>(&mut self, other: &T) {
self.truncate();
self.append_utf8(other);
}
@@ -909,28 +951,32 @@ extern "C" {
fn Gecko_IncrementStringAdoptCount(data: *mut c_void);
// Gecko implementation in nsSubstring.cpp
fn Gecko_FinalizeCString(this: *mut nsACString);
fn Gecko_AssignCString(this: *mut nsACString, other: *const nsACString);
fn Gecko_AppendCString(this: *mut nsACString, other: *const nsACString);
fn Gecko_SetLengthCString(this: *mut nsACString, length: u32);
+ fn Gecko_BeginWritingCString(this: *mut nsACString) -> *mut u8;
fn Gecko_FallibleAssignCString(this: *mut nsACString, other: *const nsACString) -> bool;
fn Gecko_FallibleAppendCString(this: *mut nsACString, other: *const nsACString) -> bool;
fn Gecko_FallibleSetLengthCString(this: *mut nsACString, length: u32) -> bool;
+ fn Gecko_FallibleBeginWritingCString(this: *mut nsACString) -> *mut u8;
fn Gecko_FinalizeString(this: *mut nsAString);
fn Gecko_AssignString(this: *mut nsAString, other: *const nsAString);
fn Gecko_AppendString(this: *mut nsAString, other: *const nsAString);
fn Gecko_SetLengthString(this: *mut nsAString, length: u32);
+ fn Gecko_BeginWritingString(this: *mut nsAString) -> *mut u16;
fn Gecko_FallibleAssignString(this: *mut nsAString, other: *const nsAString) -> bool;
fn Gecko_FallibleAppendString(this: *mut nsAString, other: *const nsAString) -> bool;
fn Gecko_FallibleSetLengthString(this: *mut nsAString, length: u32) -> bool;
+ fn Gecko_FallibleBeginWritingString(this: *mut nsAString) -> *mut u16;
// Gecko implementation in nsReadableUtils.cpp
fn Gecko_AppendUTF16toCString(this: *mut nsACString, other: *const nsAString);
fn Gecko_AppendUTF8toString(this: *mut nsAString, other: *const nsACString);
fn Gecko_FallibleAppendUTF16toCString(this: *mut nsACString, other: *const nsAString) -> bool;
fn Gecko_FallibleAppendUTF8toString(this: *mut nsAString, other: *const nsACString) -> bool;
}
--- a/xpcom/string/nsSubstring.cpp
+++ b/xpcom/string/nsSubstring.cpp
@@ -414,16 +414,26 @@ bool Gecko_FallibleAppendCString(nsACStr
return aThis->Append(*aOther, mozilla::fallible);
}
bool Gecko_FallibleSetLengthCString(nsACString* aThis, uint32_t aLength)
{
return aThis->SetLength(aLength, mozilla::fallible);
}
+char* Gecko_BeginWritingCString(nsACString* aThis)
+{
+ return aThis->BeginWriting();
+}
+
+char* Gecko_FallibleBeginWritingCString(nsACString* aThis)
+{
+ return aThis->BeginWriting(mozilla::fallible);
+}
+
void Gecko_FinalizeString(nsAString* aThis)
{
aThis->~nsAString();
}
void Gecko_AssignString(nsAString* aThis, const nsAString* aOther)
{
aThis->Assign(*aOther);
@@ -449,9 +459,19 @@ bool Gecko_FallibleAppendString(nsAStrin
return aThis->Append(*aOther, mozilla::fallible);
}
bool Gecko_FallibleSetLengthString(nsAString* aThis, uint32_t aLength)
{
return aThis->SetLength(aLength, mozilla::fallible);
}
+char16_t* Gecko_BeginWritingString(nsAString* aThis)
+{
+ return aThis->BeginWriting();
+}
+
+char16_t* Gecko_FallibleBeginWritingString(nsAString* aThis)
+{
+ return aThis->BeginWriting(mozilla::fallible);
+}
+
} // extern "C"