1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
//! 在 ASCII `[u8]` 上的操作。
use crate::ascii;
use crate::fmt::{self, Write};
use crate::iter;
use crate::mem;
use crate::ops;
#[cfg(not(test))]
impl [u8] {
/// 检查此切片中的所有字节是否都在 ASCII 范围内。
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
#[rustc_const_unstable(feature = "const_slice_is_ascii", issue = "111090")]
#[must_use]
#[inline]
pub const fn is_ascii(&self) -> bool {
is_ascii(self)
}
/// 如果此切片为 [`is_ascii`](Self::is_ascii),则将其作为 [ASCII characters](`ascii::Char`) 的切片返回,否则返回 `None`。
///
#[unstable(feature = "ascii_char", issue = "110998")]
#[must_use]
#[inline]
pub const fn as_ascii(&self) -> Option<&[ascii::Char]> {
if self.is_ascii() {
// SAFETY: 刚刚检查它是 ASCII
Some(unsafe { self.as_ascii_unchecked() })
} else {
None
}
}
/// 将此字节片段转换为 ASCII 字符片段,而不检查它们是否有效。
///
///
/// # Safety
///
/// 切片中的每个字节都必须在 `0..=127` 中,否则就是 UB。
#[unstable(feature = "ascii_char", issue = "110998")]
#[must_use]
#[inline]
pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char] {
let byte_ptr: *const [u8] = self;
let ascii_ptr = byte_ptr as *const [ascii::Char];
// SAFETY: 调用者承诺所有字节都是 ASCII
unsafe { &*ascii_ptr }
}
/// 检查两个片是否是 ASCII 大小写不敏感的匹配项。
///
/// 与 `to_ascii_lowercase(a) == to_ascii_lowercase(b)` 相同,但不分配和复制临时文件。
///
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
#[must_use]
#[inline]
pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b))
}
/// 将该切片原位转换为其 ASCII 大写形式。
///
/// ASCII 字母 'a' 到 'z' 映射到 'A' 到 'Z',但是非 ASCII 字母不变。
///
/// 要返回新的大写值而不修改现有值,请使用 [`to_ascii_uppercase`]。
///
///
/// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
///
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
#[inline]
pub fn make_ascii_uppercase(&mut self) {
for byte in self {
byte.make_ascii_uppercase();
}
}
/// 将该切片原位转换为其 ASCII 小写等效项。
///
/// ASCII 字母 'A' 到 'Z' 映射到 'a' 到 'z',但是非 ASCII 字母不变。
///
/// 要返回新的小写值而不修改现有值,请使用 [`to_ascii_lowercase`]。
///
///
/// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
///
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
#[inline]
pub fn make_ascii_lowercase(&mut self) {
for byte in self {
byte.make_ascii_lowercase();
}
}
/// 返回一个迭代器,该迭代器产生此转义版本的一个 ASCII 字符串,将其视为一个 ASCII 字符串。
///
///
/// # Examples
///
/// ```
///
/// let s = b"0\t\r\n'\"\\\x9d";
/// let escaped = s.escape_ascii().to_string();
/// assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d");
/// ```
#[must_use = "this returns the escaped bytes as an iterator, \
without modifying the original"]
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
pub fn escape_ascii(&self) -> EscapeAscii<'_> {
EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
}
/// 返回删除了前导 ASCII 空白字节的字节切片。
///
/// 'Whitespace' 是指 `u8::is_ascii_whitespace` 使用的定义。
///
///
/// # Examples
///
/// ```
/// #![feature(byte_slice_trim_ascii)]
///
/// assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n");
/// assert_eq!(b" ".trim_ascii_start(), b"");
/// assert_eq!(b"".trim_ascii_start(), b"");
/// ```
#[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
pub const fn trim_ascii_start(&self) -> &[u8] {
let mut bytes = self;
// Note: 基于模式匹配的方法 (而不是索引) 允许将函数设为 const。
//
while let [first, rest @ ..] = bytes {
if first.is_ascii_whitespace() {
bytes = rest;
} else {
break;
}
}
bytes
}
/// 返回删除了尾随 ASCII 空白字节的字节切片。
///
/// 'Whitespace' 是指 `u8::is_ascii_whitespace` 使用的定义。
///
///
/// # Examples
///
/// ```
/// #![feature(byte_slice_trim_ascii)]
///
/// assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world");
/// assert_eq!(b" ".trim_ascii_end(), b"");
/// assert_eq!(b"".trim_ascii_end(), b"");
/// ```
#[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
pub const fn trim_ascii_end(&self) -> &[u8] {
let mut bytes = self;
// Note: 基于模式匹配的方法 (而不是索引) 允许将函数设为 const。
//
while let [rest @ .., last] = bytes {
if last.is_ascii_whitespace() {
bytes = rest;
} else {
break;
}
}
bytes
}
/// 返回删除了前导和尾随 ASCII 空白字节的字节切片。
///
///
/// 'Whitespace' 是指 `u8::is_ascii_whitespace` 使用的定义。
///
/// # Examples
///
/// ```
/// #![feature(byte_slice_trim_ascii)]
///
/// assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world");
/// assert_eq!(b" ".trim_ascii(), b"");
/// assert_eq!(b"".trim_ascii(), b"");
/// ```
///
#[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
pub const fn trim_ascii(&self) -> &[u8] {
self.trim_ascii_start().trim_ascii_end()
}
}
impl_fn_for_zst! {
#[derive(Clone)]
struct EscapeByte impl Fn = |byte: &u8| -> ascii::EscapeDefault {
ascii::escape_default(*byte)
};
}
/// 一个字节的转义版本的迭代器。
///
/// 这个 `struct` 是由 [`slice::escape_ascii`] 方法创建的。
/// 有关更多信息,请参见其文档。
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct EscapeAscii<'a> {
inner: iter::FlatMap<super::Iter<'a, u8>, ascii::EscapeDefault, EscapeByte>,
}
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> iter::Iterator for EscapeAscii<'a> {
type Item = u8;
#[inline]
fn next(&mut self) -> Option<u8> {
self.inner.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Fold: FnMut(Acc, Self::Item) -> R,
R: ops::Try<Output = Acc>,
{
self.inner.try_fold(init, fold)
}
#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.inner.fold(init, fold)
}
#[inline]
fn last(mut self) -> Option<u8> {
self.next_back()
}
}
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> {
fn next_back(&mut self) -> Option<u8> {
self.inner.next_back()
}
}
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> iter::FusedIterator for EscapeAscii<'a> {}
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> fmt::Display for EscapeAscii<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.clone().try_for_each(|b| f.write_char(b as char))
}
}
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> fmt::Debug for EscapeAscii<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EscapeAscii").finish_non_exhaustive()
}
}
/// 如果单词 `v` 中的任何字节为 nonascii (>=128),则返回 `true`。
/// 来自 `../str/mod.rs`,它对 utf8 验证执行类似的操作。
#[inline]
const fn contains_nonascii(v: usize) -> bool {
const NONASCII_MASK: usize = usize::repeat_u8(0x80);
(NONASCII_MASK & v) != 0
}
/// ASCII 测试*没有*一次块优化。
///
/// 它经过精心构造以生成漂亮的小代码 -- 它在 `-O` 中比 "obvious" 方式在 `-C opt-level=s` 下生成的代码小。
/// 如果您触摸它,请务必运行 (并在需要时更新) 组装测试。
///
#[unstable(feature = "str_internals", issue = "none")]
#[doc(hidden)]
#[inline]
pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool {
while let [rest @ .., last] = bytes {
if !last.is_ascii() {
break;
}
bytes = rest;
}
bytes.is_empty()
}
/// 优化的 ASCII 测试,将使用每次使用一次的操作,而不是一次使用字节的操作 (如果可能)。
///
/// 我们在这里使用的算法非常简单。如果 `s` 太短,我们只检查每个字节并完成它。Otherwise:
///
/// - 读取未对齐负载的第一个单词。。
/// - 对齐指针,读取后续单词,直到对齐负载结束。
/// - 从 `s` 读取未装载的最后一个 `usize`。
///
/// 如果这些负载中的任何一个产生了 `contains_nonascii` (above) 返回 true 的值,则我们知道答案为 false。
///
///
///
#[inline]
const fn is_ascii(s: &[u8]) -> bool {
const USIZE_SIZE: usize = mem::size_of::<usize>();
let len = s.len();
let align_offset = s.as_ptr().align_offset(USIZE_SIZE);
// 如果我们不能从一次单词的实现中获得任何收益,请回到标量循环。
//
// 我们还针对 `size_of::<usize>()` 不足以与 `usize` 对齐的体系结构执行此操作,因为这是一种奇怪的 edge 情况。
//
//
if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
return is_ascii_simple(s);
}
// 我们总是读第一个单词 unaligned,这意味着 `align_offset` 是
// 0,对于对齐的读取,我们将再次读取相同的值。
let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset };
let start = s.as_ptr();
// SAFETY: 我们在上面验证 `len < USIZE_SIZE`。
let first_word = unsafe { (start as *const usize).read_unaligned() };
if contains_nonascii(first_word) {
return false;
}
// 我们在上面对此进行了某种程度的隐式检查。
// 请注意,`offset_to_aligned` 是 `align_offset` 或 `USIZE_SIZE`,以上均已明确检查了两者。
//
debug_assert!(offset_to_aligned <= len);
// SAFETY: word_ptr 是 (正确对齐的) usize ptr,用于读取切片的中间块。
//
let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize };
// `byte_pos` 是 `word_ptr` 的字节索引,用于循环结束检查。
let mut byte_pos = offset_to_aligned;
// 偏执狂会检查对齐情况,因为我们将要进行一堆未对齐的负载。实际上,除非有 `align_offset` 中的错误,否则这应该是不可能的。
// 虽然此方法在 CTFE 中被允许虚假地失败,但如果它没有对齐信息,它应该更早地为 `align_offset` 提供 `usize::MAX`,通过标量路径而不是这个路径发送内容,因此如果可以访问,则此检查应该通过。
//
//
//
//
//
debug_assert!(word_ptr.is_aligned_to(mem::align_of::<usize>()));
// 读取后续的单词,直到最后一个对齐的单词为止 (不包括最后一个对齐的单词本身),以便稍后在尾部检查中完成,以确保尾部对于额外的分支 `byte_pos == len` 始终最多为一个 `usize`。
//
//
while byte_pos < len - USIZE_SIZE {
// 完好无损的检查,以确保读取的范围
debug_assert!(byte_pos + USIZE_SIZE <= len);
// 并且我们关于 `byte_pos` 的假设成立。
debug_assert!(matches!(
word_ptr.cast::<u8>().guaranteed_eq(start.wrapping_add(byte_pos)),
// 它们来自相同的分配,因此即使在 CTFE 中也有望始终匹配,但如果它拒绝比较它们也没关系,因为它只是一个调试检查。
//
//
None | Some(true),
));
// SAFETY: 我们知道 `word_ptr` 正确对齐 (因为 `align_offset`),并且我们知道 `word_ptr` 和末尾之间有足够的字节
//
let word = unsafe { word_ptr.read() };
if contains_nonascii(word) {
return false;
}
byte_pos += USIZE_SIZE;
// SAFETY: 我们知道 `byte_pos <= len - USIZE_SIZE`,这意味着在此 `add` 之后,`word_ptr` 最多只能是最后一个。
//
word_ptr = unsafe { word_ptr.add(1) };
}
// 进行健全性检查,确保仅剩 `usize` 个。
// 这应该由我们的循环条件来保证。
debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE);
// SAFETY: 这依赖于 `len >= USIZE_SIZE`,我们将在开始时对其进行检查。
let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() };
!contains_nonascii(last_word)
}