]> git.lizzy.rs Git - rust.git/blobdiff - src/libcore/str/mod.rs
Apply suggestions from code review
[rust.git] / src / libcore / str / mod.rs
index ab771b1164bada9cac464668ce8ab02b5755636d..f89edf1910fac06f25f4c835b35ab5642f007f82 100644 (file)
@@ -1,5 +1,4 @@
 // ignore-tidy-filelength
-// ignore-tidy-undocumented-unsafe
 
 //! String manipulation.
 //!
@@ -341,6 +340,7 @@ pub fn error_len(&self) -> Option<usize> {
 #[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) })
 }
 
@@ -379,6 +379,7 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
 #[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) })
 }
 
@@ -581,7 +582,7 @@ impl<'a> Iterator for Chars<'a> {
     #[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) }
         })
     }
@@ -628,7 +629,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> {
     #[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) }
         })
     }
@@ -658,6 +659,7 @@ impl<'a> Chars<'a> {
     #[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()) }
     }
 }
@@ -1102,6 +1104,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
     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)
@@ -1119,6 +1122,7 @@ fn next(&mut self) -> Option<&'a str> {
 
         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;
@@ -1151,11 +1155,13 @@ fn next_back(&mut self) -> Option<&'a str>
 
         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))
@@ -1295,6 +1301,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 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)) })
@@ -1305,6 +1312,7 @@ fn next_back(&mut self) -> Option<(usize, &'a str)>
     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)) })
@@ -1348,6 +1356,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 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)
@@ -1359,6 +1368,7 @@ fn next_back(&mut self) -> Option<&'a str>
     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)
@@ -1579,6 +1589,9 @@ macro_rules! next {
             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
@@ -1804,6 +1817,7 @@ fn get(self, slice: &str) -> Option<&Self::Output> {
                 && 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
@@ -1815,6 +1829,7 @@ fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
                 && 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
@@ -1845,6 +1860,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
                 && 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)
@@ -1873,6 +1889,7 @@ impl SliceIndex<str> for ops::RangeTo<usize> {
         #[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
@@ -1881,6 +1898,7 @@ fn get(self, slice: &str) -> Option<&Self::Output> {
         #[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
@@ -1903,8 +1921,8 @@ fn index(self, slice: &str) -> &Self::Output {
         }
         #[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)
@@ -1934,6 +1952,7 @@ impl SliceIndex<str> for ops::RangeFrom<usize> {
         #[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
@@ -1942,6 +1961,7 @@ fn get(self, slice: &str) -> Option<&Self::Output> {
         #[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
@@ -1966,8 +1986,8 @@ fn index(self, slice: &str) -> &Self::Output {
         }
         #[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())
@@ -2238,7 +2258,6 @@ pub fn is_char_boundary(&self, index: usize) -> bool {
     #[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] {
@@ -2247,6 +2266,7 @@ union Slices<'a> {
             str: &'a str,
             slice: &'a [u8],
         }
+        // SAFETY: const sound because we transmute two types with the same layout
         unsafe { Slices { str: self }.slice }
     }
 
@@ -2573,6 +2593,7 @@ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut s
     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)
@@ -2617,6 +2638,7 @@ pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
         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)),
@@ -3805,8 +3827,8 @@ pub fn trim_matches<'a, P>(&'a self, pat: P) -> &'a str
         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)
         }
     }
@@ -3844,8 +3866,8 @@ pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
         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())
         }
     }
@@ -3970,8 +3992,8 @@ pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str
         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)
         }
     }
@@ -4166,6 +4188,7 @@ pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
     /// ```
     #[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()
     }
@@ -4191,6 +4214,7 @@ pub fn make_ascii_uppercase(&mut self) {
     /// ```
     #[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()
     }
@@ -4356,6 +4380,7 @@ fn default() -> Self {
 #[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 []) }
     }
@@ -4412,6 +4437,7 @@ struct BytesIsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b [u8]| -> bool {
 
     #[derive(Clone)]
     struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str {
+        // SAFETY: not safe
         unsafe { from_utf8_unchecked(bytes) }
     };
 }