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
//! 在 ASCII `[u8]` 上的操作。

use crate::ascii;
use crate::fmt::{self, Write};
use crate::iter;
use crate::mem;
use crate::ops;

#[lang = "slice_u8"]
#[cfg(not(test))]
impl [u8] {
    /// 检查此切片中的所有字节是否都在 ASCII 范围内。
    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
    #[inline]
    pub fn is_ascii(&self) -> bool {
        is_ascii(self)
    }

    /// 检查两个片是否是 ASCII 大小写不敏感的匹配项。
    ///
    /// 与 `to_ascii_lowercase(a) == to_ascii_lowercase(b)` 相同,但不分配和复制临时文件。
    ///
    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
    #[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
    ///
    /// ```
    /// #![feature(inherent_ascii_escape)]
    ///
    /// let s = b"0\t\r\n'\"\\\x9d";
    /// let escaped = s.escape_ascii().to_string();
    /// assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d");
    /// ```
    #[unstable(feature = "inherent_ascii_escape", issue = "77174")]
    pub fn escape_ascii(&self) -> EscapeAscii<'_> {
        EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
    }
}

impl_fn_for_zst! {
    #[derive(Clone)]
    struct EscapeByte impl Fn = |byte: &u8| -> ascii::EscapeDefault {
        ascii::escape_default(*byte)
    };
}

/// 一个字节的转义版本的迭代器。
///
/// 这个 `struct` 是由 [`slice::escape_ascii`] 方法创建的。
/// 有关更多信息,请参见其文档。
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
#[derive(Clone)]
pub struct EscapeAscii<'a> {
    inner: iter::FlatMap<super::Iter<'a, u8>, ascii::EscapeDefault, EscapeByte>,
}

#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
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()
    }
}

#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> {
    fn next_back(&mut self) -> Option<u8> {
        self.inner.next_back()
    }
}
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {}
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
impl<'a> iter::FusedIterator for EscapeAscii<'a> {}
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
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))
    }
}
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
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]
fn contains_nonascii(v: usize) -> bool {
    const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize;
    (NONASCII_MASK & v) != 0
}

/// 优化的 ASCII 测试,将使用每次使用一次的操作,而不是一次使用字节的操作 (如果可能)。
///
/// 我们在这里使用的算法非常简单。如果 `s` 太短,我们只检查每个字节并完成它。Otherwise:
///
/// - 读取未对齐负载的第一个单词。。
/// - 对齐指针,读取后续单词,直到对齐负载结束。
/// - 从 `s` 读取未装载的最后一个 `usize`。
///
/// 如果这些负载中的任何一个产生了 `contains_nonascii` (above) 返回 true 的值,则我们知道答案为 false。
///
///
///
#[inline]
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 s.iter().all(|b| b.is_ascii());
    }

    // 我们总是读第一个单词 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` 中的错误,否则这应该是不可能的。
    //
    debug_assert_eq!((word_ptr as usize) % mem::align_of::<usize>(), 0);

    // 读取后续的单词,直到最后一个对齐的单词为止 (不包括最后一个对齐的单词本身),以便稍后在尾部检查中完成,以确保尾部对于额外的分支 `byte_pos == len` 始终最多为一个 `usize`。
    //
    //
    while byte_pos < len - USIZE_SIZE {
        debug_assert!(
            // 完好无损的检查,以确保读取的范围
            (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) &&
            // 并且我们关于 `byte_pos` 的假设成立。
            (word_ptr as usize) - (start as usize) == byte_pos
        );

        // 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)
}