/rust/registry/src/index.crates.io-1949cf8c6b5b557f/nom-8.0.0/src/traits.rs
Line | Count | Source |
1 | | //! Traits input types have to implement to work with nom combinators |
2 | | use core::iter::Enumerate; |
3 | | use core::str::CharIndices; |
4 | | |
5 | | use crate::error::{ErrorKind, ParseError}; |
6 | | use crate::internal::{Err, IResult, Needed}; |
7 | | use crate::lib::std::iter::Copied; |
8 | | use crate::lib::std::ops::{ |
9 | | Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, |
10 | | }; |
11 | | use crate::lib::std::slice::Iter; |
12 | | use crate::lib::std::str::from_utf8; |
13 | | use crate::lib::std::str::Chars; |
14 | | use crate::lib::std::str::FromStr; |
15 | | use crate::IsStreaming; |
16 | | use crate::Mode; |
17 | | |
18 | | #[cfg(feature = "alloc")] |
19 | | use crate::lib::std::string::String; |
20 | | #[cfg(feature = "alloc")] |
21 | | use crate::lib::std::vec::Vec; |
22 | | |
23 | | /// Parser input types must implement this trait |
24 | | pub trait Input: Clone + Sized { |
25 | | /// The current input type is a sequence of that `Item` type. |
26 | | /// |
27 | | /// Example: `u8` for `&[u8]` or `char` for `&str` |
28 | | type Item; |
29 | | |
30 | | /// An iterator over the input type, producing the item |
31 | | type Iter: Iterator<Item = Self::Item>; |
32 | | |
33 | | /// An iterator over the input type, producing the item and its byte position |
34 | | /// If we're iterating over `&str`, the position |
35 | | /// corresponds to the byte index of the character |
36 | | type IterIndices: Iterator<Item = (usize, Self::Item)>; |
37 | | |
38 | | /// Calculates the input length, as indicated by its name, |
39 | | /// and the name of the trait itself |
40 | | fn input_len(&self) -> usize; |
41 | | |
42 | | /// Returns a slice of `index` bytes. panics if index > length |
43 | | fn take(&self, index: usize) -> Self; |
44 | | /// Returns a slice starting at `index` bytes. panics if index > length |
45 | | fn take_from(&self, index: usize) -> Self; |
46 | | /// Split the stream at the `index` byte offset. panics if index > length |
47 | | fn take_split(&self, index: usize) -> (Self, Self); |
48 | | |
49 | | /// Returns the byte position of the first element satisfying the predicate |
50 | | fn position<P>(&self, predicate: P) -> Option<usize> |
51 | | where |
52 | | P: Fn(Self::Item) -> bool; |
53 | | |
54 | | /// Returns an iterator over the elements |
55 | | fn iter_elements(&self) -> Self::Iter; |
56 | | /// Returns an iterator over the elements and their byte offsets |
57 | | fn iter_indices(&self) -> Self::IterIndices; |
58 | | |
59 | | /// Get the byte offset from the element's position in the stream |
60 | | fn slice_index(&self, count: usize) -> Result<usize, Needed>; |
61 | | |
62 | | /// Looks for the first element of the input type for which the condition returns true, |
63 | | /// and returns the input up to this position. |
64 | | /// |
65 | | /// *streaming version*: If no element is found matching the condition, this will return `Incomplete` |
66 | 0 | fn split_at_position<P, E: ParseError<Self>>(&self, predicate: P) -> IResult<Self, Self, E> |
67 | 0 | where |
68 | 0 | P: Fn(Self::Item) -> bool, |
69 | | { |
70 | 0 | match self.position(predicate) { |
71 | 0 | Some(n) => Ok(self.take_split(n)), |
72 | 0 | None => Err(Err::Incomplete(Needed::new(1))), |
73 | | } |
74 | 0 | } |
75 | | |
76 | | /// Looks for the first element of the input type for which the condition returns true |
77 | | /// and returns the input up to this position. |
78 | | /// |
79 | | /// Fails if the produced slice is empty. |
80 | | /// |
81 | | /// *streaming version*: If no element is found matching the condition, this will return `Incomplete` |
82 | 0 | fn split_at_position1<P, E: ParseError<Self>>( |
83 | 0 | &self, |
84 | 0 | predicate: P, |
85 | 0 | e: ErrorKind, |
86 | 0 | ) -> IResult<Self, Self, E> |
87 | 0 | where |
88 | 0 | P: Fn(Self::Item) -> bool, |
89 | | { |
90 | 0 | match self.position(predicate) { |
91 | 0 | Some(0) => Err(Err::Error(E::from_error_kind(self.clone(), e))), |
92 | 0 | Some(n) => Ok(self.take_split(n)), |
93 | 0 | None => Err(Err::Incomplete(Needed::new(1))), |
94 | | } |
95 | 0 | } |
96 | | |
97 | | /// Looks for the first element of the input type for which the condition returns true, |
98 | | /// and returns the input up to this position. |
99 | | /// |
100 | | /// *complete version*: If no element is found matching the condition, this will return the whole input |
101 | 0 | fn split_at_position_complete<P, E: ParseError<Self>>( |
102 | 0 | &self, |
103 | 0 | predicate: P, |
104 | 0 | ) -> IResult<Self, Self, E> |
105 | 0 | where |
106 | 0 | P: Fn(Self::Item) -> bool, |
107 | | { |
108 | 0 | match self.split_at_position(predicate) { |
109 | 0 | Err(Err::Incomplete(_)) => Ok(self.take_split(self.input_len())), |
110 | 0 | res => res, |
111 | | } |
112 | 0 | } |
113 | | |
114 | | /// Looks for the first element of the input type for which the condition returns true |
115 | | /// and returns the input up to this position. |
116 | | /// |
117 | | /// Fails if the produced slice is empty. |
118 | | /// |
119 | | /// *complete version*: If no element is found matching the condition, this will return the whole input |
120 | 0 | fn split_at_position1_complete<P, E: ParseError<Self>>( |
121 | 0 | &self, |
122 | 0 | predicate: P, |
123 | 0 | e: ErrorKind, |
124 | 0 | ) -> IResult<Self, Self, E> |
125 | 0 | where |
126 | 0 | P: Fn(Self::Item) -> bool, |
127 | | { |
128 | 0 | match self.split_at_position1(predicate, e) { |
129 | | Err(Err::Incomplete(_)) => { |
130 | 0 | if self.input_len() == 0 { |
131 | 0 | Err(Err::Error(E::from_error_kind(self.clone(), e))) |
132 | | } else { |
133 | 0 | Ok(self.take_split(self.input_len())) |
134 | | } |
135 | | } |
136 | 0 | res => res, |
137 | | } |
138 | 0 | } |
139 | | |
140 | | /// mode version of split_at_position |
141 | 0 | fn split_at_position_mode<OM: crate::OutputMode, P, E: ParseError<Self>>( |
142 | 0 | &self, |
143 | 0 | predicate: P, |
144 | 0 | ) -> crate::PResult<OM, Self, Self, E> |
145 | 0 | where |
146 | 0 | P: Fn(Self::Item) -> bool, |
147 | | { |
148 | 0 | match self.position(predicate) { |
149 | 0 | Some(n) => Ok((self.take_from(n), OM::Output::bind(|| self.take(n)))), |
150 | | None => { |
151 | 0 | if OM::Incomplete::is_streaming() { |
152 | 0 | Err(Err::Incomplete(Needed::new(1))) |
153 | | } else { |
154 | 0 | let len = self.input_len(); |
155 | 0 | Ok((self.take_from(len), OM::Output::bind(|| self.take(len)))) |
156 | | } |
157 | | } |
158 | | } |
159 | 0 | } |
160 | | |
161 | | /// mode version of split_at_position |
162 | 0 | fn split_at_position_mode1<OM: crate::OutputMode, P, E: ParseError<Self>>( |
163 | 0 | &self, |
164 | 0 | predicate: P, |
165 | 0 | e: ErrorKind, |
166 | 0 | ) -> crate::PResult<OM, Self, Self, E> |
167 | 0 | where |
168 | 0 | P: Fn(Self::Item) -> bool, |
169 | | { |
170 | 0 | match self.position(predicate) { |
171 | 0 | Some(0) => Err(Err::Error(OM::Error::bind(|| { |
172 | 0 | E::from_error_kind(self.clone(), e) |
173 | 0 | }))), |
174 | 0 | Some(n) => Ok((self.take_from(n), OM::Output::bind(|| self.take(n)))), |
175 | | None => { |
176 | 0 | if OM::Incomplete::is_streaming() { |
177 | 0 | Err(Err::Incomplete(Needed::new(1))) |
178 | | } else { |
179 | 0 | let len = self.input_len(); |
180 | 0 | if len == 0 { |
181 | 0 | Err(Err::Error(OM::Error::bind(|| { |
182 | 0 | E::from_error_kind(self.clone(), e) |
183 | 0 | }))) |
184 | | } else { |
185 | 0 | Ok((self.take_from(len), OM::Output::bind(|| self.take(len)))) |
186 | | } |
187 | | } |
188 | | } |
189 | | } |
190 | 0 | } |
191 | | } |
192 | | |
193 | | impl<'a> Input for &'a [u8] { |
194 | | type Item = u8; |
195 | | type Iter = Copied<Iter<'a, u8>>; |
196 | | type IterIndices = Enumerate<Self::Iter>; |
197 | | |
198 | 0 | fn input_len(&self) -> usize { |
199 | 0 | self.len() |
200 | 0 | } |
201 | | |
202 | | #[inline] |
203 | 0 | fn take(&self, index: usize) -> Self { |
204 | 0 | &self[0..index] |
205 | 0 | } |
206 | | |
207 | 0 | fn take_from(&self, index: usize) -> Self { |
208 | 0 | &self[index..] |
209 | 0 | } |
210 | | #[inline] |
211 | 0 | fn take_split(&self, index: usize) -> (Self, Self) { |
212 | 0 | let (prefix, suffix) = self.split_at(index); |
213 | 0 | (suffix, prefix) |
214 | 0 | } |
215 | | |
216 | | #[inline] |
217 | 0 | fn position<P>(&self, predicate: P) -> Option<usize> |
218 | 0 | where |
219 | 0 | P: Fn(Self::Item) -> bool, |
220 | | { |
221 | 0 | self.iter().position(|b| predicate(*b)) |
222 | 0 | } |
223 | | |
224 | | #[inline] |
225 | 0 | fn iter_elements(&self) -> Self::Iter { |
226 | 0 | self.iter().copied() |
227 | 0 | } |
228 | | |
229 | | #[inline] |
230 | 0 | fn iter_indices(&self) -> Self::IterIndices { |
231 | 0 | self.iter_elements().enumerate() |
232 | 0 | } |
233 | | |
234 | | #[inline] |
235 | 0 | fn slice_index(&self, count: usize) -> Result<usize, Needed> { |
236 | 0 | if self.len() >= count { |
237 | 0 | Ok(count) |
238 | | } else { |
239 | 0 | Err(Needed::new(count - self.len())) |
240 | | } |
241 | 0 | } |
242 | | |
243 | | #[inline(always)] |
244 | 0 | fn split_at_position<P, E: ParseError<Self>>(&self, predicate: P) -> IResult<Self, Self, E> |
245 | 0 | where |
246 | 0 | P: Fn(Self::Item) -> bool, |
247 | | { |
248 | 0 | match self.iter().position(|c| predicate(*c)) { |
249 | 0 | Some(i) => Ok(self.take_split(i)), |
250 | 0 | None => Err(Err::Incomplete(Needed::new(1))), |
251 | | } |
252 | 0 | } |
253 | | |
254 | | #[inline(always)] |
255 | 0 | fn split_at_position1<P, E: ParseError<Self>>( |
256 | 0 | &self, |
257 | 0 | predicate: P, |
258 | 0 | e: ErrorKind, |
259 | 0 | ) -> IResult<Self, Self, E> |
260 | 0 | where |
261 | 0 | P: Fn(Self::Item) -> bool, |
262 | | { |
263 | 0 | match self.iter().position(|c| predicate(*c)) { |
264 | 0 | Some(0) => Err(Err::Error(E::from_error_kind(self, e))), |
265 | 0 | Some(i) => Ok(self.take_split(i)), |
266 | 0 | None => Err(Err::Incomplete(Needed::new(1))), |
267 | | } |
268 | 0 | } |
269 | | |
270 | 0 | fn split_at_position_complete<P, E: ParseError<Self>>( |
271 | 0 | &self, |
272 | 0 | predicate: P, |
273 | 0 | ) -> IResult<Self, Self, E> |
274 | 0 | where |
275 | 0 | P: Fn(Self::Item) -> bool, |
276 | | { |
277 | 0 | match self.iter().position(|c| predicate(*c)) { |
278 | 0 | Some(i) => Ok(self.take_split(i)), |
279 | 0 | None => Ok(self.take_split(self.len())), |
280 | | } |
281 | 0 | } |
282 | | |
283 | | #[inline(always)] |
284 | 0 | fn split_at_position1_complete<P, E: ParseError<Self>>( |
285 | 0 | &self, |
286 | 0 | predicate: P, |
287 | 0 | e: ErrorKind, |
288 | 0 | ) -> IResult<Self, Self, E> |
289 | 0 | where |
290 | 0 | P: Fn(Self::Item) -> bool, |
291 | | { |
292 | 0 | match self.iter().position(|c| predicate(*c)) { |
293 | 0 | Some(0) => Err(Err::Error(E::from_error_kind(self, e))), |
294 | 0 | Some(i) => Ok(self.take_split(i)), |
295 | | None => { |
296 | 0 | if self.is_empty() { |
297 | 0 | Err(Err::Error(E::from_error_kind(self, e))) |
298 | | } else { |
299 | 0 | Ok(self.take_split(self.len())) |
300 | | } |
301 | | } |
302 | | } |
303 | 0 | } |
304 | | |
305 | | /// mode version of split_at_position |
306 | | #[inline(always)] |
307 | 0 | fn split_at_position_mode<OM: crate::OutputMode, P, E: ParseError<Self>>( |
308 | 0 | &self, |
309 | 0 | predicate: P, |
310 | 0 | ) -> crate::PResult<OM, Self, Self, E> |
311 | 0 | where |
312 | 0 | P: Fn(Self::Item) -> bool, |
313 | | { |
314 | 0 | match self.iter().position(|c| predicate(*c)) { |
315 | 0 | Some(n) => Ok((self.take_from(n), OM::Output::bind(|| self.take(n)))), |
316 | | None => { |
317 | 0 | if OM::Incomplete::is_streaming() { |
318 | 0 | Err(Err::Incomplete(Needed::new(1))) |
319 | | } else { |
320 | | Ok(( |
321 | 0 | self.take_from(self.len()), |
322 | 0 | OM::Output::bind(|| self.take(self.len())), |
323 | | )) |
324 | | } |
325 | | } |
326 | | } |
327 | 0 | } |
328 | | |
329 | | /// mode version of split_at_position |
330 | | #[inline(always)] |
331 | 0 | fn split_at_position_mode1<OM: crate::OutputMode, P, E: ParseError<Self>>( |
332 | 0 | &self, |
333 | 0 | predicate: P, |
334 | 0 | e: ErrorKind, |
335 | 0 | ) -> crate::PResult<OM, Self, Self, E> |
336 | 0 | where |
337 | 0 | P: Fn(Self::Item) -> bool, |
338 | | { |
339 | 0 | match self.iter().position(|c| predicate(*c)) { |
340 | 0 | Some(0) => Err(Err::Error(OM::Error::bind(|| E::from_error_kind(self, e)))), |
341 | 0 | Some(n) => Ok((self.take_from(n), OM::Output::bind(|| self.take(n)))), |
342 | | None => { |
343 | 0 | if OM::Incomplete::is_streaming() { |
344 | 0 | Err(Err::Incomplete(Needed::new(1))) |
345 | 0 | } else if self.is_empty() { |
346 | 0 | Err(Err::Error(OM::Error::bind(|| E::from_error_kind(self, e)))) |
347 | | } else { |
348 | | Ok(( |
349 | 0 | self.take_from(self.len()), |
350 | 0 | OM::Output::bind(|| self.take(self.len())), |
351 | | )) |
352 | | } |
353 | | } |
354 | | } |
355 | 0 | } |
356 | | } |
357 | | |
358 | | impl<'a> Input for &'a str { |
359 | | type Item = char; |
360 | | type Iter = Chars<'a>; |
361 | | type IterIndices = CharIndices<'a>; |
362 | | |
363 | 0 | fn input_len(&self) -> usize { |
364 | 0 | self.len() |
365 | 0 | } |
366 | | |
367 | | #[inline] |
368 | 0 | fn take(&self, index: usize) -> Self { |
369 | 0 | &self[..index] |
370 | 0 | } Unexecuted instantiation: <&str as nom::traits::Input>::take Unexecuted instantiation: <&str as nom::traits::Input>::take |
371 | | |
372 | | #[inline] |
373 | 0 | fn take_from(&self, index: usize) -> Self { |
374 | 0 | &self[index..] |
375 | 0 | } Unexecuted instantiation: <&str as nom::traits::Input>::take_from Unexecuted instantiation: <&str as nom::traits::Input>::take_from |
376 | | |
377 | | // return byte index |
378 | | #[inline] |
379 | 0 | fn take_split(&self, index: usize) -> (Self, Self) { |
380 | 0 | let (prefix, suffix) = self.split_at(index); |
381 | 0 | (suffix, prefix) |
382 | 0 | } Unexecuted instantiation: <&str as nom::traits::Input>::take_split Unexecuted instantiation: <&str as nom::traits::Input>::take_split |
383 | | |
384 | 0 | fn position<P>(&self, predicate: P) -> Option<usize> |
385 | 0 | where |
386 | 0 | P: Fn(Self::Item) -> bool, |
387 | | { |
388 | 0 | self.find(predicate) |
389 | 0 | } |
390 | | |
391 | | #[inline] |
392 | 0 | fn iter_elements(&self) -> Self::Iter { |
393 | 0 | self.chars() |
394 | 0 | } Unexecuted instantiation: <&str as nom::traits::Input>::iter_elements Unexecuted instantiation: <&str as nom::traits::Input>::iter_elements |
395 | | |
396 | | #[inline] |
397 | 0 | fn iter_indices(&self) -> Self::IterIndices { |
398 | 0 | self.char_indices() |
399 | 0 | } |
400 | | |
401 | | #[inline] |
402 | 0 | fn slice_index(&self, count: usize) -> Result<usize, Needed> { |
403 | 0 | let mut cnt = 0; |
404 | 0 | for (index, _) in self.char_indices() { |
405 | 0 | if cnt == count { |
406 | 0 | return Ok(index); |
407 | 0 | } |
408 | 0 | cnt += 1; |
409 | | } |
410 | 0 | if cnt == count { |
411 | 0 | return Ok(self.len()); |
412 | 0 | } |
413 | 0 | Err(Needed::Unknown) |
414 | 0 | } |
415 | | |
416 | | #[inline(always)] |
417 | 0 | fn split_at_position<P, E: ParseError<Self>>(&self, predicate: P) -> IResult<Self, Self, E> |
418 | 0 | where |
419 | 0 | P: Fn(Self::Item) -> bool, |
420 | | { |
421 | 0 | match self.find(predicate) { |
422 | | // The position i is returned from str::find() which means it is within the bounds of the string |
423 | 0 | Some(i) => { |
424 | 0 | let (str1, str2) = self.split_at(i); |
425 | 0 | Ok((str2, str1)) |
426 | | } |
427 | 0 | None => Err(Err::Incomplete(Needed::new(1))), |
428 | | } |
429 | 0 | } |
430 | | |
431 | | #[inline(always)] |
432 | 0 | fn split_at_position1<P, E: ParseError<Self>>( |
433 | 0 | &self, |
434 | 0 | predicate: P, |
435 | 0 | e: ErrorKind, |
436 | 0 | ) -> IResult<Self, Self, E> |
437 | 0 | where |
438 | 0 | P: Fn(Self::Item) -> bool, |
439 | | { |
440 | 0 | match self.find(predicate) { |
441 | 0 | Some(0) => Err(Err::Error(E::from_error_kind(self, e))), |
442 | | // The position i is returned from str::find() which means it is within the bounds of the string |
443 | 0 | Some(i) => { |
444 | 0 | let (str1, str2) = self.split_at(i); |
445 | 0 | Ok((str2, str1)) |
446 | | } |
447 | 0 | None => Err(Err::Incomplete(Needed::new(1))), |
448 | | } |
449 | 0 | } |
450 | | |
451 | | #[inline(always)] |
452 | 0 | fn split_at_position_complete<P, E: ParseError<Self>>( |
453 | 0 | &self, |
454 | 0 | predicate: P, |
455 | 0 | ) -> IResult<Self, Self, E> |
456 | 0 | where |
457 | 0 | P: Fn(Self::Item) -> bool, |
458 | | { |
459 | 0 | match self.find(predicate) { |
460 | | // The position i is returned from str::find() which means it is within the bounds of the string |
461 | 0 | Some(i) => { |
462 | 0 | let (str1, str2) = self.split_at(i); |
463 | 0 | Ok((str2, str1)) |
464 | | } |
465 | 0 | None => Ok(self.split_at(0)), |
466 | | } |
467 | 0 | } Unexecuted instantiation: <&str as nom::traits::Input>::split_at_position_complete::<nom::character::complete::multispace0<&str, nom::error::Error<&str>>::{closure#0}, nom::error::Error<&str>>Unexecuted instantiation: <&str as nom::traits::Input>::split_at_position_complete::<nom::character::complete::space0<&str, nom::error::Error<&str>>::{closure#0}, nom::error::Error<&str>>Unexecuted instantiation: <&str as nom::traits::Input>::split_at_position_complete::<_, _> |
468 | | |
469 | | #[inline(always)] |
470 | 0 | fn split_at_position1_complete<P, E: ParseError<Self>>( |
471 | 0 | &self, |
472 | 0 | predicate: P, |
473 | 0 | e: ErrorKind, |
474 | 0 | ) -> IResult<Self, Self, E> |
475 | 0 | where |
476 | 0 | P: Fn(Self::Item) -> bool, |
477 | | { |
478 | 0 | match self.find(predicate) { |
479 | 0 | Some(0) => Err(Err::Error(E::from_error_kind(self, e))), |
480 | | // The position i is returned from str::find() which means it is within the bounds of the string |
481 | 0 | Some(i) => { |
482 | 0 | let (str1, str2) = self.split_at(i); |
483 | 0 | Ok((str2, str1)) |
484 | | } |
485 | | None => { |
486 | 0 | if self.is_empty() { |
487 | 0 | Err(Err::Error(E::from_error_kind(self, e))) |
488 | | } else { |
489 | | // the end of slice is a char boundary |
490 | 0 | let (str1, str2) = self.split_at(self.len()); |
491 | 0 | Ok((str2, str1)) |
492 | | } |
493 | | } |
494 | | } |
495 | 0 | } Unexecuted instantiation: <&str as nom::traits::Input>::split_at_position1_complete::<nom::character::complete::multispace1<&str, nom::error::Error<&str>>::{closure#0}, nom::error::Error<&str>>Unexecuted instantiation: <&str as nom::traits::Input>::split_at_position1_complete::<nom::character::complete::digit1<&str, nom::error::Error<&str>>::{closure#0}, nom::error::Error<&str>>Unexecuted instantiation: <&str as nom::traits::Input>::split_at_position1_complete::<nom::character::complete::space1<&str, nom::error::Error<&str>>::{closure#0}, nom::error::Error<&str>>Unexecuted instantiation: <&str as nom::traits::Input>::split_at_position1_complete::<_, _> |
496 | | |
497 | | /// mode version of split_at_position |
498 | | #[inline(always)] |
499 | 0 | fn split_at_position_mode<OM: crate::OutputMode, P, E: ParseError<Self>>( |
500 | 0 | &self, |
501 | 0 | predicate: P, |
502 | 0 | ) -> crate::PResult<OM, Self, Self, E> |
503 | 0 | where |
504 | 0 | P: Fn(Self::Item) -> bool, |
505 | | { |
506 | 0 | match self.find(predicate) { |
507 | 0 | Some(n) => unsafe { |
508 | | // find() returns a byte index that is already in the slice at a char boundary |
509 | | Ok(( |
510 | 0 | self.get_unchecked(n..), |
511 | 0 | OM::Output::bind(|| self.get_unchecked(..n)), |
512 | | )) |
513 | | }, |
514 | | None => { |
515 | 0 | if OM::Incomplete::is_streaming() { |
516 | 0 | Err(Err::Incomplete(Needed::new(1))) |
517 | | } else { |
518 | | // the end of slice is a char boundary |
519 | | unsafe { |
520 | | Ok(( |
521 | 0 | self.get_unchecked(self.len()..), |
522 | 0 | OM::Output::bind(|| self.get_unchecked(..self.len())), |
523 | | )) |
524 | | } |
525 | | } |
526 | | } |
527 | | } |
528 | 0 | } |
529 | | |
530 | | /// mode version of split_at_position |
531 | | #[inline(always)] |
532 | 0 | fn split_at_position_mode1<OM: crate::OutputMode, P, E: ParseError<Self>>( |
533 | 0 | &self, |
534 | 0 | predicate: P, |
535 | 0 | e: ErrorKind, |
536 | 0 | ) -> crate::PResult<OM, Self, Self, E> |
537 | 0 | where |
538 | 0 | P: Fn(Self::Item) -> bool, |
539 | | { |
540 | 0 | match self.find(predicate) { |
541 | 0 | Some(0) => Err(Err::Error(OM::Error::bind(|| E::from_error_kind(self, e)))), |
542 | 0 | Some(n) => unsafe { |
543 | | // find() returns a byte index that is already in the slice at a char boundary |
544 | | Ok(( |
545 | 0 | self.get_unchecked(n..), |
546 | 0 | OM::Output::bind(|| self.get_unchecked(..n)), |
547 | | )) |
548 | | }, |
549 | | None => { |
550 | 0 | if OM::Incomplete::is_streaming() { |
551 | 0 | Err(Err::Incomplete(Needed::new(1))) |
552 | 0 | } else if self.is_empty() { |
553 | 0 | Err(Err::Error(OM::Error::bind(|| E::from_error_kind(self, e)))) |
554 | | } else { |
555 | | // the end of slice is a char boundary |
556 | | unsafe { |
557 | | Ok(( |
558 | 0 | self.get_unchecked(self.len()..), |
559 | 0 | OM::Output::bind(|| self.get_unchecked(..self.len())), |
560 | | )) |
561 | | } |
562 | | } |
563 | | } |
564 | | } |
565 | 0 | } |
566 | | } |
567 | | |
568 | | /// Useful functions to calculate the offset between slices and show a hexdump of a slice |
569 | | pub trait Offset { |
570 | | /// Offset between the first byte of self and the first byte of the argument |
571 | | /// the argument must be a part of self, otherwise this can fail with arithmetic |
572 | | /// underflows as it compares byte offsets |
573 | | fn offset(&self, second: &Self) -> usize; |
574 | | } |
575 | | |
576 | | impl Offset for [u8] { |
577 | 0 | fn offset(&self, second: &Self) -> usize { |
578 | 0 | let fst = self.as_ptr(); |
579 | 0 | let snd = second.as_ptr(); |
580 | | |
581 | 0 | snd as usize - fst as usize |
582 | 0 | } |
583 | | } |
584 | | |
585 | | impl<'a> Offset for &'a [u8] { |
586 | 0 | fn offset(&self, second: &Self) -> usize { |
587 | 0 | let fst = self.as_ptr(); |
588 | 0 | let snd = second.as_ptr(); |
589 | | |
590 | 0 | snd as usize - fst as usize |
591 | 0 | } |
592 | | } |
593 | | |
594 | | impl Offset for str { |
595 | 0 | fn offset(&self, second: &Self) -> usize { |
596 | 0 | let fst = self.as_ptr(); |
597 | 0 | let snd = second.as_ptr(); |
598 | | |
599 | 0 | snd as usize - fst as usize |
600 | 0 | } |
601 | | } |
602 | | |
603 | | impl<'a> Offset for &'a str { |
604 | 0 | fn offset(&self, second: &Self) -> usize { |
605 | 0 | let fst = self.as_ptr(); |
606 | 0 | let snd = second.as_ptr(); |
607 | | |
608 | 0 | snd as usize - fst as usize |
609 | 0 | } |
610 | | } |
611 | | |
612 | | /// Helper trait for types that can be viewed as a byte slice |
613 | | pub trait AsBytes { |
614 | | /// Casts the input type to a byte slice |
615 | | fn as_bytes(&self) -> &[u8]; |
616 | | } |
617 | | |
618 | | impl<'a> AsBytes for &'a str { |
619 | | #[inline(always)] |
620 | 0 | fn as_bytes(&self) -> &[u8] { |
621 | 0 | (*self).as_bytes() |
622 | 0 | } |
623 | | } |
624 | | |
625 | | impl AsBytes for str { |
626 | | #[inline(always)] |
627 | 0 | fn as_bytes(&self) -> &[u8] { |
628 | 0 | self.as_ref() |
629 | 0 | } |
630 | | } |
631 | | |
632 | | impl<'a> AsBytes for &'a [u8] { |
633 | | #[inline(always)] |
634 | 0 | fn as_bytes(&self) -> &[u8] { |
635 | 0 | self |
636 | 0 | } |
637 | | } |
638 | | |
639 | | impl AsBytes for [u8] { |
640 | | #[inline(always)] |
641 | 0 | fn as_bytes(&self) -> &[u8] { |
642 | 0 | self |
643 | 0 | } |
644 | | } |
645 | | |
646 | | impl<'a, const N: usize> AsBytes for &'a [u8; N] { |
647 | | #[inline(always)] |
648 | 0 | fn as_bytes(&self) -> &[u8] { |
649 | 0 | self.as_slice() |
650 | 0 | } |
651 | | } |
652 | | |
653 | | impl<const N: usize> AsBytes for [u8; N] { |
654 | | #[inline(always)] |
655 | 0 | fn as_bytes(&self) -> &[u8] { |
656 | 0 | self |
657 | 0 | } |
658 | | } |
659 | | |
660 | | /// Transforms common types to a char for basic token parsing |
661 | | #[allow(clippy::len_without_is_empty)] |
662 | | pub trait AsChar: Copy { |
663 | | /// makes a char from self |
664 | | fn as_char(self) -> char; |
665 | | |
666 | | /// Tests that self is an alphabetic character |
667 | | /// |
668 | | /// Warning: for `&str` it recognizes alphabetic |
669 | | /// characters outside of the 52 ASCII letters |
670 | | fn is_alpha(self) -> bool; |
671 | | |
672 | | /// Tests that self is an alphabetic character |
673 | | /// or a decimal digit |
674 | | fn is_alphanum(self) -> bool; |
675 | | /// Tests that self is a decimal digit |
676 | | fn is_dec_digit(self) -> bool; |
677 | | /// Tests that self is an hex digit |
678 | | fn is_hex_digit(self) -> bool; |
679 | | /// Tests that self is an octal digit |
680 | | fn is_oct_digit(self) -> bool; |
681 | | /// Tests that self is a binary digit |
682 | | fn is_bin_digit(self) -> bool; |
683 | | /// Gets the len in bytes for self |
684 | | fn len(self) -> usize; |
685 | | /// Tests that self is ASCII space or tab |
686 | | fn is_space(self) -> bool; |
687 | | /// Tests if byte is ASCII newline: \n |
688 | | fn is_newline(self) -> bool; |
689 | | } |
690 | | |
691 | | impl AsChar for u8 { |
692 | | #[inline] |
693 | 0 | fn as_char(self) -> char { |
694 | 0 | self as char |
695 | 0 | } |
696 | | #[inline] |
697 | 0 | fn is_alpha(self) -> bool { |
698 | 0 | matches!(self, 0x41..=0x5A | 0x61..=0x7A) |
699 | 0 | } |
700 | | #[inline] |
701 | 0 | fn is_alphanum(self) -> bool { |
702 | 0 | self.is_alpha() || self.is_dec_digit() |
703 | 0 | } |
704 | | #[inline] |
705 | 0 | fn is_dec_digit(self) -> bool { |
706 | 0 | matches!(self, 0x30..=0x39) |
707 | 0 | } |
708 | | #[inline] |
709 | 0 | fn is_hex_digit(self) -> bool { |
710 | 0 | matches!(self, 0x30..=0x39 | 0x41..=0x46 | 0x61..=0x66) |
711 | 0 | } |
712 | | #[inline] |
713 | 0 | fn is_oct_digit(self) -> bool { |
714 | 0 | matches!(self, 0x30..=0x37) |
715 | 0 | } |
716 | | #[inline] |
717 | 0 | fn is_bin_digit(self) -> bool { |
718 | 0 | matches!(self, 0x30..=0x31) |
719 | 0 | } |
720 | | #[inline] |
721 | 0 | fn len(self) -> usize { |
722 | 0 | 1 |
723 | 0 | } |
724 | | #[inline] |
725 | 0 | fn is_space(self) -> bool { |
726 | 0 | self == b' ' || self == b'\t' |
727 | 0 | } |
728 | 0 | fn is_newline(self) -> bool { |
729 | 0 | self == b'\n' |
730 | 0 | } |
731 | | } |
732 | | impl<'a> AsChar for &'a u8 { |
733 | | #[inline] |
734 | 0 | fn as_char(self) -> char { |
735 | 0 | *self as char |
736 | 0 | } |
737 | | #[inline] |
738 | 0 | fn is_alpha(self) -> bool { |
739 | 0 | matches!(*self, 0x41..=0x5A | 0x61..=0x7A) |
740 | 0 | } |
741 | | #[inline] |
742 | 0 | fn is_alphanum(self) -> bool { |
743 | 0 | self.is_alpha() || self.is_dec_digit() |
744 | 0 | } |
745 | | #[inline] |
746 | 0 | fn is_dec_digit(self) -> bool { |
747 | 0 | matches!(*self, 0x30..=0x39) |
748 | 0 | } |
749 | | #[inline] |
750 | 0 | fn is_hex_digit(self) -> bool { |
751 | 0 | matches!(*self, 0x30..=0x39 | 0x41..=0x46 | 0x61..=0x66) |
752 | 0 | } |
753 | | #[inline] |
754 | 0 | fn is_oct_digit(self) -> bool { |
755 | 0 | matches!(*self, 0x30..=0x37) |
756 | 0 | } |
757 | | #[inline] |
758 | 0 | fn is_bin_digit(self) -> bool { |
759 | 0 | matches!(*self, 0x30..=0x31) |
760 | 0 | } |
761 | | #[inline] |
762 | 0 | fn len(self) -> usize { |
763 | 0 | 1 |
764 | 0 | } |
765 | | #[inline] |
766 | 0 | fn is_space(self) -> bool { |
767 | 0 | *self == b' ' || *self == b'\t' |
768 | 0 | } |
769 | 0 | fn is_newline(self) -> bool { |
770 | 0 | *self == b'\n' |
771 | 0 | } |
772 | | } |
773 | | |
774 | | impl AsChar for char { |
775 | | #[inline] |
776 | 0 | fn as_char(self) -> char { |
777 | 0 | self |
778 | 0 | } Unexecuted instantiation: <char as nom::traits::AsChar>::as_char Unexecuted instantiation: <char as nom::traits::AsChar>::as_char |
779 | | #[inline] |
780 | 0 | fn is_alpha(self) -> bool { |
781 | 0 | self.is_ascii_alphabetic() |
782 | 0 | } |
783 | | #[inline] |
784 | 0 | fn is_alphanum(self) -> bool { |
785 | 0 | self.is_alpha() || self.is_dec_digit() |
786 | 0 | } |
787 | | #[inline] |
788 | 0 | fn is_dec_digit(self) -> bool { |
789 | 0 | self.is_ascii_digit() |
790 | 0 | } Unexecuted instantiation: <char as nom::traits::AsChar>::is_dec_digit Unexecuted instantiation: <char as nom::traits::AsChar>::is_dec_digit |
791 | | #[inline] |
792 | 0 | fn is_hex_digit(self) -> bool { |
793 | 0 | self.is_ascii_hexdigit() |
794 | 0 | } |
795 | | #[inline] |
796 | 0 | fn is_oct_digit(self) -> bool { |
797 | 0 | self.is_digit(8) |
798 | 0 | } |
799 | | #[inline] |
800 | 0 | fn is_bin_digit(self) -> bool { |
801 | 0 | self.is_digit(2) |
802 | 0 | } |
803 | | #[inline] |
804 | 0 | fn len(self) -> usize { |
805 | 0 | self.len_utf8() |
806 | 0 | } Unexecuted instantiation: <char as nom::traits::AsChar>::len Unexecuted instantiation: <char as nom::traits::AsChar>::len |
807 | | #[inline] |
808 | 0 | fn is_space(self) -> bool { |
809 | 0 | self == ' ' || self == '\t' |
810 | 0 | } |
811 | 0 | fn is_newline(self) -> bool { |
812 | 0 | self == '\n' |
813 | 0 | } |
814 | | } |
815 | | |
816 | | impl<'a> AsChar for &'a char { |
817 | | #[inline] |
818 | 0 | fn as_char(self) -> char { |
819 | 0 | *self |
820 | 0 | } Unexecuted instantiation: <&char as nom::traits::AsChar>::as_char Unexecuted instantiation: <&char as nom::traits::AsChar>::as_char |
821 | | #[inline] |
822 | 0 | fn is_alpha(self) -> bool { |
823 | 0 | self.is_ascii_alphabetic() |
824 | 0 | } |
825 | | #[inline] |
826 | 0 | fn is_alphanum(self) -> bool { |
827 | 0 | self.is_alpha() || self.is_dec_digit() |
828 | 0 | } |
829 | | #[inline] |
830 | 0 | fn is_dec_digit(self) -> bool { |
831 | 0 | self.is_ascii_digit() |
832 | 0 | } |
833 | | #[inline] |
834 | 0 | fn is_hex_digit(self) -> bool { |
835 | 0 | self.is_ascii_hexdigit() |
836 | 0 | } |
837 | | #[inline] |
838 | 0 | fn is_oct_digit(self) -> bool { |
839 | 0 | self.is_digit(8) |
840 | 0 | } |
841 | | #[inline] |
842 | 0 | fn is_bin_digit(self) -> bool { |
843 | 0 | self.is_digit(2) |
844 | 0 | } |
845 | | #[inline] |
846 | 0 | fn len(self) -> usize { |
847 | 0 | self.len_utf8() |
848 | 0 | } Unexecuted instantiation: <&char as nom::traits::AsChar>::len Unexecuted instantiation: <&char as nom::traits::AsChar>::len |
849 | | #[inline] |
850 | 0 | fn is_space(self) -> bool { |
851 | 0 | *self == ' ' || *self == '\t' |
852 | 0 | } |
853 | 0 | fn is_newline(self) -> bool { |
854 | 0 | *self == '\n' |
855 | 0 | } |
856 | | } |
857 | | |
858 | | /// Indicates whether a comparison was successful, an error, or |
859 | | /// if more data was needed |
860 | | #[derive(Debug, Eq, PartialEq)] |
861 | | pub enum CompareResult { |
862 | | /// Comparison was successful |
863 | | Ok, |
864 | | /// We need more data to be sure |
865 | | Incomplete, |
866 | | /// Comparison failed |
867 | | Error, |
868 | | } |
869 | | |
870 | | /// Abstracts comparison operations |
871 | | pub trait Compare<T> { |
872 | | /// Compares self to another value for equality |
873 | | fn compare(&self, t: T) -> CompareResult; |
874 | | /// Compares self to another value for equality |
875 | | /// independently of the case. |
876 | | /// |
877 | | /// Warning: for `&str`, the comparison is done |
878 | | /// by lowercasing both strings and comparing |
879 | | /// the result. This is a temporary solution until |
880 | | /// a better one appears |
881 | | fn compare_no_case(&self, t: T) -> CompareResult; |
882 | | } |
883 | | |
884 | 0 | fn lowercase_byte(c: u8) -> u8 { |
885 | 0 | match c { |
886 | 0 | b'A'..=b'Z' => c - b'A' + b'a', |
887 | 0 | _ => c, |
888 | | } |
889 | 0 | } |
890 | | |
891 | | impl<'a, 'b> Compare<&'b [u8]> for &'a [u8] { |
892 | | #[inline(always)] |
893 | 0 | fn compare(&self, t: &'b [u8]) -> CompareResult { |
894 | 0 | let pos = self.iter().zip(t.iter()).position(|(a, b)| a != b); Unexecuted instantiation: <&[u8] as nom::traits::Compare<&[u8]>>::compare::{closure#0}Unexecuted instantiation: <&[u8] as nom::traits::Compare<&[u8]>>::compare::{closure#0} |
895 | | |
896 | 0 | match pos { |
897 | 0 | Some(_) => CompareResult::Error, |
898 | | None => { |
899 | 0 | if self.len() >= t.len() { |
900 | 0 | CompareResult::Ok |
901 | | } else { |
902 | 0 | CompareResult::Incomplete |
903 | | } |
904 | | } |
905 | | } |
906 | 0 | } |
907 | | |
908 | | #[inline(always)] |
909 | 0 | fn compare_no_case(&self, t: &'b [u8]) -> CompareResult { |
910 | 0 | if self |
911 | 0 | .iter() |
912 | 0 | .zip(t) |
913 | 0 | .any(|(a, b)| lowercase_byte(*a) != lowercase_byte(*b)) |
914 | | { |
915 | 0 | CompareResult::Error |
916 | 0 | } else if self.len() < t.len() { |
917 | 0 | CompareResult::Incomplete |
918 | | } else { |
919 | 0 | CompareResult::Ok |
920 | | } |
921 | 0 | } |
922 | | } |
923 | | |
924 | | impl<'a, 'b> Compare<&'b str> for &'a [u8] { |
925 | | #[inline(always)] |
926 | 0 | fn compare(&self, t: &'b str) -> CompareResult { |
927 | 0 | self.compare(AsBytes::as_bytes(t)) |
928 | 0 | } |
929 | | #[inline(always)] |
930 | 0 | fn compare_no_case(&self, t: &'b str) -> CompareResult { |
931 | 0 | self.compare_no_case(AsBytes::as_bytes(t)) |
932 | 0 | } |
933 | | } |
934 | | |
935 | | impl<'a, 'b> Compare<&'b str> for &'a str { |
936 | | #[inline(always)] |
937 | 0 | fn compare(&self, t: &'b str) -> CompareResult { |
938 | 0 | self.as_bytes().compare(t.as_bytes()) |
939 | 0 | } |
940 | | |
941 | | //FIXME: this version is too simple and does not use the current locale |
942 | | #[inline(always)] |
943 | 0 | fn compare_no_case(&self, t: &'b str) -> CompareResult { |
944 | 0 | let pos = self |
945 | 0 | .chars() |
946 | 0 | .zip(t.chars()) |
947 | 0 | .position(|(a, b)| a.to_lowercase().ne(b.to_lowercase())); |
948 | | |
949 | 0 | match pos { |
950 | 0 | Some(_) => CompareResult::Error, |
951 | | None => { |
952 | 0 | if self.len() >= t.len() { |
953 | 0 | CompareResult::Ok |
954 | | } else { |
955 | 0 | CompareResult::Incomplete |
956 | | } |
957 | | } |
958 | | } |
959 | 0 | } |
960 | | } |
961 | | |
962 | | impl<'a, 'b> Compare<&'b [u8]> for &'a str { |
963 | | #[inline(always)] |
964 | 0 | fn compare(&self, t: &'b [u8]) -> CompareResult { |
965 | 0 | AsBytes::as_bytes(self).compare(t) |
966 | 0 | } |
967 | | #[inline(always)] |
968 | 0 | fn compare_no_case(&self, t: &'b [u8]) -> CompareResult { |
969 | 0 | AsBytes::as_bytes(self).compare_no_case(t) |
970 | 0 | } |
971 | | } |
972 | | |
973 | | /// Look for a token in self |
974 | | pub trait FindToken<T> { |
975 | | /// Returns true if self contains the token |
976 | | fn find_token(&self, token: T) -> bool; |
977 | | } |
978 | | |
979 | | impl<'a> FindToken<u8> for &'a [u8] { |
980 | 0 | fn find_token(&self, token: u8) -> bool { |
981 | 0 | memchr::memchr(token, self).is_some() |
982 | 0 | } |
983 | | } |
984 | | |
985 | | impl<'a> FindToken<u8> for &'a str { |
986 | 0 | fn find_token(&self, token: u8) -> bool { |
987 | 0 | self.as_bytes().find_token(token) |
988 | 0 | } |
989 | | } |
990 | | |
991 | | impl<'a, 'b> FindToken<&'a u8> for &'b [u8] { |
992 | 0 | fn find_token(&self, token: &u8) -> bool { |
993 | 0 | self.find_token(*token) |
994 | 0 | } |
995 | | } |
996 | | |
997 | | impl<'a, 'b> FindToken<&'a u8> for &'b str { |
998 | 0 | fn find_token(&self, token: &u8) -> bool { |
999 | 0 | self.as_bytes().find_token(token) |
1000 | 0 | } |
1001 | | } |
1002 | | |
1003 | | impl<'a> FindToken<char> for &'a [u8] { |
1004 | 0 | fn find_token(&self, token: char) -> bool { |
1005 | 0 | self.iter().any(|i| *i == token as u8) |
1006 | 0 | } |
1007 | | } |
1008 | | |
1009 | | impl<'a> FindToken<char> for &'a str { |
1010 | 0 | fn find_token(&self, token: char) -> bool { |
1011 | 0 | self.chars().any(|i| i == token) |
1012 | 0 | } |
1013 | | } |
1014 | | |
1015 | | impl<'a> FindToken<char> for &'a [char] { |
1016 | 0 | fn find_token(&self, token: char) -> bool { |
1017 | 0 | self.iter().any(|i| *i == token) |
1018 | 0 | } |
1019 | | } |
1020 | | |
1021 | | impl<'a, 'b> FindToken<&'a char> for &'b [char] { |
1022 | 0 | fn find_token(&self, token: &char) -> bool { |
1023 | 0 | self.find_token(*token) |
1024 | 0 | } |
1025 | | } |
1026 | | |
1027 | | /// Look for a substring in self |
1028 | | pub trait FindSubstring<T> { |
1029 | | /// Returns the byte position of the substring if it is found |
1030 | | fn find_substring(&self, substr: T) -> Option<usize>; |
1031 | | } |
1032 | | |
1033 | | impl<'a, 'b> FindSubstring<&'b [u8]> for &'a [u8] { |
1034 | 0 | fn find_substring(&self, substr: &'b [u8]) -> Option<usize> { |
1035 | 0 | if substr.len() > self.len() { |
1036 | 0 | return None; |
1037 | 0 | } |
1038 | | |
1039 | 0 | let (&substr_first, substr_rest) = match substr.split_first() { |
1040 | 0 | Some(split) => split, |
1041 | | // an empty substring is found at position 0 |
1042 | | // This matches the behavior of str.find(""). |
1043 | 0 | None => return Some(0), |
1044 | | }; |
1045 | | |
1046 | 0 | if substr_rest.is_empty() { |
1047 | 0 | return memchr::memchr(substr_first, self); |
1048 | 0 | } |
1049 | | |
1050 | 0 | let mut offset = 0; |
1051 | 0 | let haystack = &self[..self.len() - substr_rest.len()]; |
1052 | | |
1053 | 0 | while let Some(position) = memchr::memchr(substr_first, &haystack[offset..]) { |
1054 | 0 | offset += position; |
1055 | 0 | let next_offset = offset + 1; |
1056 | 0 | if &self[next_offset..][..substr_rest.len()] == substr_rest { |
1057 | 0 | return Some(offset); |
1058 | 0 | } |
1059 | | |
1060 | 0 | offset = next_offset; |
1061 | | } |
1062 | | |
1063 | 0 | None |
1064 | 0 | } |
1065 | | } |
1066 | | |
1067 | | impl<'a, 'b> FindSubstring<&'b str> for &'a [u8] { |
1068 | 0 | fn find_substring(&self, substr: &'b str) -> Option<usize> { |
1069 | 0 | self.find_substring(AsBytes::as_bytes(substr)) |
1070 | 0 | } |
1071 | | } |
1072 | | |
1073 | | impl<'a, 'b> FindSubstring<&'b str> for &'a str { |
1074 | | //returns byte index |
1075 | 0 | fn find_substring(&self, substr: &'b str) -> Option<usize> { |
1076 | 0 | self.find(substr) |
1077 | 0 | } |
1078 | | } |
1079 | | |
1080 | | /// Used to integrate `str`'s `parse()` method |
1081 | | pub trait ParseTo<R> { |
1082 | | /// Succeeds if `parse()` succeeded. The byte slice implementation |
1083 | | /// will first convert it to a `&str`, then apply the `parse()` function |
1084 | | fn parse_to(&self) -> Option<R>; |
1085 | | } |
1086 | | |
1087 | | impl<'a, R: FromStr> ParseTo<R> for &'a [u8] { |
1088 | 0 | fn parse_to(&self) -> Option<R> { |
1089 | 0 | from_utf8(self).ok().and_then(|s| s.parse().ok()) |
1090 | 0 | } |
1091 | | } |
1092 | | |
1093 | | impl<'a, R: FromStr> ParseTo<R> for &'a str { |
1094 | 0 | fn parse_to(&self) -> Option<R> { |
1095 | 0 | self.parse().ok() |
1096 | 0 | } |
1097 | | } |
1098 | | |
1099 | | impl<'a, const N: usize> Compare<[u8; N]> for &'a [u8] { |
1100 | | #[inline(always)] |
1101 | 0 | fn compare(&self, t: [u8; N]) -> CompareResult { |
1102 | 0 | self.compare(&t[..]) |
1103 | 0 | } |
1104 | | |
1105 | | #[inline(always)] |
1106 | 0 | fn compare_no_case(&self, t: [u8; N]) -> CompareResult { |
1107 | 0 | self.compare_no_case(&t[..]) |
1108 | 0 | } |
1109 | | } |
1110 | | |
1111 | | impl<'a, 'b, const N: usize> Compare<&'b [u8; N]> for &'a [u8] { |
1112 | | #[inline(always)] |
1113 | 0 | fn compare(&self, t: &'b [u8; N]) -> CompareResult { |
1114 | 0 | self.compare(&t[..]) |
1115 | 0 | } |
1116 | | |
1117 | | #[inline(always)] |
1118 | 0 | fn compare_no_case(&self, t: &'b [u8; N]) -> CompareResult { |
1119 | 0 | self.compare_no_case(&t[..]) |
1120 | 0 | } |
1121 | | } |
1122 | | |
1123 | | impl<const N: usize> FindToken<u8> for [u8; N] { |
1124 | 0 | fn find_token(&self, token: u8) -> bool { |
1125 | 0 | memchr::memchr(token, &self[..]).is_some() |
1126 | 0 | } |
1127 | | } |
1128 | | |
1129 | | impl<'a, const N: usize> FindToken<&'a u8> for [u8; N] { |
1130 | 0 | fn find_token(&self, token: &u8) -> bool { |
1131 | 0 | self.find_token(*token) |
1132 | 0 | } |
1133 | | } |
1134 | | |
1135 | | /// Abstracts something which can extend an `Extend`. |
1136 | | /// Used to build modified input slices in `escaped_transform` |
1137 | | pub trait ExtendInto { |
1138 | | /// The current input type is a sequence of that `Item` type. |
1139 | | /// |
1140 | | /// Example: `u8` for `&[u8]` or `char` for `&str` |
1141 | | type Item; |
1142 | | |
1143 | | /// The type that will be produced |
1144 | | type Extender; |
1145 | | |
1146 | | /// Create a new `Extend` of the correct type |
1147 | | fn new_builder(&self) -> Self::Extender; |
1148 | | /// Accumulate the input into an accumulator |
1149 | | fn extend_into(&self, acc: &mut Self::Extender); |
1150 | | } |
1151 | | |
1152 | | #[cfg(feature = "alloc")] |
1153 | | impl ExtendInto for [u8] { |
1154 | | type Item = u8; |
1155 | | type Extender = Vec<u8>; |
1156 | | |
1157 | | #[inline] |
1158 | 0 | fn new_builder(&self) -> Vec<u8> { |
1159 | 0 | Vec::new() |
1160 | 0 | } |
1161 | | #[inline] |
1162 | 0 | fn extend_into(&self, acc: &mut Vec<u8>) { |
1163 | 0 | acc.extend(self.iter().cloned()); |
1164 | 0 | } |
1165 | | } |
1166 | | |
1167 | | #[cfg(feature = "alloc")] |
1168 | | impl ExtendInto for &[u8] { |
1169 | | type Item = u8; |
1170 | | type Extender = Vec<u8>; |
1171 | | |
1172 | | #[inline] |
1173 | 0 | fn new_builder(&self) -> Vec<u8> { |
1174 | 0 | Vec::new() |
1175 | 0 | } |
1176 | | #[inline] |
1177 | 0 | fn extend_into(&self, acc: &mut Vec<u8>) { |
1178 | 0 | acc.extend_from_slice(self); |
1179 | 0 | } |
1180 | | } |
1181 | | |
1182 | | #[cfg(feature = "alloc")] |
1183 | | impl ExtendInto for str { |
1184 | | type Item = char; |
1185 | | type Extender = String; |
1186 | | |
1187 | | #[inline] |
1188 | 0 | fn new_builder(&self) -> String { |
1189 | 0 | String::new() |
1190 | 0 | } |
1191 | | #[inline] |
1192 | 0 | fn extend_into(&self, acc: &mut String) { |
1193 | 0 | acc.push_str(self); |
1194 | 0 | } |
1195 | | } |
1196 | | |
1197 | | #[cfg(feature = "alloc")] |
1198 | | impl ExtendInto for &str { |
1199 | | type Item = char; |
1200 | | type Extender = String; |
1201 | | |
1202 | | #[inline] |
1203 | 0 | fn new_builder(&self) -> String { |
1204 | 0 | String::new() |
1205 | 0 | } |
1206 | | #[inline] |
1207 | 0 | fn extend_into(&self, acc: &mut String) { |
1208 | 0 | acc.push_str(self); |
1209 | 0 | } |
1210 | | } |
1211 | | |
1212 | | #[cfg(feature = "alloc")] |
1213 | | impl ExtendInto for char { |
1214 | | type Item = char; |
1215 | | type Extender = String; |
1216 | | |
1217 | | #[inline] |
1218 | 0 | fn new_builder(&self) -> String { |
1219 | 0 | String::new() |
1220 | 0 | } |
1221 | | #[inline] |
1222 | 0 | fn extend_into(&self, acc: &mut String) { |
1223 | 0 | acc.push(*self); |
1224 | 0 | } |
1225 | | } |
1226 | | |
1227 | | /// Helper trait to convert numbers to usize. |
1228 | | /// |
1229 | | /// By default, usize implements `From<u8>` and `From<u16>` but not |
1230 | | /// `From<u32>` and `From<u64>` because that would be invalid on some |
1231 | | /// platforms. This trait implements the conversion for platforms |
1232 | | /// with 32 and 64 bits pointer platforms |
1233 | | pub trait ToUsize { |
1234 | | /// converts self to usize |
1235 | | fn to_usize(&self) -> usize; |
1236 | | } |
1237 | | |
1238 | | impl ToUsize for u8 { |
1239 | | #[inline] |
1240 | 0 | fn to_usize(&self) -> usize { |
1241 | 0 | *self as usize |
1242 | 0 | } |
1243 | | } |
1244 | | |
1245 | | impl ToUsize for u16 { |
1246 | | #[inline] |
1247 | 0 | fn to_usize(&self) -> usize { |
1248 | 0 | *self as usize |
1249 | 0 | } |
1250 | | } |
1251 | | |
1252 | | impl ToUsize for usize { |
1253 | | #[inline] |
1254 | 0 | fn to_usize(&self) -> usize { |
1255 | 0 | *self |
1256 | 0 | } |
1257 | | } |
1258 | | |
1259 | | #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] |
1260 | | impl ToUsize for u32 { |
1261 | | #[inline] |
1262 | 0 | fn to_usize(&self) -> usize { |
1263 | 0 | *self as usize |
1264 | 0 | } |
1265 | | } |
1266 | | |
1267 | | #[cfg(target_pointer_width = "64")] |
1268 | | impl ToUsize for u64 { |
1269 | | #[inline] |
1270 | 0 | fn to_usize(&self) -> usize { |
1271 | 0 | *self as usize |
1272 | 0 | } |
1273 | | } |
1274 | | |
1275 | | /// Equivalent From implementation to avoid orphan rules in bits parsers |
1276 | | pub trait ErrorConvert<E> { |
1277 | | /// Transform to another error type |
1278 | | fn convert(self) -> E; |
1279 | | } |
1280 | | |
1281 | | impl<I> ErrorConvert<(I, ErrorKind)> for ((I, usize), ErrorKind) { |
1282 | 0 | fn convert(self) -> (I, ErrorKind) { |
1283 | 0 | ((self.0).0, self.1) |
1284 | 0 | } |
1285 | | } |
1286 | | |
1287 | | impl<I> ErrorConvert<((I, usize), ErrorKind)> for (I, ErrorKind) { |
1288 | 0 | fn convert(self) -> ((I, usize), ErrorKind) { |
1289 | 0 | ((self.0, 0), self.1) |
1290 | 0 | } |
1291 | | } |
1292 | | |
1293 | | use crate::error; |
1294 | | impl<I> ErrorConvert<error::Error<I>> for error::Error<(I, usize)> { |
1295 | 0 | fn convert(self) -> error::Error<I> { |
1296 | 0 | error::Error { |
1297 | 0 | input: self.input.0, |
1298 | 0 | code: self.code, |
1299 | 0 | } |
1300 | 0 | } |
1301 | | } |
1302 | | |
1303 | | impl<I> ErrorConvert<error::Error<(I, usize)>> for error::Error<I> { |
1304 | 0 | fn convert(self) -> error::Error<(I, usize)> { |
1305 | 0 | error::Error { |
1306 | 0 | input: (self.input, 0), |
1307 | 0 | code: self.code, |
1308 | 0 | } |
1309 | 0 | } |
1310 | | } |
1311 | | |
1312 | | impl ErrorConvert<()> for () { |
1313 | 0 | fn convert(self) {} |
1314 | | } |
1315 | | |
1316 | | #[cfg(feature = "std")] |
1317 | | #[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))] |
1318 | | /// Helper trait to show a byte slice as a hex dump |
1319 | | pub trait HexDisplay { |
1320 | | /// Converts the value of `self` to a hex dump, returning the owned |
1321 | | /// `String`. |
1322 | | fn to_hex(&self, chunk_size: usize) -> String; |
1323 | | |
1324 | | /// Converts the value of `self` to a hex dump beginning at `from` address, returning the owned |
1325 | | /// `String`. |
1326 | | fn to_hex_from(&self, chunk_size: usize, from: usize) -> String; |
1327 | | } |
1328 | | |
1329 | | #[cfg(feature = "std")] |
1330 | | static CHARS: &[u8] = b"0123456789abcdef"; |
1331 | | |
1332 | | #[cfg(feature = "std")] |
1333 | | impl HexDisplay for [u8] { |
1334 | | #[allow(unused_variables)] |
1335 | 0 | fn to_hex(&self, chunk_size: usize) -> String { |
1336 | 0 | self.to_hex_from(chunk_size, 0) |
1337 | 0 | } |
1338 | | |
1339 | | #[allow(unused_variables)] |
1340 | 0 | fn to_hex_from(&self, chunk_size: usize, from: usize) -> String { |
1341 | 0 | let mut v = Vec::with_capacity(self.len() * 3); |
1342 | 0 | let mut i = from; |
1343 | 0 | for chunk in self.chunks(chunk_size) { |
1344 | 0 | let s = format!("{:08x}", i); |
1345 | 0 | for &ch in s.as_bytes().iter() { |
1346 | 0 | v.push(ch); |
1347 | 0 | } |
1348 | 0 | v.push(b'\t'); |
1349 | | |
1350 | 0 | i += chunk_size; |
1351 | | |
1352 | 0 | for &byte in chunk { |
1353 | 0 | v.push(CHARS[(byte >> 4) as usize]); |
1354 | 0 | v.push(CHARS[(byte & 0xf) as usize]); |
1355 | 0 | v.push(b' '); |
1356 | 0 | } |
1357 | 0 | if chunk_size > chunk.len() { |
1358 | 0 | for j in 0..(chunk_size - chunk.len()) { |
1359 | 0 | v.push(b' '); |
1360 | 0 | v.push(b' '); |
1361 | 0 | v.push(b' '); |
1362 | 0 | } |
1363 | 0 | } |
1364 | 0 | v.push(b'\t'); |
1365 | | |
1366 | 0 | for &byte in chunk { |
1367 | 0 | if matches!(byte, 32..=126 | 128..=255) { |
1368 | 0 | v.push(byte); |
1369 | 0 | } else { |
1370 | 0 | v.push(b'.'); |
1371 | 0 | } |
1372 | | } |
1373 | 0 | v.push(b'\n'); |
1374 | | } |
1375 | | |
1376 | 0 | String::from_utf8_lossy(&v[..]).into_owned() |
1377 | 0 | } |
1378 | | } |
1379 | | |
1380 | | #[cfg(feature = "std")] |
1381 | | impl HexDisplay for str { |
1382 | | #[allow(unused_variables)] |
1383 | 0 | fn to_hex(&self, chunk_size: usize) -> String { |
1384 | 0 | self.to_hex_from(chunk_size, 0) |
1385 | 0 | } |
1386 | | |
1387 | | #[allow(unused_variables)] |
1388 | 0 | fn to_hex_from(&self, chunk_size: usize, from: usize) -> String { |
1389 | 0 | self.as_bytes().to_hex_from(chunk_size, from) |
1390 | 0 | } |
1391 | | } |
1392 | | |
1393 | | /// A saturating iterator for usize. |
1394 | | pub struct SaturatingIterator { |
1395 | | count: usize, |
1396 | | } |
1397 | | |
1398 | | impl Iterator for SaturatingIterator { |
1399 | | type Item = usize; |
1400 | | |
1401 | 0 | fn next(&mut self) -> Option<Self::Item> { |
1402 | 0 | let old_count = self.count; |
1403 | 0 | self.count = self.count.saturating_add(1); |
1404 | 0 | Some(old_count) |
1405 | 0 | } |
1406 | | } |
1407 | | |
1408 | | /// Abstractions for range-like types. |
1409 | | pub trait NomRange<Idx> { |
1410 | | /// The saturating iterator type. |
1411 | | type Saturating: Iterator<Item = Idx>; |
1412 | | /// The bounded iterator type. |
1413 | | type Bounded: Iterator<Item = Idx>; |
1414 | | |
1415 | | /// `true` if `item` is contained in the range. |
1416 | | fn contains(&self, item: &Idx) -> bool; |
1417 | | |
1418 | | /// Returns the bounds of this range. |
1419 | | fn bounds(&self) -> (Bound<Idx>, Bound<Idx>); |
1420 | | |
1421 | | /// `true` if the range is inverted. |
1422 | | fn is_inverted(&self) -> bool; |
1423 | | |
1424 | | /// Creates a saturating iterator. |
1425 | | /// A saturating iterator counts the number of iterations starting from 0 up to the upper bound of this range. |
1426 | | /// If the upper bound is infinite the iterator saturates at the largest representable value of its type and |
1427 | | /// returns it for all further elements. |
1428 | | fn saturating_iter(&self) -> Self::Saturating; |
1429 | | |
1430 | | /// Creates a bounded iterator. |
1431 | | /// A bounded iterator counts the number of iterations starting from 0 up to the upper bound of this range. |
1432 | | /// If the upper bounds is infinite the iterator counts up until the amount of iterations has reached the |
1433 | | /// largest representable value of its type and then returns `None` for all further elements. |
1434 | | fn bounded_iter(&self) -> Self::Bounded; |
1435 | | } |
1436 | | |
1437 | | impl NomRange<usize> for Range<usize> { |
1438 | | type Saturating = Range<usize>; |
1439 | | type Bounded = Range<usize>; |
1440 | | |
1441 | 0 | fn bounds(&self) -> (Bound<usize>, Bound<usize>) { |
1442 | 0 | (Bound::Included(self.start), Bound::Excluded(self.end)) |
1443 | 0 | } |
1444 | | |
1445 | 0 | fn contains(&self, item: &usize) -> bool { |
1446 | 0 | RangeBounds::contains(self, item) |
1447 | 0 | } |
1448 | | |
1449 | 0 | fn is_inverted(&self) -> bool { |
1450 | 0 | self.start >= self.end |
1451 | 0 | } |
1452 | | |
1453 | 0 | fn saturating_iter(&self) -> Self::Saturating { |
1454 | 0 | if self.end == 0 { |
1455 | 0 | Range::default() |
1456 | | } else { |
1457 | 0 | 0..self.end - 1 |
1458 | | } |
1459 | 0 | } |
1460 | | |
1461 | 0 | fn bounded_iter(&self) -> Self::Bounded { |
1462 | 0 | if self.end == 0 { |
1463 | 0 | Range::default() |
1464 | | } else { |
1465 | 0 | 0..self.end - 1 |
1466 | | } |
1467 | 0 | } |
1468 | | } |
1469 | | |
1470 | | impl NomRange<usize> for RangeInclusive<usize> { |
1471 | | type Saturating = Range<usize>; |
1472 | | type Bounded = Range<usize>; |
1473 | | |
1474 | 0 | fn bounds(&self) -> (Bound<usize>, Bound<usize>) { |
1475 | 0 | (Bound::Included(*self.start()), Bound::Included(*self.end())) |
1476 | 0 | } |
1477 | | |
1478 | 0 | fn contains(&self, item: &usize) -> bool { |
1479 | 0 | RangeBounds::contains(self, item) |
1480 | 0 | } |
1481 | | |
1482 | 0 | fn is_inverted(&self) -> bool { |
1483 | 0 | !RangeInclusive::contains(self, self.start()) |
1484 | 0 | } |
1485 | | |
1486 | 0 | fn saturating_iter(&self) -> Self::Saturating { |
1487 | 0 | 0..*self.end() |
1488 | 0 | } |
1489 | | |
1490 | 0 | fn bounded_iter(&self) -> Self::Bounded { |
1491 | 0 | 0..*self.end() |
1492 | 0 | } |
1493 | | } |
1494 | | |
1495 | | impl NomRange<usize> for RangeFrom<usize> { |
1496 | | type Saturating = SaturatingIterator; |
1497 | | type Bounded = Range<usize>; |
1498 | | |
1499 | 0 | fn bounds(&self) -> (Bound<usize>, Bound<usize>) { |
1500 | 0 | (Bound::Included(self.start), Bound::Unbounded) |
1501 | 0 | } |
1502 | | |
1503 | 0 | fn contains(&self, item: &usize) -> bool { |
1504 | 0 | RangeBounds::contains(self, item) |
1505 | 0 | } |
1506 | | |
1507 | 0 | fn is_inverted(&self) -> bool { |
1508 | 0 | false |
1509 | 0 | } |
1510 | | |
1511 | 0 | fn saturating_iter(&self) -> Self::Saturating { |
1512 | 0 | SaturatingIterator { count: 0 } |
1513 | 0 | } |
1514 | | |
1515 | 0 | fn bounded_iter(&self) -> Self::Bounded { |
1516 | 0 | 0..usize::MAX |
1517 | 0 | } |
1518 | | } |
1519 | | |
1520 | | impl NomRange<usize> for RangeTo<usize> { |
1521 | | type Saturating = Range<usize>; |
1522 | | type Bounded = Range<usize>; |
1523 | | |
1524 | 0 | fn bounds(&self) -> (Bound<usize>, Bound<usize>) { |
1525 | 0 | (Bound::Unbounded, Bound::Excluded(self.end)) |
1526 | 0 | } |
1527 | | |
1528 | 0 | fn contains(&self, item: &usize) -> bool { |
1529 | 0 | RangeBounds::contains(self, item) |
1530 | 0 | } |
1531 | | |
1532 | 0 | fn is_inverted(&self) -> bool { |
1533 | 0 | false |
1534 | 0 | } |
1535 | | |
1536 | 0 | fn saturating_iter(&self) -> Self::Saturating { |
1537 | 0 | if self.end == 0 { |
1538 | 0 | Range::default() |
1539 | | } else { |
1540 | 0 | 0..self.end - 1 |
1541 | | } |
1542 | 0 | } |
1543 | | |
1544 | 0 | fn bounded_iter(&self) -> Self::Bounded { |
1545 | 0 | if self.end == 0 { |
1546 | 0 | Range::default() |
1547 | | } else { |
1548 | 0 | 0..self.end - 1 |
1549 | | } |
1550 | 0 | } |
1551 | | } |
1552 | | |
1553 | | impl NomRange<usize> for RangeToInclusive<usize> { |
1554 | | type Saturating = Range<usize>; |
1555 | | type Bounded = Range<usize>; |
1556 | | |
1557 | 0 | fn bounds(&self) -> (Bound<usize>, Bound<usize>) { |
1558 | 0 | (Bound::Unbounded, Bound::Included(self.end)) |
1559 | 0 | } |
1560 | | |
1561 | 0 | fn contains(&self, item: &usize) -> bool { |
1562 | 0 | RangeBounds::contains(self, item) |
1563 | 0 | } |
1564 | | |
1565 | 0 | fn is_inverted(&self) -> bool { |
1566 | 0 | false |
1567 | 0 | } |
1568 | | |
1569 | 0 | fn saturating_iter(&self) -> Self::Saturating { |
1570 | 0 | 0..self.end |
1571 | 0 | } |
1572 | | |
1573 | 0 | fn bounded_iter(&self) -> Self::Bounded { |
1574 | 0 | 0..self.end |
1575 | 0 | } |
1576 | | } |
1577 | | |
1578 | | impl NomRange<usize> for RangeFull { |
1579 | | type Saturating = SaturatingIterator; |
1580 | | type Bounded = Range<usize>; |
1581 | | |
1582 | 0 | fn bounds(&self) -> (Bound<usize>, Bound<usize>) { |
1583 | 0 | (Bound::Unbounded, Bound::Unbounded) |
1584 | 0 | } |
1585 | | |
1586 | 0 | fn contains(&self, item: &usize) -> bool { |
1587 | 0 | RangeBounds::contains(self, item) |
1588 | 0 | } |
1589 | | |
1590 | 0 | fn is_inverted(&self) -> bool { |
1591 | 0 | false |
1592 | 0 | } |
1593 | | |
1594 | 0 | fn saturating_iter(&self) -> Self::Saturating { |
1595 | 0 | SaturatingIterator { count: 0 } |
1596 | 0 | } |
1597 | | |
1598 | 0 | fn bounded_iter(&self) -> Self::Bounded { |
1599 | 0 | 0..usize::MAX |
1600 | 0 | } |
1601 | | } |
1602 | | |
1603 | | impl NomRange<usize> for usize { |
1604 | | type Saturating = Range<usize>; |
1605 | | type Bounded = Range<usize>; |
1606 | | |
1607 | 0 | fn bounds(&self) -> (Bound<usize>, Bound<usize>) { |
1608 | 0 | (Bound::Included(*self), Bound::Included(*self)) |
1609 | 0 | } |
1610 | | |
1611 | 0 | fn contains(&self, item: &usize) -> bool { |
1612 | 0 | self == item |
1613 | 0 | } |
1614 | | |
1615 | 0 | fn is_inverted(&self) -> bool { |
1616 | 0 | false |
1617 | 0 | } |
1618 | | |
1619 | 0 | fn saturating_iter(&self) -> Self::Saturating { |
1620 | 0 | 0..*self |
1621 | 0 | } |
1622 | | |
1623 | 0 | fn bounded_iter(&self) -> Self::Bounded { |
1624 | 0 | 0..*self |
1625 | 0 | } |
1626 | | } |
1627 | | |
1628 | | #[cfg(test)] |
1629 | | mod tests { |
1630 | | use super::*; |
1631 | | |
1632 | | #[test] |
1633 | | fn test_offset_u8() { |
1634 | | let s = b"abcd123"; |
1635 | | let a = &s[..]; |
1636 | | let b = &a[2..]; |
1637 | | let c = &a[..4]; |
1638 | | let d = &a[3..5]; |
1639 | | assert_eq!(a.offset(b), 2); |
1640 | | assert_eq!(a.offset(c), 0); |
1641 | | assert_eq!(a.offset(d), 3); |
1642 | | } |
1643 | | |
1644 | | #[test] |
1645 | | fn test_offset_str() { |
1646 | | let a = "abcřèÂßÇd123"; |
1647 | | let b = &a[7..]; |
1648 | | let c = &a[..5]; |
1649 | | let d = &a[5..9]; |
1650 | | assert_eq!(a.offset(b), 7); |
1651 | | assert_eq!(a.offset(c), 0); |
1652 | | assert_eq!(a.offset(d), 5); |
1653 | | } |
1654 | | |
1655 | | #[test] |
1656 | | fn test_slice_index() { |
1657 | | let a = "abcřèÂßÇd123"; |
1658 | | assert_eq!(a.slice_index(0), Ok(0)); |
1659 | | assert_eq!(a.slice_index(2), Ok(2)); |
1660 | | } |
1661 | | |
1662 | | #[test] |
1663 | | fn test_slice_index_utf8() { |
1664 | | let a = "a¡€💢€¡a"; |
1665 | | |
1666 | | for (c, len) in a.chars().zip([1, 2, 3, 4, 3, 2, 1]) { |
1667 | | assert_eq!(c.len(), len); |
1668 | | } |
1669 | | |
1670 | | assert_eq!(a.slice_index(0), Ok(0)); |
1671 | | assert_eq!(a.slice_index(1), Ok(1)); |
1672 | | assert_eq!(a.slice_index(2), Ok(3)); |
1673 | | assert_eq!(a.slice_index(3), Ok(6)); |
1674 | | assert_eq!(a.slice_index(4), Ok(10)); |
1675 | | assert_eq!(a.slice_index(5), Ok(13)); |
1676 | | assert_eq!(a.slice_index(6), Ok(15)); |
1677 | | assert_eq!(a.slice_index(7), Ok(16)); |
1678 | | |
1679 | | assert!(a.slice_index(8).is_err()); |
1680 | | } |
1681 | | } |