Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::{
nsACString, nsAString, nsCStringLike, BulkWriteOk, Gecko_FallibleAssignCString,
Latin1StringLike,
};
use encoding_rs::mem::*;
use encoding_rs::Encoding;
use std::slice;
/// Required math stated in the docs of
/// `convert_utf16_to_utf8()`.
#[inline(always)]
fn times_three(a: usize) -> Option<usize> {
a.checked_mul(3)
}
#[inline(always)]
fn identity(a: usize) -> Option<usize> {
Some(a)
}
#[inline(always)]
fn plus_one(a: usize) -> Option<usize> {
a.checked_add(1)
}
/// Typical cache line size per
///
/// For consistent behavior, not trying to use 128 on aarch64
/// or other fanciness like that.
const CACHE_LINE: usize = 64;
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
/// Returns true if the string is both longer than a cache line
/// and the first cache line is ASCII.
#[inline(always)]
fn long_string_starts_with_ascii(buffer: &[u8]) -> bool {
// We examine data only up to the end of the cache line
// to make this check minimally disruptive.
if buffer.len() <= CACHE_LINE {
return false;
}
let bound = CACHE_LINE - ((buffer.as_ptr() as usize) & CACHE_LINE_MASK);
is_ascii(&buffer[..bound])
}
/// Returns true if the string is both longer than two cache lines
/// and the first two cache lines are Basic Latin.
#[inline(always)]
fn long_string_stars_with_basic_latin(buffer: &[u16]) -> bool {
// We look at two cache lines with code unit size of two. There is need
// to look at more than one cache line in the UTF-16 case, because looking
// at just one cache line wouldn't catch non-ASCII Latin with high enough
// probability with Latin-script languages that have relatively infrequent
// non-ASCII characters.
if buffer.len() <= CACHE_LINE {
return false;
}
let bound = (CACHE_LINE * 2 - ((buffer.as_ptr() as usize) & CACHE_LINE_MASK)) / 2;
is_basic_latin(&buffer[..bound])
}
// Ignoring the copy avoidance complications of conversions between Latin1 and
// UTF-8, a conversion function has the outward form of
// `fn F(&mut self, other: &[T], old_len: usize) -> Result<BulkWriteOk, ()>`,
// where `T` is either `u8` or `u16`. `other` is the slice whose converted
// content are to be appended to `self` and `old_len` indicates how many
// code unit of `self` are to be preserved (0 for the assignment case and
// `self.len()` for the appending case).
//
// As implementation parameters a conversion function needs to know the
// math for computing the worst case conversion length in code units given
// the input length in code units. For a _constant conversion_ the number
// of code units the conversion produces equals the number of code units
// in the input. For a _shinking conversion_ the maximum number of code
// units the conversion can produce equals the number of code units in
// the input, but the conversion can produce fewer code units. Still, due
// to implementation details, the function might want _one_ unit more of
// output space. For an _expanding conversion_ (no need for macro), the
// minimum number of code units produced by the conversion is the number
// of code units in the input, but the conversion can produce more.
//
// Copy avoidance conversions avoid copying a refcounted buffer when it's
// ASCII-only.
//
// Internally, a conversion function needs to know the underlying
// encoding_rs conversion function, the math for computing the required
// output buffer size and, depending on the case, the underlying
// encoding_rs ASCII prefix handling function.
/// A conversion where the number of code units in the output is potentially
/// smaller than the number of code units in the input.
///
/// Takes the name of the method to be generated, the name of the conversion
/// function and the type of the input slice.
///
/// `$name` is the name of the function to generate
/// `$convert` is the underlying `encoding_rs::mem` function to use
/// `$other_ty` is the type of the input slice
/// `$math` is the worst-case length math that `$convert` expects
macro_rules! shrinking_conversion {
(name = $name:ident,
convert = $convert:ident,
other_ty = $other_ty:ty,
math = $math:ident) => {
fn $name(&mut self, other: $other_ty, old_len: usize) -> Result<BulkWriteOk, ()> {
let needed = $math(other.len()).ok_or(())?;
let mut handle =
unsafe { self.bulk_write(old_len.checked_add(needed).ok_or(())?, old_len, false)? };
let written = $convert(other, &mut handle.as_mut_slice()[old_len..]);
let new_len = old_len + written;
Ok(handle.finish(new_len, new_len > CACHE_LINE))
}
};
}
/// A conversion where the number of code units in the output is always equal
/// to the number of code units in the input.
///
/// Takes the name of the method to be generated, the name of the conversion
/// function and the type of the input slice.
///
/// `$name` is the name of the function to generate
/// `$convert` is the underlying `encoding_rs::mem` function to use
/// `$other_ty` is the type of the input slice
macro_rules! constant_conversion {
(name = $name:ident,
convert = $convert:ident,
other_ty = $other_ty:ty) => {
fn $name(
&mut self,
other: $other_ty,
old_len: usize,
allow_shrinking: bool,
) -> Result<BulkWriteOk, ()> {
let new_len = old_len.checked_add(other.len()).ok_or(())?;
let mut handle = unsafe { self.bulk_write(new_len, old_len, allow_shrinking)? };
$convert(other, &mut handle.as_mut_slice()[old_len..]);
Ok(handle.finish(new_len, false))
}
};
}
/// An intermediate check for avoiding a copy and having an `StringBuffer` refcount increment
/// instead when both `self` and `other` are `nsACString`s, `other` is entirely ASCII and all old
/// data in `self` is discarded.
///
/// `$name` is the name of the function to generate
/// `$impl` is the underlying conversion that takes a slice and that is used
/// when we can't just adopt the incoming buffer as-is
/// `$string_like` is the kind of input taken
macro_rules! ascii_copy_avoidance {
(name = $name:ident,
implementation = $implementation:ident,
string_like = $string_like:ident) => {
fn $name<T: $string_like + ?Sized>(
&mut self,
other: &T,
old_len: usize,
) -> Result<BulkWriteOk, ()> {
let adapter = other.adapt();
let other_slice = adapter.as_ref();
let num_ascii = if adapter.is_abstract() && old_len == 0 {
let up_to = Encoding::ascii_valid_up_to(other_slice);
if up_to == other_slice.len() {
// Calling something whose argument can be obtained from
// the adapter rather than an nsStringLike avoids a huge
// lifetime mess by keeping nsStringLike and
// Latin1StringLike free of lifetime interdependencies.
if unsafe { Gecko_FallibleAssignCString(self, other.adapt().as_ptr()) } {
return Ok(BulkWriteOk {});
} else {
return Err(());
}
}
Some(up_to)
} else {
None
};
self.$implementation(other_slice, old_len, num_ascii)
}
};
}
impl nsAString {
// Valid UTF-8 to UTF-16
// Documentation says the destination buffer needs to have
// as many code units as the input.
shrinking_conversion!(
name = fallible_append_str_impl,
convert = convert_str_to_utf16,
other_ty = &str,
math = identity
);
/// Convert a valid UTF-8 string into valid UTF-16 and replace the content
/// of this string with the conversion result.
pub fn assign_str(&mut self, other: &str) {
self.fallible_append_str_impl(other, 0)
.expect("Out of memory");
}
/// Convert a valid UTF-8 string into valid UTF-16 and fallibly replace the
/// content of this string with the conversion result.
pub fn fallible_assign_str(&mut self, other: &str) -> Result<(), ()> {
self.fallible_append_str_impl(other, 0).map(|_| ())
}
/// Convert a valid UTF-8 string into valid UTF-16 and append the conversion
/// to this string.
pub fn append_str(&mut self, other: &str) {
let len = self.len();
self.fallible_append_str_impl(other, len)
.expect("Out of memory");
}
/// Convert a valid UTF-8 string into valid UTF-16 and fallibly append the
/// conversion to this string.
pub fn fallible_append_str(&mut self, other: &str) -> Result<(), ()> {
let len = self.len();
self.fallible_append_str_impl(other, len).map(|_| ())
}
// Potentially-invalid UTF-8 to UTF-16
// Documentation says the destination buffer needs to have
// one more code unit than the input.
shrinking_conversion!(
name = fallible_append_utf8_impl,
convert = convert_utf8_to_utf16,
other_ty = &[u8],
math = plus_one
);
/// Convert a potentially-invalid UTF-8 string into valid UTF-16
/// (replacing invalid sequences with the REPLACEMENT CHARACTER) and
/// replace the content of this string with the conversion result.
pub fn assign_utf8(&mut self, other: &[u8]) {
self.fallible_append_utf8_impl(other, 0)
.expect("Out of memory");
}
/// Convert a potentially-invalid UTF-8 string into valid UTF-16
/// (replacing invalid sequences with the REPLACEMENT CHARACTER) and
/// fallibly replace the content of this string with the conversion result.
pub fn fallible_assign_utf8(&mut self, other: &[u8]) -> Result<(), ()> {
self.fallible_append_utf8_impl(other, 0).map(|_| ())
}
/// Convert a potentially-invalid UTF-8 string into valid UTF-16
/// (replacing invalid sequences with the REPLACEMENT CHARACTER) and
/// append the conversion result to this string.
pub fn append_utf8(&mut self, other: &[u8]) {
let len = self.len();
self.fallible_append_utf8_impl(other, len)
.expect("Out of memory");
}
/// Convert a potentially-invalid UTF-8 string into valid UTF-16
/// (replacing invalid sequences with the REPLACEMENT CHARACTER) and
/// fallibly append the conversion result to this string.
pub fn fallible_append_utf8(&mut self, other: &[u8]) -> Result<(), ()> {
let len = self.len();
self.fallible_append_utf8_impl(other, len).map(|_| ())
}
// Latin1 to UTF-16
constant_conversion!(
name = fallible_append_latin1_impl,
convert = convert_latin1_to_utf16,
other_ty = &[u8]
);
/// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!)
/// into UTF-16 and replace the content of this string with the conversion result.
pub fn assign_latin1(&mut self, other: &[u8]) {
self.fallible_append_latin1_impl(other, 0, true)
.expect("Out of memory");
}
/// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!)
/// into UTF-16 and fallibly replace the content of this string with the
/// conversion result.
pub fn fallible_assign_latin1(&mut self, other: &[u8]) -> Result<(), ()> {
self.fallible_append_latin1_impl(other, 0, true).map(|_| ())
}
/// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!)
/// into UTF-16 and append the conversion result to this string.
pub fn append_latin1(&mut self, other: &[u8]) {
let len = self.len();
self.fallible_append_latin1_impl(other, len, false)
.expect("Out of memory");
}
/// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!)
/// into UTF-16 and fallibly append the conversion result to this string.
pub fn fallible_append_latin1(&mut self, other: &[u8]) -> Result<(), ()> {
let len = self.len();
self.fallible_append_latin1_impl(other, len, false)
.map(|_| ())
}
}
impl nsACString {
// UTF-16 to UTF-8
fn fallible_append_utf16_to_utf8_impl(
&mut self,
other: &[u16],
old_len: usize,
) -> Result<BulkWriteOk, ()> {
// We first size the buffer for ASCII if the first two cache lines are ASCII. If that turns out
// not to be enough, we size for the worst case given the length of the remaining input at that
// point. BUT if the worst case fits inside the inline capacity of an autostring, we skip
// the ASCII stuff.
let worst_case_needed = if let Some(inline_capacity) = self.inline_capacity() {
let worst_case = times_three(other.len()).ok_or(())?;
if worst_case <= inline_capacity {
Some(worst_case)
} else {
None
}
} else {
None
};
let (filled, read, mut handle) =
if worst_case_needed.is_none() && long_string_stars_with_basic_latin(other) {
let new_len_with_ascii = old_len.checked_add(other.len()).ok_or(())?;
let mut handle = unsafe { self.bulk_write(new_len_with_ascii, old_len, false)? };
let (read, written) =
convert_utf16_to_utf8_partial(other, &mut handle.as_mut_slice()[old_len..]);
let left = other.len() - read;
if left == 0 {
return Ok(handle.finish(old_len + written, true));
}
let filled = old_len + written;
let needed = times_three(left).ok_or(())?;
let new_len = filled.checked_add(needed).ok_or(())?;
unsafe {
handle.restart_bulk_write(new_len, filled, false)?;
}
(filled, read, handle)
} else {
// Started with non-ASCII. Compute worst case
let needed = if let Some(n) = worst_case_needed {
n
} else {
times_three(other.len()).ok_or(())?
};
let new_len = old_len.checked_add(needed).ok_or(())?;
let handle = unsafe { self.bulk_write(new_len, old_len, false)? };
(old_len, 0, handle)
};
let written = convert_utf16_to_utf8(&other[read..], &mut handle.as_mut_slice()[filled..]);
Ok(handle.finish(filled + written, true))
}
/// Convert a potentially-invalid UTF-16 string into valid UTF-8
/// (replacing invalid sequences with the REPLACEMENT CHARACTER) and
/// replace the content of this string with the conversion result.
pub fn assign_utf16_to_utf8(&mut self, other: &[u16]) {
self.fallible_append_utf16_to_utf8_impl(other, 0)
.expect("Out of memory");
}
/// Convert a potentially-invalid UTF-16 string into valid UTF-8
/// (replacing invalid sequences with the REPLACEMENT CHARACTER) and
/// fallibly replace the content of this string with the conversion result.
pub fn fallible_assign_utf16_to_utf8(&mut self, other: &[u16]) -> Result<(), ()> {
self.fallible_append_utf16_to_utf8_impl(other, 0)
.map(|_| ())
}
/// Convert a potentially-invalid UTF-16 string into valid UTF-8
/// (replacing invalid sequences with the REPLACEMENT CHARACTER) and
/// append the conversion result to this string.
pub fn append_utf16_to_utf8(&mut self, other: &[u16]) {
let len = self.len();
self.fallible_append_utf16_to_utf8_impl(other, len)
.expect("Out of memory");
}
/// Convert a potentially-invalid UTF-16 string into valid UTF-8
/// (replacing invalid sequences with the REPLACEMENT CHARACTER) and
/// fallibly append the conversion result to this string.
pub fn fallible_append_utf16_to_utf8(&mut self, other: &[u16]) -> Result<(), ()> {
let len = self.len();
self.fallible_append_utf16_to_utf8_impl(other, len)
.map(|_| ())
}
// UTF-16 to Latin1
constant_conversion!(
name = fallible_append_utf16_to_latin1_lossy_impl,
convert = convert_utf16_to_latin1_lossy,
other_ty = &[u16]
);
/// Convert a UTF-16 string whose all code points are below U+0100 into
/// a Latin1 (scalar value is byte value; not windows-1252!) string and
/// replace the content of this string with the conversion result.
///
/// # Panics
///
/// If the input contains code points above U+00FF or is not valid UTF-16,
/// panics in debug mode and produces garbage in a memory-safe way in
/// release builds. The nature of the garbage may differ based on CPU
/// architecture and must not be relied upon.
pub fn assign_utf16_to_latin1_lossy(&mut self, other: &[u16]) {
self.fallible_append_utf16_to_latin1_lossy_impl(other, 0, true)
.expect("Out of memory");
}
/// Convert a UTF-16 string whose all code points are below U+0100 into
/// a Latin1 (scalar value is byte value; not windows-1252!) string and
/// fallibly replace the content of this string with the conversion result.
///
/// # Panics
///
/// If the input contains code points above U+00FF or is not valid UTF-16,
/// panics in debug mode and produces garbage in a memory-safe way in
/// release builds. The nature of the garbage may differ based on CPU
/// architecture and must not be relied upon.
pub fn fallible_assign_utf16_to_latin1_lossy(&mut self, other: &[u16]) -> Result<(), ()> {
self.fallible_append_utf16_to_latin1_lossy_impl(other, 0, true)
.map(|_| ())
}
/// Convert a UTF-16 string whose all code points are below U+0100 into
/// a Latin1 (scalar value is byte value; not windows-1252!) string and
/// append the conversion result to this string.
///
/// # Panics
///
/// If the input contains code points above U+00FF or is not valid UTF-16,
/// panics in debug mode and produces garbage in a memory-safe way in
/// release builds. The nature of the garbage may differ based on CPU
/// architecture and must not be relied upon.
pub fn append_utf16_to_latin1_lossy(&mut self, other: &[u16]) {
let len = self.len();
self.fallible_append_utf16_to_latin1_lossy_impl(other, len, false)
.expect("Out of memory");
}
/// Convert a UTF-16 string whose all code points are below U+0100 into
/// a Latin1 (scalar value is byte value; not windows-1252!) string and
/// fallibly append the conversion result to this string.
///
/// # Panics
///
/// If the input contains code points above U+00FF or is not valid UTF-16,
/// panics in debug mode and produces garbage in a memory-safe way in
/// release builds. The nature of the garbage may differ based on CPU
/// architecture and must not be relied upon.
pub fn fallible_append_utf16_to_latin1_lossy(&mut self, other: &[u16]) -> Result<(), ()> {
let len = self.len();
self.fallible_append_utf16_to_latin1_lossy_impl(other, len, false)
.map(|_| ())
}
// UTF-8 to Latin1
ascii_copy_avoidance!(
name = fallible_append_utf8_to_latin1_lossy_check,
implementation = fallible_append_utf8_to_latin1_lossy_impl,
string_like = nsCStringLike
);
fn fallible_append_utf8_to_latin1_lossy_impl(
&mut self,
other: &[u8],
old_len: usize,
maybe_num_ascii: Option<usize>,
) -> Result<BulkWriteOk, ()> {
let new_len = old_len.checked_add(other.len()).ok_or(())?;
let num_ascii = maybe_num_ascii.unwrap_or(0);
// Already checked for overflow above, so this can't overflow.
let old_len_plus_num_ascii = old_len + num_ascii;
let mut handle = unsafe { self.bulk_write(new_len, old_len, false)? };
let written = {
let buffer = handle.as_mut_slice();
if num_ascii != 0 {
(&mut buffer[old_len..old_len_plus_num_ascii]).copy_from_slice(&other[..num_ascii]);
}
convert_utf8_to_latin1_lossy(&other[num_ascii..], &mut buffer[old_len_plus_num_ascii..])
};
Ok(handle.finish(old_len_plus_num_ascii + written, true))
}
/// Convert a UTF-8 string whose all code points are below U+0100 into
/// a Latin1 (scalar value is byte value; not windows-1252!) string and
/// replace the content of this string with the conversion result.
///
/// # Panics
///
/// If the input contains code points above U+00FF or is not valid UTF-8,
/// panics in debug mode and produces garbage in a memory-safe way in
/// release builds. The nature of the garbage may differ based on CPU
/// architecture and must not be relied upon.
pub fn assign_utf8_to_latin1_lossy<T: nsCStringLike + ?Sized>(&mut self, other: &T) {
self.fallible_append_utf8_to_latin1_lossy_check(other, 0)
.expect("Out of memory");
}
/// Convert a UTF-8 string whose all code points are below U+0100 into
/// a Latin1 (scalar value is byte value; not windows-1252!) string and
/// fallibly replace the content of this string with the conversion result.
///
/// # Panics
///
/// If the input contains code points above U+00FF or is not valid UTF-8,
/// panics in debug mode and produces garbage in a memory-safe way in
/// release builds. The nature of the garbage may differ based on CPU
/// architecture and must not be relied upon.
pub fn fallible_assign_utf8_to_latin1_lossy<T: nsCStringLike + ?Sized>(
&mut self,
other: &T,
) -> Result<(), ()> {
self.fallible_append_utf8_to_latin1_lossy_check(other, 0)
.map(|_| ())
}
/// Convert a UTF-8 string whose all code points are below U+0100 into
/// a Latin1 (scalar value is byte value; not windows-1252!) string and
/// append the conversion result to this string.
///
/// # Panics
///
/// If the input contains code points above U+00FF or is not valid UTF-8,
/// panics in debug mode and produces garbage in a memory-safe way in
/// release builds. The nature of the garbage may differ based on CPU
/// architecture and must not be relied upon.
pub fn append_utf8_to_latin1_lossy<T: nsCStringLike + ?Sized>(&mut self, other: &T) {
let len = self.len();
self.fallible_append_utf8_to_latin1_lossy_check(other, len)
.expect("Out of memory");
}
/// Convert a UTF-8 string whose all code points are below U+0100 into
/// a Latin1 (scalar value is byte value; not windows-1252!) string and
/// fallibly append the conversion result to this string.
///
/// # Panics
///
/// If the input contains code points above U+00FF or is not valid UTF-8,
/// panics in debug mode and produces garbage in a memory-safe way in
/// release builds. The nature of the garbage may differ based on CPU
/// architecture and must not be relied upon.
pub fn fallible_append_utf8_to_latin1_lossy<T: nsCStringLike + ?Sized>(
&mut self,
other: &T,
) -> Result<(), ()> {
let len = self.len();
self.fallible_append_utf8_to_latin1_lossy_check(other, len)
.map(|_| ())
}
// Latin1 to UTF-8 CString
ascii_copy_avoidance!(
name = fallible_append_latin1_to_utf8_check,
implementation = fallible_append_latin1_to_utf8_impl,
string_like = Latin1StringLike
);
fn fallible_append_latin1_to_utf8_impl(
&mut self,
other: &[u8],
old_len: usize,
maybe_num_ascii: Option<usize>,
) -> Result<BulkWriteOk, ()> {
let (filled, read, mut handle) = if let Some(num_ascii) = maybe_num_ascii {
// Wrapper checked for ASCII
let left = other.len() - num_ascii;
let filled = old_len + num_ascii;
let needed = left.checked_mul(2).ok_or(())?;
let new_len = filled.checked_add(needed).ok_or(())?;
let mut handle = unsafe { self.bulk_write(new_len, old_len, false)? };
if num_ascii != 0 {
(&mut handle.as_mut_slice()[old_len..filled]).copy_from_slice(&other[..num_ascii]);
}
(filled, num_ascii, handle)
} else {
let worst_case_needed = if let Some(inline_capacity) = self.inline_capacity() {
let worst_case = other.len().checked_mul(2).ok_or(())?;
if worst_case <= inline_capacity {
Some(worst_case)
} else {
None
}
} else {
None
};
if worst_case_needed.is_none() && long_string_starts_with_ascii(other) {
// Wrapper didn't check for ASCII, so let's see if `other` starts with ASCII
// `other` starts with ASCII, so let's first size the buffer
// with optimism that it's ASCII-only.
let new_len_with_ascii = old_len.checked_add(other.len()).ok_or(())?;
let mut handle = unsafe { self.bulk_write(new_len_with_ascii, old_len, false)? };
let (read, written) =
convert_latin1_to_utf8_partial(other, &mut handle.as_mut_slice()[old_len..]);
let left = other.len() - read;
let filled = old_len + written;
if left == 0 {
// `other` fit in the initial allocation
return Ok(handle.finish(filled, true));
}
let needed = left.checked_mul(2).ok_or(())?;
let new_len = filled.checked_add(needed).ok_or(())?;
unsafe {
handle.restart_bulk_write(new_len, filled, false)?;
}
(filled, read, handle)
} else {
// Started with non-ASCII. Assume worst case.
let needed = if let Some(n) = worst_case_needed {
n
} else {
other.len().checked_mul(2).ok_or(())?
};
let new_len = old_len.checked_add(needed).ok_or(())?;
let handle = unsafe { self.bulk_write(new_len, old_len, false)? };
(old_len, 0, handle)
}
};
let written = convert_latin1_to_utf8(&other[read..], &mut handle.as_mut_slice()[filled..]);
Ok(handle.finish(filled + written, true))
}
/// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!)
/// into UTF-8 and replace the content of this string with the conversion result.
pub fn assign_latin1_to_utf8<T: Latin1StringLike + ?Sized>(&mut self, other: &T) {
self.fallible_append_latin1_to_utf8_check(other, 0)
.expect("Out of memory");
}
/// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!)
/// into UTF-8 and fallibly replace the content of this string with the
/// conversion result.
pub fn fallible_assign_latin1_to_utf8<T: Latin1StringLike + ?Sized>(
&mut self,
other: &T,
) -> Result<(), ()> {
self.fallible_append_latin1_to_utf8_check(other, 0)
.map(|_| ())
}
/// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!)
/// into UTF-8 and append the conversion result to this string.
pub fn append_latin1_to_utf8<T: Latin1StringLike + ?Sized>(&mut self, other: &T) {
let len = self.len();
self.fallible_append_latin1_to_utf8_check(other, len)
.expect("Out of memory");
}
/// 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)
.map(|_| ())
}
}
#[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 = 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,
allow_shrinking: bool,
) -> bool {
let other_slice = slice::from_raw_parts(other, other_len);
(*this)
.fallible_append_latin1_impl(other_slice, old_len, allow_shrinking)
.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 = 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,
allow_shrinking: bool,
) -> bool {
let other_slice = slice::from_raw_parts(other, other_len);
(*this)
.fallible_append_utf16_to_latin1_lossy_impl(other_slice, old_len, allow_shrinking)
.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()
}