Skip to main content

utf8_iter/
str.rs

1// Copyright Mozilla Foundation
2//
3// Licensed under the Apache License (Version 2.0), or the MIT license,
4// (the "Licenses") at your option. You may not use this file except in
5// compliance with one of the Licenses. You may obtain copies of the
6// Licenses at:
7//
8//    https://www.apache.org/licenses/LICENSE-2.0
9//    https://opensource.org/licenses/MIT
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the Licenses is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the Licenses for the specific language governing permissions and
15// limitations under the Licenses.
16
17#![allow(unsafe_code)] // Needed to make efficient use of the invariant of `str`
18
19use crate::Utf8Handler;
20
21use utf_types::utf8::Ascii;
22use utf_types::utf8::FourByteSequence;
23use utf_types::utf8::LeadForFourByte;
24use utf_types::utf8::LeadForMultiByte;
25use utf_types::utf8::LeadForThreeByte;
26use utf_types::utf8::ThreeByteSequence;
27use utf_types::utf8::TwoByteSequence;
28use utf_types::utf8::UnconstrainedContinuation;
29
30/// Iterator over guaranteed-well-formed UTF-8 with `Utf8Handler`.
31/// The `Utf8Handler::error()` is, of course, never called.
32#[derive(#[automatically_derived]impl<'a, H: ::core::fmt::Debug> ::core::fmt::Debug for
    CharsWithHandler<'a, H> where H: Utf8Handler {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "CharsWithHandler inner handler", &self.inner, &&self.handler)
    }
}Debug)]
33pub struct CharsWithHandler<'a, H>
34where
35    H: Utf8Handler,
36{
37    /// # Safety invariant
38    ///
39    /// `self.inner.as_slice()` is well-formed UTF-8, except when a method that
40    /// advances the `CharsWithHandler` as an iterator ()`next`, `next_back`,
41    /// `next_with_minimum_lead`) is in the process of reading a UTF-8 sequence
42    /// from `self.inner`.
43    ///
44    /// Note: For panic-safety, methods that change the state of `self.inner`
45    /// must first consume a full UTF-8 sequence (such that the above-stated
46    /// invariant holds again) before calling into `self.handler`, so that
47    /// the invariant of `self.inner` is upheld even if `self.handler`
48    /// panics.
49    inner: core::slice::Iter<'a, u8>,
50    handler: H,
51}
52
53impl<'a, H> CharsWithHandler<'a, H>
54where
55    H: Utf8Handler,
56{
57    #[inline(always)]
58    /// Creates the iterator from a `&str` and handler.
59    pub fn new(s: &'a str, handler: H) -> Self {
60        CharsWithHandler::<'a, H> {
61            inner: s.as_bytes().iter(),
62            handler,
63        }
64    }
65
66    /// Views the current remaining data in the iterator as a subslice
67    /// of the original slice.
68    #[inline(always)]
69    pub fn as_str(&self) -> &'a str {
70        // SAFETY: OK per the safety invariant of `self.inner`.
71        unsafe { core::str::from_utf8_unchecked(self.inner.as_slice()) }
72    }
73
74    /// Obtains a reference to the handler.
75    #[inline(always)]
76    pub fn handler(&self) -> &H {
77        &self.handler
78    }
79
80    /// Obtains the output for the next UTF-8 sequence whose lead byte
81    /// is greater than or equal to `multi_byte_lead` ignoring UTF-8
82    /// sequences before such a UTF-8 sequence. (Or `None` if the iterator
83    /// is consumed without finding such a UTF-8 sequence.)
84    #[inline(always)]
85    pub fn next_with_minimum_lead(
86        &mut self,
87        multi_byte_lead: LeadForMultiByte,
88    ) -> Option<H::Output> {
89        let bound = multi_byte_lead.to_u8();
90        loop {
91            let byte = *self.inner.next()?;
92            if byte < bound {
93                continue;
94            }
95            // SAFETY: From the safety invariant of `self.inner`
96            // we know that upon entry into this method `self.inner`
97            // represented well-formed UTF-8.
98            //
99            // We know that well-formed UTF-8 consists of three kinds
100            // of bytes:
101            // 1. ASCII bytes
102            // 2. Continuation bytes
103            // 3. Lead bytes for multi-byte sequences.
104            //
105            // We know that ASCII bytes and continuation bytes are
106            // below lead bytes for multi-byte sequences in unsigned
107            // integer order.
108            //
109            // Since `bound` is a lead byte for a multi-byte sequence,
110            // we know that ASCII bytes and continuation bytes take
111            // the `continue` path above.
112            //
113            // Therefore, we know that `byte` must now be a lead byte
114            // for a multibyte sequence. Since we know that `self.inner`
115            // represented well-formed UTF-8 upon entry into this method,
116            // we know that `self.inner` will yield the continuation bytes
117            // that are appropriate given `byte` as the lead byte for
118            // a multibyte sequence.
119            //
120            // INVARIANT UPHELD for `self.inner`:
121            // `consume_continuations` consumes the rest of the
122            // multi-byte UTF-8 sequence causing a complete sequence
123            // to be consumed.
124            return Some(unsafe { self.consume_continuations(byte) });
125        }
126    }
127
128    /// Consumes continuations given multi-byte lead byte `first`.
129    ///
130    /// # Safety
131    ///
132    /// `first` must be a lead byte for a multi-byte UTF-8 sequence and
133    /// the concatenation of `first` and `self.inner` must be well-formed
134    /// UTF-8.
135    ///
136    /// # Safety-usable invariant
137    ///
138    /// This method consumes from `self.inner` the continuation bytes that
139    /// belong to the multi-byte sequence started by `first`.
140    #[inline(always)]
141    unsafe fn consume_continuations(&mut self, first: u8) -> H::Output {
142        if true {
    if !LeadForMultiByte::is(first) {
        ::core::panicking::panic("assertion failed: LeadForMultiByte::is(first)")
    };
};debug_assert!(LeadForMultiByte::is(first));
143        // SAFETY: Since we don't have a single-byte sequence (per the
144        // safety invariant of this method) and we know the concatenation
145        // of `first` and `self.inner` is well-formed UTF-8, a second
146        // byte must exist.
147        let second = *unsafe { self.inner.next().unwrap_unchecked() };
148        if first < LeadForThreeByte::MIN as u8 {
149            // INVARIANT UPHELD for `self.inner`:
150            // We consumed a complete UTF-8 sequence; see "SAFETY"
151            // below.
152            return self.handler.two_byte(
153                // SAFETY: From the invariant of this method we know that
154                // `first` is a multibyte lead and `second` must be a
155                // continuation since the concatenation of `first` and
156                // `self.inner` was well-formed UTF-8 upon entry into
157                // the method. Since `first` is also less than the
158                // smallest lead for a three-byte sequence, it must be
159                // a lead for a two-byte sequence. Therefore, we have
160                // a two-byte UTF-8 sequence, which satisfies the invariant
161                // of `TwoByteSequence::new_unchecked()`.
162                unsafe { TwoByteSequence::new_unchecked(first, second) },
163            );
164        }
165        // SAFETY: Per the above two "SAFETY" comments, we don't have
166        // a single-byte or a two-byte sequence if we get this far, so
167        // a third byte must exist given that the concanation of `first`
168        // and `self.inner` was well-formed UTF-8 at the start of this
169        // method.
170        let third = *unsafe { self.inner.next().unwrap_unchecked() };
171        if first < LeadForFourByte::MIN as u8 {
172            // INVARIANT UPHELD for `self.inner`:
173            // We consumed a complete UTF-8 sequence; see "SAFETY"
174            // below.
175            return self.handler.three_byte(unsafe {
176                // SAFETY: From the safety invariant of this method
177                // we know that the concatenation of `first` and
178                // `self.inner` was well-formed UTF-8 at the start of
179                // this method. The safety invariant of this method
180                // rules out a single-byte sequence and we have already
181                // checked for and ruled out a two-byte sequence. Most
182                // recently, we ruled out a four-byte sequence. Therefore,
183                // we must have a three-byte sequence, which satisfies
184                // the safety invariant of `ThreeByteSequence::new_unchecked()`.
185                ThreeByteSequence::new_unchecked(first, second, third)
186            });
187        }
188        // SAFETY: Since we don't have a single-byte sequence, a two-byte
189        // sequence, or a three-byte sequence (per above) and we know
190        // from the safety invariant of this method that the concatenation
191        // of `first` and `self.inner` was well-formed UTF-8 upon entry
192        // into this method. Therefore, a fourth byte must exist.
193        let fourth = *unsafe { self.inner.next().unwrap_unchecked() };
194        // INVARIANT UPHELD for `self.inner`:
195        // We consumed a complete UTF-8 sequence; see "SAFETY"
196        // below.
197        self.handler.four_byte(
198            // SAFETY: From the safety invariant of this method
199            // we know that the concatenation of `first` and
200            // `self.inner` was well-formed UTF-8 at the start of
201            // this method. The safety invariant of this method
202            // rules out a single-byte sequence and we have already
203            // checked for and ruled out a two-byte and three-byte
204            // sequences. Therefore, we must have a four-byte
205            // sequence, which satisfies the safety invariant of
206            // `FourByteSequence::new_unchecked()`.
207            unsafe { FourByteSequence::new_unchecked(first, second, third, fourth) },
208        )
209    }
210}
211
212impl<'a, H> Clone for CharsWithHandler<'a, H>
213where
214    H: Utf8Handler + Clone,
215{
216    fn clone(&self) -> Self {
217        Self {
218            inner: self.inner.clone(),
219            handler: self.handler.clone(),
220        }
221    }
222}
223
224impl<'a, H> Iterator for CharsWithHandler<'a, H>
225where
226    H: Utf8Handler,
227{
228    type Item = H::Output;
229
230    #[inline(always)]
231    fn next(&mut self) -> Option<H::Output> {
232        let first = *self.inner.next()?;
233        if let Ok(ascii) = Ascii::try_new(first) {
234            return Some(self.handler.single_byte(ascii));
235        }
236        // SAFETY: Since `self.inner` represented well-formed UTF-8
237        // upon entry into this method and `first` is not ASCII,
238        // first must be a valid lead byte for a multi-byte UTF-8
239        // sequence.
240        //
241        // INVARIANT UPHELD for `self.inner`:
242        // `consume_continuations` consumes the rest of the
243        // multi-byte UTF-8 sequence causing a complete sequence
244        // to be consumed.
245        Some(unsafe { self.consume_continuations(first) })
246    }
247
248    #[inline(always)]
249    fn count(self) -> usize {
250        self.as_str().chars().count()
251    }
252
253    #[inline(always)]
254    fn size_hint(&self) -> (usize, Option<usize>) {
255        let len = self.as_str().len();
256        (len.div_ceil(4), Some(len))
257    }
258
259    #[inline(always)]
260    fn last(mut self) -> Option<Self::Item> {
261        // No need to go through the entire string.
262        self.next_back()
263    }
264}
265
266impl<'a, H> DoubleEndedIterator for CharsWithHandler<'a, H>
267where
268    H: Utf8Handler,
269{
270    #[inline(always)]
271    fn next_back(&mut self) -> Option<H::Output> {
272        let last = *self.inner.next_back()?;
273        if let Ok(ascii) = Ascii::try_new(last) {
274            return Some(self.handler.single_byte(ascii));
275        }
276        if true {
    if !UnconstrainedContinuation::is(last) {
        ::core::panicking::panic("assertion failed: UnconstrainedContinuation::is(last)")
    };
};debug_assert!(UnconstrainedContinuation::is(last));
277        // SAFETY: Since the last byte was not a single-byte sequence
278        // given that `self.inner` represented well-formed UTF-8 upon
279        // entry into this method, an earlier byte must exist.
280        let second_last = *unsafe { self.inner.next_back().unwrap_unchecked() };
281        if !UnconstrainedContinuation::is(second_last) {
282            // INVARIANT UPHELD for `self.inner`:
283            // We consumed a complete UTF-8 sequence; see "SAFETY" below.
284            return Some(self.handler.two_byte(
285                // SAFETY: Given that `self.inner` represented well-formed
286                // UTF-8 upon entry into this method and that `last` is a continuation
287                // but `second_last` is not, they must form a two-byte UTF-8
288                // sequence, which satisfies the safety invariant of
289                // `TwoByteSequence::new_unchecked()`.
290                unsafe { TwoByteSequence::new_unchecked(second_last, last) },
291            ));
292        }
293        // SAFETY: Given that `self.inner` represented well-formed
294        // UTF-8 upon entry into this method and we've ruled out a
295        // single-byte sequence and a two-byte sequence, an earlier
296        // byte must exist.
297        let third_last = *unsafe { self.inner.next_back().unwrap_unchecked() };
298        if !UnconstrainedContinuation::is(third_last) {
299            // INVARIANT UPHELD for `self.inner`:
300            // We consumed a complete UTF-8 sequence; see "SAFETY" below.
301            return Some(self.handler.three_byte(
302                // SAFETY: Given that `self.inner` represented well-formed
303                // UTF-8 upon entry into this method and that `last` and `second_last`
304                // are continuations but `third_last` is not, they must form a three-byte UTF-8
305                // sequence, which satisfies the safety invariant of `ThreeByteSequence::new_unchecked()`.
306                unsafe { ThreeByteSequence::new_unchecked(third_last, second_last, last) },
307            ));
308        }
309        // SAFETY: Given that `self.inner` represented well-formed
310        // UTF-8 upon entry into this method and we've ruled out a
311        // single-byte sequence, a two-byte sequence, and a three-byte
312        // sequences, an earlier byte must exist.
313        let fourth_last = *unsafe { self.inner.next_back().unwrap_unchecked() };
314        // INVARIANT UPHELD for `self.inner`:
315        // We consumed a complete UTF-8 sequence; see "SAFETY" below.
316        Some(self.handler.four_byte(
317            // SAFETY: Given that `self.inner` represented well-formed
318            // UTF-8 upon entry into this method and we've ruled out a
319            // single-byte sequence, a two-byte sequence, and a three-byte
320            // sequences, this must be a four-byte sequence, which satisfies
321            // the safety invariant of `FourByteSequence::new_unchecked()`.
322            unsafe { FourByteSequence::new_unchecked(fourth_last, third_last, second_last, last) },
323        ))
324    }
325}
326
327impl<H> core::iter::FusedIterator for CharsWithHandler<'_, H> where H: Utf8Handler {}