// ignore-tidy-filelength
-// ignore-tidy-undocumented-unsafe
//! String manipulation.
//!
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
run_utf8_validation(v)?;
+ // SAFETY: just ran validation
Ok(unsafe { from_utf8_unchecked(v) })
}
#[stable(feature = "str_mut_extras", since = "1.20.0")]
pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
run_utf8_validation(v)?;
+ // SAFETY: just ran validation
Ok(unsafe { from_utf8_unchecked_mut(v) })
}
#[inline]
fn next(&mut self) -> Option<char> {
next_code_point(&mut self.iter).map(|ch| {
- // str invariant says `ch` is a valid Unicode Scalar Value
+ // SAFETY: str invariant says `ch` is a valid Unicode Scalar Value
unsafe { char::from_u32_unchecked(ch) }
})
}
#[inline]
fn next_back(&mut self) -> Option<char> {
next_code_point_reverse(&mut self.iter).map(|ch| {
- // str invariant says `ch` is a valid Unicode Scalar Value
+ // SAFETY: str invariant says `ch` is a valid Unicode Scalar Value
unsafe { char::from_u32_unchecked(ch) }
})
}
#[stable(feature = "iter_to_slice", since = "1.4.0")]
#[inline]
pub fn as_str(&self) -> &'a str {
+ // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid utf8
unsafe { from_utf8_unchecked(self.iter.as_slice()) }
}
}
fn get_end(&mut self) -> Option<&'a str> {
if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) {
self.finished = true;
+ // SAFETY: `self.start` and `self.end` always lie on unicode boundaries
unsafe {
let string = self.matcher.haystack().get_unchecked(self.start..self.end);
Some(string)
let haystack = self.matcher.haystack();
match self.matcher.next_match() {
+ // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries
Some((a, b)) => unsafe {
let elt = haystack.get_unchecked(self.start..a);
self.start = b;
let haystack = self.matcher.haystack();
match self.matcher.next_match_back() {
+ // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries
Some((a, b)) => unsafe {
let elt = haystack.get_unchecked(b..self.end);
self.end = a;
Some(elt)
},
+ // SAFETY: `self.start` and `self.end` always lie on unicode boundaries
None => unsafe {
self.finished = true;
Some(haystack.get_unchecked(self.start..self.end))
impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
#[inline]
fn next(&mut self) -> Option<(usize, &'a str)> {
+ // SAFETY: `Searcher` guaratees that `start` and `end` lie on unicode boundaries
self.0
.next_match()
.map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) })
where
P::Searcher: ReverseSearcher<'a>,
{
+ // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries
self.0
.next_match_back()
.map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) })
impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> {
#[inline]
fn next(&mut self) -> Option<&'a str> {
+ // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries
self.0.next_match().map(|(a, b)| unsafe {
// Indices are known to be on utf8 boundaries
self.0.haystack().get_unchecked(a..b)
where
P::Searcher: ReverseSearcher<'a>,
{
+ // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries
self.0.next_match_back().map(|(a, b)| unsafe {
// Indices are known to be on utf8 boundaries
self.0.haystack().get_unchecked(a..b)
if align != usize::max_value() && align.wrapping_sub(index) % usize_bytes == 0 {
let ptr = v.as_ptr();
while index < blocks_end {
+ // SAFETY: since `align - index` and `ascii_block_size` are multiples of
+ // `usize_bytes`, `ptr.add(index)` is always aligned with a `usize` so we
+ // may cast directly to a `const` pointer.
unsafe {
let block = ptr.add(index) as *const usize;
// break if there is a nonascii byte
&& slice.is_char_boundary(self.start)
&& slice.is_char_boundary(self.end)
{
+ // SAFETY: just checked that `start` and `end` are on a char boundary
Some(unsafe { self.get_unchecked(slice) })
} else {
None
&& slice.is_char_boundary(self.start)
&& slice.is_char_boundary(self.end)
{
+ // SAFETY: just checked that `start` and `end` are on a char boundary
Some(unsafe { self.get_unchecked_mut(slice) })
} else {
None
&& slice.is_char_boundary(self.start)
&& slice.is_char_boundary(self.end)
{
+ // SAFETY: just checked that `start` and `end` are on a char boundary
unsafe { self.get_unchecked_mut(slice) }
} else {
super::slice_error_fail(slice, self.start, self.end)
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
if slice.is_char_boundary(self.end) {
+ // SAFETY: just checked that `end` is on a char boundary
Some(unsafe { self.get_unchecked(slice) })
} else {
None
#[inline]
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
if slice.is_char_boundary(self.end) {
+ // SAFETY: just checked that `end` is on a char boundary
Some(unsafe { self.get_unchecked_mut(slice) })
} else {
None
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
- // is_char_boundary checks that the index is in [0, .len()]
if slice.is_char_boundary(self.end) {
+ // SAFETY: just checked that `end` is on a char boundary
unsafe { self.get_unchecked_mut(slice) }
} else {
super::slice_error_fail(slice, 0, self.end)
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
if slice.is_char_boundary(self.start) {
+ // SAFETY: just checked that `start` is on a char boundary
Some(unsafe { self.get_unchecked(slice) })
} else {
None
#[inline]
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
if slice.is_char_boundary(self.start) {
+ // SAFETY: just checked that `start` is on a char boundary
Some(unsafe { self.get_unchecked_mut(slice) })
} else {
None
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
- // is_char_boundary checks that the index is in [0, .len()]
if slice.is_char_boundary(self.start) {
+ // SAFETY: just checked that `start` is on a char boundary
unsafe { self.get_unchecked_mut(slice) }
} else {
super::slice_error_fail(slice, self.start, slice.len())
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "str_as_bytes", since = "1.32.0")]
#[inline(always)]
- // SAFETY: const sound because we transmute two types with the same layout
#[allow(unused_attributes)]
#[allow_internal_unstable(const_fn_union)]
pub const fn as_bytes(&self) -> &[u8] {
str: &'a str,
slice: &'a [u8],
}
+ // SAFETY: const sound because we transmute two types with the same layout
unsafe { Slices { str: self }.slice }
}
pub fn split_at(&self, mid: usize) -> (&str, &str) {
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(mid) {
+ // SAFETY: just checked that `mid` is on a char boundary
unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) }
} else {
slice_error_fail(self, 0, mid)
if self.is_char_boundary(mid) {
let len = self.len();
let ptr = self.as_mut_ptr();
+ // SAFETY: just checked that `mid` is on a char boundary
unsafe {
(
from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)),
if let Some((_, b)) = matcher.next_reject_back() {
j = b;
}
+ // SAFETY: `Searcher` is known to return valid indices
unsafe {
- // Searcher is known to return valid indices
self.get_unchecked(i..j)
}
}
if let Some((a, _)) = matcher.next_reject() {
i = a;
}
+ // SAFETY: `Searcher` is known to return valid indices
unsafe {
- // Searcher is known to return valid indices
self.get_unchecked(i..self.len())
}
}
if let Some((_, b)) = matcher.next_reject_back() {
j = b;
}
+ // SAFETY: `Searcher` is known to return valid indices
unsafe {
- // Searcher is known to return valid indices
self.get_unchecked(0..j)
}
}
/// ```
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
pub fn make_ascii_uppercase(&mut self) {
+ // SAFETY: safe because we transmute two types with the same layout
let me = unsafe { self.as_bytes_mut() };
me.make_ascii_uppercase()
}
/// ```
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
pub fn make_ascii_lowercase(&mut self) {
+ // SAFETY: safe because we transmute two types with the same layout
let me = unsafe { self.as_bytes_mut() };
me.make_ascii_lowercase()
}
#[stable(feature = "default_mut_str", since = "1.28.0")]
impl Default for &mut str {
/// Creates an empty mutable str
+ // SAFETY: `str` is guranteed to be UTF-8
fn default() -> Self {
unsafe { from_utf8_unchecked_mut(&mut []) }
}
#[derive(Clone)]
struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str {
+ // SAFETY: not safe
unsafe { from_utf8_unchecked(bytes) }
};
}