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(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 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 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 {}