Bug 1402247 part 3 - Call Rust-based append/assign code from nsReadableUtils. draft
authorHenri Sivonen <hsivonen@hsivonen.fi>
Mon, 05 Feb 2018 19:05:45 +0200
changeset 768029 a1a06fd30435879dbd04856f41361f63dd2fe4ce
parent 768028 917205e84091e02f36a5e649a849ea8a3c3afb69
child 768030 1e0741a3568da43dd13df3724966e06ccebe46da
push id102784
push userbmo:hsivonen@hsivonen.fi
push dateThu, 15 Mar 2018 16:05:17 +0000
bugs1402247
milestone61.0a1
Bug 1402247 part 3 - Call Rust-based append/assign code from nsReadableUtils. MozReview-Commit-ID: EWe2ZFU7aQ5
dom/base/Link.cpp
dom/url/URLMainThread.cpp
dom/url/URLWorker.cpp
servo/support/gecko/nsstring/src/conversions.rs
servo/support/gecko/nsstring/src/lib.rs
xpcom/string/nsReadableUtils.cpp
xpcom/string/nsReadableUtils.h
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -732,17 +732,18 @@ Link::GetSearch(nsAString &_search)
     // Do not throw!  Not having a valid URI or URL should result in an empty
     // string.
     return;
   }
 
   nsAutoCString search;
   nsresult rv = url->GetQuery(search);
   if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
-    CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, _search);
+    _search.Assign((char16_t)'?');
+    AppendUTF8toUTF16(search, _search);
   }
 }
 
 void
 Link::GetPort(nsAString &_port)
 {
   _port.Truncate();
 
--- a/dom/url/URLMainThread.cpp
+++ b/dom/url/URLMainThread.cpp
@@ -422,17 +422,18 @@ URLMainThread::GetSearch(nsAString& aSea
   // Do not throw!  Not having a valid URI or URL should result in an empty
   // string.
 
   nsAutoCString search;
   nsresult rv;
 
   rv = mURI->GetQuery(search);
   if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
-    CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
+    aSearch.Assign((char16_t)'?');
+    AppendUTF8toUTF16(search, aSearch);
   }
 }
 
 void
 URLMainThread::GetHash(nsAString& aHash, ErrorResult& aRv) const
 {
   aHash.Truncate();
 
--- a/dom/url/URLWorker.cpp
+++ b/dom/url/URLWorker.cpp
@@ -1110,17 +1110,18 @@ URLWorker::GetSearch(nsAString& aSearch,
   aSearch.Truncate();
 
   if (mStdURL) {
     nsAutoCString search;
     nsresult rv;
 
     rv = mStdURL->GetQuery(search);
     if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
-      CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
+      aSearch.Assign((char16_t)'?');
+      AppendUTF8toUTF16(search, aSearch);
     }
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
   RefPtr<GetterRunnable> runnable =
     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterSearch, aSearch,
                        mURLProxy);
--- a/servo/support/gecko/nsstring/src/conversions.rs
+++ b/servo/support/gecko/nsstring/src/conversions.rs
@@ -499,8 +499,43 @@ impl nsACString {
     /// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!)
     /// into UTF-8 and fallibly append the conversion result to this string.
     pub fn fallible_append_latin1_to_utf8<T: Latin1StringLike + ?Sized>(&mut self, other: &T) -> Result<(), ()> {
         let len = self.len();
         self.fallible_append_latin1_to_utf8_check(other, len)
     }
 
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn nsstring_fallible_append_utf8_impl(this: *mut nsAString, other: *const u8, other_len: usize, old_len: usize) -> bool {
+    let other_slice = ::std::slice::from_raw_parts(other, other_len);
+    (*this).fallible_append_utf8_impl(other_slice, old_len).is_ok()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn nsstring_fallible_append_latin1_impl(this: *mut nsAString, other: *const u8, other_len: usize, old_len: usize) -> bool {
+    let other_slice = ::std::slice::from_raw_parts(other, other_len);
+    (*this).fallible_append_latin1_impl(other_slice, old_len).is_ok()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn nscstring_fallible_append_utf16_to_utf8_impl(this: *mut nsACString, other: *const u16, other_len: usize, old_len: usize) -> bool {
+    let other_slice = ::std::slice::from_raw_parts(other, other_len);
+    (*this).fallible_append_utf16_to_utf8_impl(other_slice, old_len).is_ok()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn nscstring_fallible_append_utf16_to_latin1_lossy_impl(this: *mut nsACString, other: *const u16, other_len: usize, old_len: usize) -> bool {
+    let other_slice = ::std::slice::from_raw_parts(other, other_len);
+    (*this).fallible_append_utf16_to_latin1_lossy_impl(other_slice, old_len).is_ok()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn nscstring_fallible_append_utf8_to_latin1_lossy_check(this: *mut nsACString, other: *const nsACString, old_len: usize) -> bool {
+    (*this).fallible_append_utf8_to_latin1_lossy_check(&*other, old_len).is_ok()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn nscstring_fallible_append_latin1_to_utf8_check(this: *mut nsACString, other: *const nsACString, old_len: usize) -> bool {
+    (*this).fallible_append_latin1_to_utf8_check(&*other, old_len).is_ok()
+}
+
--- a/servo/support/gecko/nsstring/src/lib.rs
+++ b/servo/support/gecko/nsstring/src/lib.rs
@@ -125,16 +125,23 @@ use std::mem;
 use std::ops::{Deref, DerefMut};
 use std::os::raw::c_void;
 use std::slice;
 use std::str;
 use std::u32;
 
 mod conversions;
 
+pub use self::conversions::nsstring_fallible_append_utf8_impl;
+pub use self::conversions::nsstring_fallible_append_latin1_impl;
+pub use self::conversions::nscstring_fallible_append_utf16_to_utf8_impl;
+pub use self::conversions::nscstring_fallible_append_utf16_to_latin1_lossy_impl;
+pub use self::conversions::nscstring_fallible_append_utf8_to_latin1_lossy_check;
+pub use self::conversions::nscstring_fallible_append_latin1_to_utf8_check;
+
 ///////////////////////////////////
 // Internal Implementation Flags //
 ///////////////////////////////////
 
 mod data_flags {
     bitflags! {
         // While this has the same layout as u16, it cannot be passed
         // over FFI safely as a u16.
--- a/xpcom/string/nsReadableUtils.cpp
+++ b/xpcom/string/nsReadableUtils.cpp
@@ -73,340 +73,16 @@ FirstNonASCII(const char16_t* aBegin, co
   if (mozilla::supports_sse2()) {
     return mozilla::SSE2::FirstNonASCII(aBegin, aEnd);
   }
 #endif
 
   return FirstNonASCIIUnvectorized(aBegin, aEnd);
 }
 
-void
-LossyCopyUTF16toASCII(const nsAString& aSource, nsACString& aDest)
-{
-  aDest.Truncate();
-  LossyAppendUTF16toASCII(aSource, aDest);
-}
-
-void
-CopyASCIItoUTF16(const nsACString& aSource, nsAString& aDest)
-{
-  if (!CopyASCIItoUTF16(aSource, aDest, mozilla::fallible)) {
-    // Note that this may wildly underestimate the allocation that failed, as
-    // we report the length of aSource as UTF-16 instead of UTF-8.
-    aDest.AllocFailed(aDest.Length() + aSource.Length());
-  }
-}
-
-bool
-CopyASCIItoUTF16(const nsACString& aSource, nsAString& aDest,
-                 const mozilla::fallible_t& aFallible)
-{
-  aDest.Truncate();
-  return AppendASCIItoUTF16(aSource, aDest, aFallible);
-}
-
-void
-LossyCopyUTF16toASCII(const char16ptr_t aSource, nsACString& aDest)
-{
-  aDest.Truncate();
-  if (aSource) {
-    LossyAppendUTF16toASCII(nsDependentString(aSource), aDest);
-  }
-}
-
-void
-CopyASCIItoUTF16(const char* aSource, nsAString& aDest)
-{
-  aDest.Truncate();
-  if (aSource) {
-    AppendASCIItoUTF16(nsDependentCString(aSource), aDest);
-  }
-}
-
-void
-CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest)
-{
-  if (!CopyUTF16toUTF8(aSource, aDest, mozilla::fallible)) {
-    // Note that this may wildly underestimate the allocation that failed, as
-    // we report the length of aSource as UTF-16 instead of UTF-8.
-    aDest.AllocFailed(aDest.Length() + aSource.Length());
-  }
-}
-
-bool
-CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest,
-                const mozilla::fallible_t& aFallible)
-{
-  aDest.Truncate();
-  if (!AppendUTF16toUTF8(aSource, aDest, aFallible)) {
-    return false;
-  }
-  return true;
-}
-
-void
-CopyUTF8toUTF16(const nsACString& aSource, nsAString& aDest)
-{
-  aDest.Truncate();
-  AppendUTF8toUTF16(aSource, aDest);
-}
-
-void
-CopyUTF16toUTF8(const char16ptr_t aSource, nsACString& aDest)
-{
-  aDest.Truncate();
-  AppendUTF16toUTF8(aSource, aDest);
-}
-
-void
-CopyUTF8toUTF16(const char* aSource, nsAString& aDest)
-{
-  aDest.Truncate();
-  AppendUTF8toUTF16(aSource, aDest);
-}
-
-void
-LossyAppendUTF16toASCII(const nsAString& aSource, nsACString& aDest)
-{
-  uint32_t old_dest_length = aDest.Length();
-  aDest.SetLength(old_dest_length + aSource.Length());
-
-  nsAString::const_iterator fromBegin, fromEnd;
-
-  nsACString::iterator dest;
-  aDest.BeginWriting(dest);
-
-  dest.advance(old_dest_length);
-
-  // right now, this won't work on multi-fragment destinations
-  LossyConvertEncoding16to8 converter(dest.get());
-
-  copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
-              converter);
-}
-
-void
-AppendASCIItoUTF16(const nsACString& aSource, nsAString& aDest)
-{
-  if (!AppendASCIItoUTF16(aSource, aDest, mozilla::fallible)) {
-    aDest.AllocFailed(aDest.Length() + aSource.Length());
-  }
-}
-
-bool
-AppendASCIItoUTF16(const nsACString& aSource, nsAString& aDest,
-                   const mozilla::fallible_t& aFallible)
-{
-  uint32_t old_dest_length = aDest.Length();
-  if (!aDest.SetLength(old_dest_length + aSource.Length(),
-                       aFallible)) {
-    return false;
-  }
-
-  nsACString::const_iterator fromBegin, fromEnd;
-
-  nsAString::iterator dest;
-  aDest.BeginWriting(dest);
-
-  dest.advance(old_dest_length);
-
-  // right now, this won't work on multi-fragment destinations
-  LossyConvertEncoding8to16 converter(dest.get());
-
-  copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
-              converter);
-  return true;
-}
-
-void
-LossyAppendUTF16toASCII(const char16ptr_t aSource, nsACString& aDest)
-{
-  if (aSource) {
-    LossyAppendUTF16toASCII(nsDependentString(aSource), aDest);
-  }
-}
-
-bool
-AppendASCIItoUTF16(const char* aSource, nsAString& aDest, const mozilla::fallible_t& aFallible)
-{
-  if (aSource) {
-    return AppendASCIItoUTF16(nsDependentCString(aSource), aDest, aFallible);
-  }
-
-  return true;
-}
-
-void
-AppendASCIItoUTF16(const char* aSource, nsAString& aDest)
-{
-  if (aSource) {
-    AppendASCIItoUTF16(nsDependentCString(aSource), aDest);
-  }
-}
-
-void
-AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest)
-{
-  if (!AppendUTF16toUTF8(aSource, aDest, mozilla::fallible)) {
-    // Note that this may wildly underestimate the allocation that failed, as
-    // we report the length of aSource as UTF-16 instead of UTF-8.
-    aDest.AllocFailed(aDest.Length() + aSource.Length());
-  }
-}
-
-bool
-AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest,
-                  const mozilla::fallible_t& aFallible)
-{
-  // At 16 characters analysis showed better performance of both the all ASCII
-  // and non-ASCII cases, so we limit calling |FirstNonASCII| to strings of
-  // that length.
-  const nsAString::size_type kFastPathMinLength = 16;
-
-  int32_t firstNonASCII = 0;
-  if (aSource.Length() >= kFastPathMinLength) {
-    firstNonASCII = FirstNonASCII(aSource.BeginReading(), aSource.EndReading());
-  }
-
-  if (firstNonASCII == -1) {
-    // This is all ASCII, we can use the more efficient lossy append.
-    mozilla::CheckedInt<nsACString::size_type> new_length(aSource.Length());
-    new_length += aDest.Length();
-
-    if (!new_length.isValid() ||
-        !aDest.SetCapacity(new_length.value(), aFallible)) {
-      return false;
-    }
-
-    LossyAppendUTF16toASCII(aSource, aDest);
-    return true;
-  }
-
-  nsAString::const_iterator source_start, source_end;
-  CalculateUTF8Size calculator;
-  aSource.BeginReading(source_start);
-  aSource.EndReading(source_end);
-
-  // Skip the characters that we know are single byte.
-  source_start.advance(firstNonASCII);
-
-  copy_string(source_start,
-              source_end, calculator);
-
-  // Include the ASCII characters that were skipped in the count.
-  size_t count = calculator.Size() + firstNonASCII;
-
-  if (count) {
-    auto old_dest_length = aDest.Length();
-    // Grow the buffer if we need to.
-    mozilla::CheckedInt<nsACString::size_type> new_length(count);
-    new_length += old_dest_length;
-
-    if (!new_length.isValid() ||
-        !aDest.SetLength(new_length.value(), aFallible)) {
-      return false;
-    }
-
-    // All ready? Time to convert
-
-    nsAString::const_iterator ascii_end;
-    aSource.BeginReading(ascii_end);
-
-    if (firstNonASCII >= static_cast<int32_t>(kFastPathMinLength)) {
-      // Use the more efficient lossy converter for the ASCII portion.
-      LossyConvertEncoding16to8 lossy_converter(
-          aDest.BeginWriting() + old_dest_length);
-      nsAString::const_iterator ascii_start;
-      aSource.BeginReading(ascii_start);
-      ascii_end.advance(firstNonASCII);
-
-      copy_string(ascii_start, ascii_end, lossy_converter);
-    } else {
-      // Not using the lossy shortcut, we need to include the leading ASCII
-      // chars.
-      firstNonASCII = 0;
-    }
-
-    ConvertUTF16toUTF8 converter(
-        aDest.BeginWriting() + old_dest_length + firstNonASCII);
-    copy_string(ascii_end,
-                aSource.EndReading(source_end), converter);
-
-    NS_ASSERTION(converter.Size() == count - firstNonASCII,
-                 "Unexpected disparity between CalculateUTF8Size and "
-                 "ConvertUTF16toUTF8");
-  }
-
-  return true;
-}
-
-void
-AppendUTF8toUTF16(const nsACString& aSource, nsAString& aDest)
-{
-  if (!AppendUTF8toUTF16(aSource, aDest, mozilla::fallible)) {
-    aDest.AllocFailed(aDest.Length() + aSource.Length());
-  }
-}
-
-bool
-AppendUTF8toUTF16(const nsACString& aSource, nsAString& aDest,
-                  const mozilla::fallible_t& aFallible)
-{
-  nsACString::const_iterator source_start, source_end;
-  CalculateUTF8Length calculator;
-  copy_string(aSource.BeginReading(source_start),
-              aSource.EndReading(source_end), calculator);
-
-  uint32_t count = calculator.Length();
-
-  // Avoid making the string mutable if we're appending an empty string
-  if (count) {
-    uint32_t old_dest_length = aDest.Length();
-
-    // Grow the buffer if we need to.
-    if (!aDest.SetLength(old_dest_length + count, aFallible)) {
-      return false;
-    }
-
-    // All ready? Time to convert
-
-    ConvertUTF8toUTF16 converter(aDest.BeginWriting() + old_dest_length);
-    copy_string(aSource.BeginReading(source_start),
-                aSource.EndReading(source_end), converter);
-
-    NS_ASSERTION(converter.ErrorEncountered() ||
-                 converter.Length() == count,
-                 "CalculateUTF8Length produced the wrong length");
-
-    if (converter.ErrorEncountered()) {
-      NS_ERROR("Input wasn't UTF8 or incorrect length was calculated");
-      aDest.SetLength(old_dest_length);
-    }
-  }
-
-  return true;
-}
-
-void
-AppendUTF16toUTF8(const char16ptr_t aSource, nsACString& aDest)
-{
-  if (aSource) {
-    AppendUTF16toUTF8(nsDependentString(aSource), aDest);
-  }
-}
-
-void
-AppendUTF8toUTF16(const char* aSource, nsAString& aDest)
-{
-  if (aSource) {
-    AppendUTF8toUTF16(nsDependentCString(aSource), aDest);
-  }
-}
-
-
 /**
  * A helper function that allocates a buffer of the desired character type big enough to hold a copy of the supplied string (plus a zero terminator).
  *
  * @param aSource an string you will eventually be making a copy of
  * @return a new buffer (of the type specified by the second parameter) which you must free with |free|.
  *
  */
 template <class FromStringT, class ToCharT>
--- a/xpcom/string/nsReadableUtils.h
+++ b/xpcom/string/nsReadableUtils.h
@@ -20,70 +20,322 @@
 
 // Can't include mozilla/Encoding.h here
 extern "C" {
   size_t encoding_utf8_valid_up_to(uint8_t const* buffer, size_t buffer_len);
   bool encoding_mem_is_ascii(uint8_t const* buffer, size_t buffer_len);
   bool encoding_mem_is_basic_latin(char16_t const* buffer, size_t buffer_len);
 }
 
+// From the nsstring crate
+extern "C" {
+  bool nsstring_fallible_append_utf8_impl(nsAString* aThis, const uint8_t* aOther, size_t aOtherLen, size_t aOldLen);
+  bool nsstring_fallible_append_latin1_impl(nsAString* aThis, const uint8_t* aOther, size_t aOtherLen, size_t aOldLen);
+  bool nscstring_fallible_append_utf16_to_utf8_impl(nsACString* aThis, const char16_t*, size_t aOtherLen, size_t aOldLen);
+  bool nscstring_fallible_append_utf16_to_latin1_lossy_impl(nsACString* aThis, const char16_t*, size_t aOtherLen, size_t aOldLen);
+  bool nscstring_fallible_append_utf8_to_latin1_lossy_check(nsACString* aThis, const nsACString* aOther, size_t aOldLen);
+  bool nscstring_fallible_append_latin1_to_utf8_check(nsACString* aThis, const nsACString* aOther, size_t aOldLen);
+}
+
 inline size_t
 Distance(const nsReadingIterator<char16_t>& aStart,
          const nsReadingIterator<char16_t>& aEnd)
 {
   MOZ_ASSERT(aStart.get() <= aEnd.get());
   return static_cast<size_t>(aEnd.get() - aStart.get());
 }
 inline size_t
 Distance(const nsReadingIterator<char>& aStart,
          const nsReadingIterator<char>& aEnd)
 {
   MOZ_ASSERT(aStart.get() <= aEnd.get());
   return static_cast<size_t>(aEnd.get() - aStart.get());
 }
 
-void LossyCopyUTF16toASCII(const nsAString& aSource, nsACString& aDest);
-void CopyASCIItoUTF16(const nsACString& aSource, nsAString& aDest);
-MOZ_MUST_USE bool CopyASCIItoUTF16(const nsACString& aSource, nsAString& aDest,
-                                   const mozilla::fallible_t&);
+// UTF-8 to UTF-16
+// Invalid UTF-8 byte sequences are replaced with the REPLACEMENT CHARACTER.
+
+inline MOZ_MUST_USE bool CopyUTF8toUTF16(mozilla::Span<const uint8_t> aSource,
+                                         nsAString& aDest,
+                                         const mozilla::fallible_t&)
+{
+  return nsstring_fallible_append_utf8_impl(&aDest, aSource.Elements(), aSource.Length(), 0);
+}
+
+inline void CopyUTF8toUTF16(mozilla::Span<const uint8_t> aSource,
+                            nsAString& aDest)
+{
+  if (MOZ_UNLIKELY(!CopyUTF8toUTF16(aSource, aDest, mozilla::fallible))) {
+    aDest.AllocFailed(aSource.Length());
+  }
+}
+
+inline MOZ_MUST_USE bool AppendUTF8toUTF16(mozilla::Span<const uint8_t> aSource,
+                                           nsAString& aDest,
+                                           const mozilla::fallible_t&)
+{
+  return nsstring_fallible_append_utf8_impl(&aDest, aSource.Elements(), aSource.Length(), aDest.Length());
+}
+
+inline void AppendUTF8toUTF16(mozilla::Span<const uint8_t> aSource,
+                              nsAString& aDest)
+{
+  if (MOZ_UNLIKELY(!AppendUTF8toUTF16(aSource, aDest, mozilla::fallible))) {
+    aDest.AllocFailed(aDest.Length() + aSource.Length());
+  }
+}
 
-void LossyCopyUTF16toASCII(const char16ptr_t aSource, nsACString& aDest);
-void CopyASCIItoUTF16(const char* aSource, nsAString& aDest);
+inline MOZ_MUST_USE bool CopyUTF8toUTF16(const char* aSource,
+                                         nsAString& aDest,
+                                         const mozilla::fallible_t&)
+{
+  if (aSource) {
+    return CopyUTF8toUTF16(mozilla::AsBytes(mozilla::MakeStringSpan(aSource)), aDest, mozilla::fallible);
+  }
+  return true;
+}
+
+inline void CopyUTF8toUTF16(const char* aSource,
+                            nsAString& aDest)
+{
+  if (aSource) {
+    CopyUTF8toUTF16(mozilla::AsBytes(mozilla::MakeStringSpan(aSource)), aDest);
+  }
+}
+
+inline MOZ_MUST_USE bool AppendUTF8toUTF16(const char* aSource,
+                                           nsAString& aDest,
+                                           const mozilla::fallible_t&)
+{
+  if (aSource) {
+    return AppendUTF8toUTF16(mozilla::AsBytes(mozilla::MakeStringSpan(aSource)), aDest, mozilla::fallible);
+  }
+  return true;
+}
+
+inline void AppendUTF8toUTF16(const char* aSource,
+                              nsAString& aDest)
+{
+  if (aSource) {
+    AppendUTF8toUTF16(mozilla::AsBytes(mozilla::MakeStringSpan(aSource)), aDest);
+  }
+}
 
-void CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest);
-MOZ_MUST_USE bool CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest,
-                                  const mozilla::fallible_t&);
-void CopyUTF8toUTF16(const nsACString& aSource, nsAString& aDest);
+// Latin1 to UTF-16
+// Interpret each incoming unsigned byte value as a Unicode scalar value (not windows-1252!).
+// The function names say "ASCII" instead of "Latin1" for legacy reasons.
+
+inline MOZ_MUST_USE bool CopyASCIItoUTF16(mozilla::Span<const uint8_t> aSource,
+                                          nsAString& aDest,
+                                          const mozilla::fallible_t&)
+{
+  return nsstring_fallible_append_latin1_impl(&aDest, aSource.Elements(), aSource.Length(), 0);
+}
+
+inline void CopyASCIItoUTF16(mozilla::Span<const uint8_t> aSource,
+                             nsAString& aDest)
+{
+  if (MOZ_UNLIKELY(!CopyASCIItoUTF16(aSource, aDest, mozilla::fallible))) {
+    aDest.AllocFailed(aSource.Length());
+  }
+}
+
+inline MOZ_MUST_USE bool AppendASCIItoUTF16(mozilla::Span<const uint8_t> aSource,
+                                            nsAString& aDest,
+                                            const mozilla::fallible_t&)
+{
+  return nsstring_fallible_append_latin1_impl(&aDest, aSource.Elements(), aSource.Length(), aDest.Length());
+}
+
+inline void AppendASCIItoUTF16(mozilla::Span<const uint8_t> aSource,
+                               nsAString& aDest)
+{
+  if (MOZ_UNLIKELY(!AppendASCIItoUTF16(aSource, aDest, mozilla::fallible))) {
+    aDest.AllocFailed(aDest.Length() + aSource.Length());
+  }
+}
 
-void CopyUTF16toUTF8(const char16ptr_t aSource, nsACString& aDest);
-void CopyUTF8toUTF16(const char* aSource, nsAString& aDest);
+inline MOZ_MUST_USE bool CopyASCIItoUTF16(const char* aSource,
+                                          nsAString& aDest,
+                                          const mozilla::fallible_t&)
+{
+  if (aSource) {
+    return CopyASCIItoUTF16(mozilla::AsBytes(mozilla::MakeStringSpan(aSource)), aDest, mozilla::fallible);
+  }
+  return true;
+}
+
+inline void CopyASCIItoUTF16(const char* aSource,
+                             nsAString& aDest)
+{
+  if (aSource) {
+    CopyASCIItoUTF16(mozilla::AsBytes(mozilla::MakeStringSpan(aSource)), aDest);
+  }
+}
+
+inline MOZ_MUST_USE bool AppendASCIItoUTF16(const char* aSource,
+                                            nsAString& aDest,
+                                            const mozilla::fallible_t&)
+{
+  if (aSource) {
+    return AppendASCIItoUTF16(mozilla::AsBytes(mozilla::MakeStringSpan(aSource)), aDest, mozilla::fallible);
+  }
+  return true;
+}
+
+inline void AppendASCIItoUTF16(const char* aSource,
+                               nsAString& aDest)
+{
+  if (aSource) {
+    AppendASCIItoUTF16(mozilla::AsBytes(mozilla::MakeStringSpan(aSource)), aDest);
+  }
+}
 
-void LossyAppendUTF16toASCII(const nsAString& aSource, nsACString& aDest);
-void AppendASCIItoUTF16(const nsACString& aSource, nsAString& aDest);
-MOZ_MUST_USE bool AppendASCIItoUTF16(const nsACString& aSource,
-                                     nsAString& aDest,
-                                     const mozilla::fallible_t&);
+// UTF-16 to UTF-8
+// Unpaired surrogates are replaced with the REPLACEMENT CHARACTER.
+
+inline MOZ_MUST_USE bool CopyUTF16toUTF8(mozilla::Span<const char16_t> aSource,
+                                         nsACString& aDest,
+                                         const mozilla::fallible_t&)
+{
+  return nscstring_fallible_append_utf16_to_utf8_impl(&aDest, aSource.Elements(), aSource.Length(), 0);
+}
+
+inline void CopyUTF16toUTF8(mozilla::Span<const char16_t> aSource,
+                            nsACString& aDest)
+{
+  if (MOZ_UNLIKELY(!CopyUTF16toUTF8(aSource, aDest, mozilla::fallible))) {
+    aDest.AllocFailed(aSource.Length());
+  }
+}
+
+inline MOZ_MUST_USE bool AppendUTF16toUTF8(mozilla::Span<const char16_t> aSource,
+                                           nsACString& aDest,
+                                           const mozilla::fallible_t&)
+{
+  return nscstring_fallible_append_utf16_to_utf8_impl(&aDest, aSource.Elements(), aSource.Length(), aDest.Length());
+}
+
+inline void AppendUTF16toUTF8(mozilla::Span<const char16_t> aSource,
+                              nsACString& aDest)
+{
+  if (MOZ_UNLIKELY(!AppendUTF16toUTF8(aSource, aDest, mozilla::fallible))) {
+    aDest.AllocFailed(aDest.Length() + aSource.Length());
+  }
+}
 
-void LossyAppendUTF16toASCII(const char16ptr_t aSource, nsACString& aDest);
-MOZ_MUST_USE bool AppendASCIItoUTF16(const char* aSource,
-                                     nsAString& aDest,
-                                     const mozilla::fallible_t&);
-void AppendASCIItoUTF16(const char* aSource, nsAString& aDest);
+inline MOZ_MUST_USE bool CopyUTF16toUTF8(const char16_t* aSource,
+                                         nsACString& aDest,
+                                         const mozilla::fallible_t&)
+{
+  if (aSource) {
+    return CopyUTF16toUTF8(mozilla::MakeStringSpan(aSource), aDest, mozilla::fallible);
+  }
+  return true;
+}
+
+inline void CopyUTF16toUTF8(const char16_t* aSource,
+                            nsACString& aDest)
+{
+  if (aSource) {
+    CopyUTF16toUTF8(mozilla::MakeStringSpan(aSource), aDest);
+  }
+}
+
+inline MOZ_MUST_USE bool AppendUTF16toUTF8(const char16_t* aSource,
+                                           nsACString& aDest,
+                                           const mozilla::fallible_t&)
+{
+  if (aSource) {
+    return AppendUTF16toUTF8(mozilla::MakeStringSpan(aSource), aDest, mozilla::fallible);
+  }
+  return true;
+}
+
+inline void AppendUTF16toUTF8(const char16_t* aSource,
+                              nsACString& aDest)
+{
+  if (aSource) {
+    AppendUTF16toUTF8(mozilla::MakeStringSpan(aSource), aDest);
+  }
+}
 
-void AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest);
-MOZ_MUST_USE bool AppendUTF16toUTF8(const nsAString& aSource,
-                                    nsACString& aDest,
-                                    const mozilla::fallible_t&);
-void AppendUTF8toUTF16(const nsACString& aSource, nsAString& aDest);
-MOZ_MUST_USE bool AppendUTF8toUTF16(const nsACString& aSource,
-                                    nsAString& aDest,
-                                    const mozilla::fallible_t&);
+// UTF-16 to Latin1
+// If all code points in the input are below U+0100, represents each scalar value
+// as an unsigned byte. (This is not windows-1252!)
+// If there are code points above U+00FF, asserts in debug builds and memory-safely
+// produces garbage in release builds. The nature of the garbage may differ based on
+// CPU architecture and must not be relied upon.
+// The names say "ASCII" instead of "Latin1" for legacy reasons.
+
+inline MOZ_MUST_USE bool LossyCopyUTF16toASCII(mozilla::Span<const char16_t> aSource,
+                                         nsACString& aDest,
+                                         const mozilla::fallible_t&)
+{
+  return nscstring_fallible_append_utf16_to_latin1_lossy_impl(&aDest, aSource.Elements(), aSource.Length(), 0);
+}
+
+inline void LossyCopyUTF16toASCII(mozilla::Span<const char16_t> aSource,
+                            nsACString& aDest)
+{
+  if (MOZ_UNLIKELY(!LossyCopyUTF16toASCII(aSource, aDest, mozilla::fallible))) {
+    aDest.AllocFailed(aSource.Length());
+  }
+}
+
+inline MOZ_MUST_USE bool LossyAppendUTF16toASCII(mozilla::Span<const char16_t> aSource,
+                                           nsACString& aDest,
+                                           const mozilla::fallible_t&)
+{
+  return nscstring_fallible_append_utf16_to_latin1_lossy_impl(&aDest, aSource.Elements(), aSource.Length(), aDest.Length());
+}
 
-void AppendUTF16toUTF8(const char16ptr_t aSource, nsACString& aDest);
-void AppendUTF8toUTF16(const char* aSource, nsAString& aDest);
+inline void LossyAppendUTF16toASCII(mozilla::Span<const char16_t> aSource,
+                              nsACString& aDest)
+{
+  if (MOZ_UNLIKELY(!LossyAppendUTF16toASCII(aSource, aDest, mozilla::fallible))) {
+    aDest.AllocFailed(aDest.Length() + aSource.Length());
+  }
+}
+
+inline MOZ_MUST_USE bool LossyCopyUTF16toASCII(const char16_t* aSource,
+                                         nsACString& aDest,
+                                         const mozilla::fallible_t&)
+{
+  if (aSource) {
+    return LossyCopyUTF16toASCII(mozilla::MakeStringSpan(aSource), aDest, mozilla::fallible);
+  }
+  return true;
+}
+
+inline void LossyCopyUTF16toASCII(const char16_t* aSource,
+                            nsACString& aDest)
+{
+  if (aSource) {
+    LossyCopyUTF16toASCII(mozilla::MakeStringSpan(aSource), aDest);
+  }
+}
+
+inline MOZ_MUST_USE bool LossyAppendUTF16toASCII(const char16_t* aSource,
+                                           nsACString& aDest,
+                                           const mozilla::fallible_t&)
+{
+  if (aSource) {
+    return LossyAppendUTF16toASCII(mozilla::MakeStringSpan(aSource), aDest, mozilla::fallible);
+  }
+  return true;
+}
+
+inline void LossyAppendUTF16toASCII(const char16_t* aSource,
+                              nsACString& aDest)
+{
+  if (aSource) {
+    LossyAppendUTF16toASCII(mozilla::MakeStringSpan(aSource), aDest);
+  }
+}
 
 /**
  * Returns a new |char| buffer containing a zero-terminated copy of |aSource|.
  *
  * Allocates and returns a new |char| buffer which you must free with |free|.
  * Performs a lossy encoding conversion by chopping 16-bit wide characters down to 8-bits wide while copying |aSource| to your new buffer.
  * This conversion is not well defined; but it reproduces legacy string behavior.
  * The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls.