• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // pest. The Elegant Parser
2 // Copyright (c) 2018 Dragoș Tiselice
3 //
4 // Licensed under the Apache License, Version 2.0
5 // <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
6 // license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. All files in the project carrying such notice may not be copied,
8 // modified, or distributed except according to those terms.
9 
10 use alloc::borrow::ToOwned;
11 use alloc::boxed::Box;
12 use alloc::rc::Rc;
13 use alloc::vec;
14 use alloc::vec::Vec;
15 use core::num::NonZeroUsize;
16 use core::ops::Range;
17 use core::sync::atomic::{AtomicUsize, Ordering};
18 
19 use crate::error::{Error, ErrorVariant};
20 use crate::iterators::{pairs, QueueableToken};
21 use crate::position::{self, Position};
22 use crate::span::Span;
23 use crate::stack::Stack;
24 use crate::RuleType;
25 
26 /// The current lookahead status of a [`ParserState`].
27 ///
28 /// [`ParserState`]: struct.ParserState.html
29 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
30 pub enum Lookahead {
31     /// The positive predicate, written as an ampersand &,
32     /// attempts to match its inner expression.
33     /// If the inner expression succeeds, parsing continues,
34     /// but at the same position as the predicate —
35     /// &foo ~ bar is thus a kind of "AND" statement:
36     /// "the input string must match foo AND bar".
37     /// If the inner expression fails,
38     /// the whole expression fails too.
39     Positive,
40     /// The negative predicate, written as an exclamation mark !,
41     /// attempts to match its inner expression.
42     /// If the inner expression fails, the predicate succeeds
43     /// and parsing continues at the same position as the predicate.
44     /// If the inner expression succeeds, the predicate fails —
45     /// !foo ~ bar is thus a kind of "NOT" statement:
46     /// "the input string must match bar but NOT foo".
47     Negative,
48     /// No lookahead (i.e. it will consume input).
49     None,
50 }
51 
52 /// The current atomicity of a [`ParserState`].
53 ///
54 /// [`ParserState`]: struct.ParserState.html
55 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
56 pub enum Atomicity {
57     /// prevents implicit whitespace: inside an atomic rule,
58     /// the tilde ~ means "immediately followed by",
59     /// and repetition operators (asterisk * and plus sign +)
60     /// have no implicit separation. In addition, all other rules
61     /// called from an atomic rule are also treated as atomic.
62     /// (interior matching rules are silent)
63     Atomic,
64     /// The same as atomic, but inner tokens are produced as normal.
65     CompoundAtomic,
66     /// implicit whitespace is enabled
67     NonAtomic,
68 }
69 
70 /// Type alias to simplify specifying the return value of chained closures.
71 pub type ParseResult<S> = Result<S, S>;
72 
73 /// Match direction for the stack. Used in `PEEK[a..b]`/`stack_match_peek_slice`.
74 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
75 pub enum MatchDir {
76     /// from the bottom to the top of the stack
77     BottomToTop,
78     /// from the top to the bottom of the stack
79     TopToBottom,
80 }
81 
82 static CALL_LIMIT: AtomicUsize = AtomicUsize::new(0);
83 
84 /// Sets the maximum call limit for the parser state
85 /// to prevent stack overflows or excessive execution times
86 /// in some grammars.
87 /// If set, the calls are tracked as a running total
88 /// over all non-terminal rules that can nest closures
89 /// (which are passed to transform the parser state).
90 ///
91 /// # Arguments
92 ///
93 /// * `limit` - The maximum number of calls. If None,
94 ///             the number of calls is unlimited.
set_call_limit(limit: Option<NonZeroUsize>)95 pub fn set_call_limit(limit: Option<NonZeroUsize>) {
96     CALL_LIMIT.store(limit.map(|f| f.get()).unwrap_or(0), Ordering::Relaxed);
97 }
98 
99 #[derive(Debug)]
100 struct CallLimitTracker {
101     current_call_limit: Option<(usize, usize)>,
102 }
103 
104 impl Default for CallLimitTracker {
default() -> Self105     fn default() -> Self {
106         let limit = CALL_LIMIT.load(Ordering::Relaxed);
107         let current_call_limit = if limit > 0 { Some((0, limit)) } else { None };
108         Self { current_call_limit }
109     }
110 }
111 
112 impl CallLimitTracker {
limit_reached(&self) -> bool113     fn limit_reached(&self) -> bool {
114         self.current_call_limit
115             .map_or(false, |(current, limit)| current >= limit)
116     }
117 
increment_depth(&mut self)118     fn increment_depth(&mut self) {
119         if let Some((current, _)) = &mut self.current_call_limit {
120             *current += 1;
121         }
122     }
123 }
124 
125 /// The complete state of a [`Parser`].
126 ///
127 /// [`Parser`]: trait.Parser.html
128 #[derive(Debug)]
129 pub struct ParserState<'i, R: RuleType> {
130     position: Position<'i>,
131     queue: Vec<QueueableToken<R>>,
132     lookahead: Lookahead,
133     pos_attempts: Vec<R>,
134     neg_attempts: Vec<R>,
135     attempt_pos: usize,
136     atomicity: Atomicity,
137     stack: Stack<Span<'i>>,
138     call_tracker: CallLimitTracker,
139 }
140 
141 /// Creates a `ParserState` from a `&str`, supplying it to a closure `f`.
142 ///
143 /// # Examples
144 ///
145 /// ```
146 /// # use pest;
147 /// let input = "";
148 /// pest::state::<(), _>(input, |s| Ok(s)).unwrap();
149 /// ```
150 #[allow(clippy::perf)]
state<'i, R: RuleType, F>(input: &'i str, f: F) -> Result<pairs::Pairs<'i, R>, Error<R>> where F: FnOnce(Box<ParserState<'i, R>>) -> ParseResult<Box<ParserState<'i, R>>>,151 pub fn state<'i, R: RuleType, F>(input: &'i str, f: F) -> Result<pairs::Pairs<'i, R>, Error<R>>
152 where
153     F: FnOnce(Box<ParserState<'i, R>>) -> ParseResult<Box<ParserState<'i, R>>>,
154 {
155     let state = ParserState::new(input);
156 
157     match f(state) {
158         Ok(state) => {
159             let len = state.queue.len();
160             Ok(pairs::new(Rc::new(state.queue), input, None, 0, len))
161         }
162         Err(mut state) => {
163             let variant = if state.reached_call_limit() {
164                 ErrorVariant::CustomError {
165                     message: "call limit reached".to_owned(),
166                 }
167             } else {
168                 state.pos_attempts.sort();
169                 state.pos_attempts.dedup();
170                 state.neg_attempts.sort();
171                 state.neg_attempts.dedup();
172                 ErrorVariant::ParsingError {
173                     positives: state.pos_attempts.clone(),
174                     negatives: state.neg_attempts.clone(),
175                 }
176             };
177 
178             Err(Error::new_from_pos(
179                 variant,
180                 // TODO(performance): Guarantee state.attempt_pos is a valid position
181                 position::Position::new(input, state.attempt_pos).unwrap(),
182             ))
183         }
184     }
185 }
186 
187 impl<'i, R: RuleType> ParserState<'i, R> {
188     /// Allocates a fresh `ParserState` object to the heap and returns the owned `Box`. This `Box`
189     /// will be passed from closure to closure based on the needs of the specified `Parser`.
190     ///
191     /// # Examples
192     ///
193     /// ```
194     /// # use pest;
195     /// let input = "";
196     /// let state: Box<pest::ParserState<&str>> = pest::ParserState::new(input);
197     /// ```
new(input: &'i str) -> Box<Self>198     pub fn new(input: &'i str) -> Box<Self> {
199         Box::new(ParserState {
200             position: Position::from_start(input),
201             queue: vec![],
202             lookahead: Lookahead::None,
203             pos_attempts: vec![],
204             neg_attempts: vec![],
205             attempt_pos: 0,
206             atomicity: Atomicity::NonAtomic,
207             stack: Stack::new(),
208             call_tracker: Default::default(),
209         })
210     }
211 
212     /// Returns a reference to the current `Position` of the `ParserState`.
213     ///
214     /// # Examples
215     ///
216     /// ```
217     /// # use pest;
218     /// # #[allow(non_camel_case_types)]
219     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
220     /// enum Rule {
221     ///     ab
222     /// }
223     ///
224     /// let input = "ab";
225     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
226     /// let position = state.position();
227     /// assert_eq!(position.pos(), 0);
228     /// ```
position(&self) -> &Position<'i>229     pub fn position(&self) -> &Position<'i> {
230         &self.position
231     }
232 
233     /// Returns the current atomicity of the `ParserState`.
234     ///
235     /// # Examples
236     ///
237     /// ```
238     /// # use pest;
239     /// # use pest::Atomicity;
240     /// # #[allow(non_camel_case_types)]
241     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
242     /// enum Rule {
243     ///     ab
244     /// }
245     ///
246     /// let input = "ab";
247     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
248     /// let atomicity = state.atomicity();
249     /// assert_eq!(atomicity, Atomicity::NonAtomic);
250     /// ```
atomicity(&self) -> Atomicity251     pub fn atomicity(&self) -> Atomicity {
252         self.atomicity
253     }
254 
255     #[inline]
inc_call_check_limit(mut self: Box<Self>) -> ParseResult<Box<Self>>256     fn inc_call_check_limit(mut self: Box<Self>) -> ParseResult<Box<Self>> {
257         if self.call_tracker.limit_reached() {
258             return Err(self);
259         }
260         self.call_tracker.increment_depth();
261         Ok(self)
262     }
263 
264     #[inline]
reached_call_limit(&self) -> bool265     fn reached_call_limit(&self) -> bool {
266         self.call_tracker.limit_reached()
267     }
268 
269     /// Wrapper needed to generate tokens. This will associate the `R` type rule to the closure
270     /// meant to match the rule.
271     ///
272     /// # Examples
273     ///
274     /// ```
275     /// # use pest;
276     /// # #[allow(non_camel_case_types)]
277     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
278     /// enum Rule {
279     ///     a
280     /// }
281     ///
282     /// let input = "a";
283     /// let pairs: Vec<_> = pest::state(input, |state| {
284     ///     state.rule(Rule::a, |s| Ok(s))
285     /// }).unwrap().collect();
286     ///
287     /// assert_eq!(pairs.len(), 1);
288     /// ```
289     #[inline]
rule<F>(mut self: Box<Self>, rule: R, f: F) -> ParseResult<Box<Self>> where F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,290     pub fn rule<F>(mut self: Box<Self>, rule: R, f: F) -> ParseResult<Box<Self>>
291     where
292         F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
293     {
294         self = self.inc_call_check_limit()?;
295         let actual_pos = self.position.pos();
296         let index = self.queue.len();
297 
298         let (pos_attempts_index, neg_attempts_index) = if actual_pos == self.attempt_pos {
299             (self.pos_attempts.len(), self.neg_attempts.len())
300         } else {
301             // Attempts have not been cleared yet since the attempt_pos is older.
302             (0, 0)
303         };
304 
305         if self.lookahead == Lookahead::None && self.atomicity != Atomicity::Atomic {
306             // Pair's position will only be known after running the closure.
307             self.queue.push(QueueableToken::Start {
308                 end_token_index: 0,
309                 input_pos: actual_pos,
310             });
311         }
312 
313         let attempts = self.attempts_at(actual_pos);
314 
315         let result = f(self);
316 
317         match result {
318             Ok(mut new_state) => {
319                 if new_state.lookahead == Lookahead::Negative {
320                     new_state.track(
321                         rule,
322                         actual_pos,
323                         pos_attempts_index,
324                         neg_attempts_index,
325                         attempts,
326                     );
327                 }
328 
329                 if new_state.lookahead == Lookahead::None
330                     && new_state.atomicity != Atomicity::Atomic
331                 {
332                     // Storing the pair's index in the first token that was added before the closure was
333                     // run.
334                     let new_index = new_state.queue.len();
335                     match new_state.queue[index] {
336                         QueueableToken::Start {
337                             ref mut end_token_index,
338                             ..
339                         } => *end_token_index = new_index,
340                         _ => unreachable!(),
341                     };
342 
343                     let new_pos = new_state.position.pos();
344 
345                     new_state.queue.push(QueueableToken::End {
346                         start_token_index: index,
347                         rule,
348                         input_pos: new_pos,
349                     });
350                 }
351 
352                 Ok(new_state)
353             }
354             Err(mut new_state) => {
355                 if new_state.lookahead != Lookahead::Negative {
356                     new_state.track(
357                         rule,
358                         actual_pos,
359                         pos_attempts_index,
360                         neg_attempts_index,
361                         attempts,
362                     );
363                 }
364 
365                 if new_state.lookahead == Lookahead::None
366                     && new_state.atomicity != Atomicity::Atomic
367                 {
368                     new_state.queue.truncate(index);
369                 }
370 
371                 Err(new_state)
372             }
373         }
374     }
375 
attempts_at(&self, pos: usize) -> usize376     fn attempts_at(&self, pos: usize) -> usize {
377         if self.attempt_pos == pos {
378             self.pos_attempts.len() + self.neg_attempts.len()
379         } else {
380             0
381         }
382     }
383 
track( &mut self, rule: R, pos: usize, pos_attempts_index: usize, neg_attempts_index: usize, prev_attempts: usize, )384     fn track(
385         &mut self,
386         rule: R,
387         pos: usize,
388         pos_attempts_index: usize,
389         neg_attempts_index: usize,
390         prev_attempts: usize,
391     ) {
392         if self.atomicity == Atomicity::Atomic {
393             return;
394         }
395 
396         // If nested rules made no progress, there is no use to report them; it's only useful to
397         // track the current rule, the exception being when only one attempt has been made during
398         // the children rules.
399         let curr_attempts = self.attempts_at(pos);
400         if curr_attempts > prev_attempts && curr_attempts - prev_attempts == 1 {
401             return;
402         }
403 
404         if pos == self.attempt_pos {
405             self.pos_attempts.truncate(pos_attempts_index);
406             self.neg_attempts.truncate(neg_attempts_index);
407         }
408 
409         if pos > self.attempt_pos {
410             self.pos_attempts.clear();
411             self.neg_attempts.clear();
412             self.attempt_pos = pos;
413         }
414 
415         let attempts = if self.lookahead != Lookahead::Negative {
416             &mut self.pos_attempts
417         } else {
418             &mut self.neg_attempts
419         };
420 
421         if pos == self.attempt_pos {
422             attempts.push(rule);
423         }
424     }
425 
426     /// Starts a sequence of transformations provided by `f` from the `Box<ParserState>`. Returns
427     /// the same `Result` returned by `f` in the case of an `Ok`, or `Err` with the current
428     /// `Box<ParserState>` otherwise.
429     ///
430     /// This method is useful to parse sequences that only match together which usually come in the
431     /// form of chained `Result`s with
432     /// [`Result::and_then`](https://doc.rust-lang.org/std/result/enum.Result.html#method.and_then).
433     ///
434     ///
435     /// # Examples
436     ///
437     /// ```
438     /// # use pest;
439     /// # #[allow(non_camel_case_types)]
440     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
441     /// enum Rule {
442     ///     a
443     /// }
444     ///
445     /// let input = "a";
446     /// let pairs: Vec<_> = pest::state(input, |state| {
447     ///     state.sequence(|s| {
448     ///         s.rule(Rule::a, |s| Ok(s)).and_then(|s| {
449     ///             s.match_string("b")
450     ///         })
451     ///     }).or_else(|s| {
452     ///         Ok(s)
453     ///     })
454     /// }).unwrap().collect();
455     ///
456     /// assert_eq!(pairs.len(), 0);
457     /// ```
458     #[inline]
sequence<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>> where F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,459     pub fn sequence<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>>
460     where
461         F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
462     {
463         self = self.inc_call_check_limit()?;
464         let token_index = self.queue.len();
465         let initial_pos = self.position;
466 
467         let result = f(self);
468 
469         match result {
470             Ok(new_state) => Ok(new_state),
471             Err(mut new_state) => {
472                 // Restore the initial position and truncate the token queue.
473                 new_state.position = initial_pos;
474                 new_state.queue.truncate(token_index);
475                 Err(new_state)
476             }
477         }
478     }
479 
480     /// Repeatedly applies the transformation provided by `f` from the `Box<ParserState>`. Returns
481     /// `Ok` with the updated `Box<ParserState>` returned by `f` wrapped up in an `Err`.
482     ///
483     /// # Examples
484     ///
485     /// ```
486     /// # use pest;
487     /// # #[allow(non_camel_case_types)]
488     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
489     /// enum Rule {
490     ///     ab
491     /// }
492     ///
493     /// let input = "aab";
494     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
495     /// let mut result = state.repeat(|s| {
496     ///     s.match_string("a")
497     /// });
498     /// assert!(result.is_ok());
499     /// assert_eq!(result.unwrap().position().pos(), 2);
500     ///
501     /// state = pest::ParserState::new(input);
502     /// result = state.repeat(|s| {
503     ///     s.match_string("b")
504     /// });
505     /// assert!(result.is_ok());
506     /// assert_eq!(result.unwrap().position().pos(), 0);
507     /// ```
508     #[inline]
repeat<F>(mut self: Box<Self>, mut f: F) -> ParseResult<Box<Self>> where F: FnMut(Box<Self>) -> ParseResult<Box<Self>>,509     pub fn repeat<F>(mut self: Box<Self>, mut f: F) -> ParseResult<Box<Self>>
510     where
511         F: FnMut(Box<Self>) -> ParseResult<Box<Self>>,
512     {
513         self = self.inc_call_check_limit()?;
514         let mut result = f(self);
515 
516         loop {
517             match result {
518                 Ok(state) => result = f(state),
519                 Err(state) => return Ok(state),
520             };
521         }
522     }
523 
524     /// Optionally applies the transformation provided by `f` from the `Box<ParserState>`. Returns
525     /// `Ok` with the updated `Box<ParserState>` returned by `f` regardless of the `Result`.
526     ///
527     /// # Examples
528     ///
529     /// ```
530     /// # use pest;
531     /// # #[allow(non_camel_case_types)]
532     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
533     /// enum Rule {
534     ///     ab
535     /// }
536     ///
537     /// let input = "ab";
538     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
539     /// let result = state.optional(|s| {
540     ///     s.match_string("ab")
541     /// });
542     /// assert!(result.is_ok());
543     ///
544     /// state = pest::ParserState::new(input);
545     /// let result = state.optional(|s| {
546     ///     s.match_string("ac")
547     /// });
548     /// assert!(result.is_ok());
549     /// ```
550     #[inline]
optional<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>> where F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,551     pub fn optional<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>>
552     where
553         F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
554     {
555         self = self.inc_call_check_limit()?;
556         match f(self) {
557             Ok(state) | Err(state) => Ok(state),
558         }
559     }
560 
561     /// Attempts to match a single character based on a filter function. Returns `Ok` with the
562     /// updated `Box<ParserState>` if successful, or `Err` with the updated `Box<ParserState>`
563     /// otherwise.
564     ///
565     /// # Examples
566     ///
567     /// ```
568     /// # use pest;
569     /// # #[allow(non_camel_case_types)]
570     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
571     /// enum Rule {}
572     ///
573     /// let input = "ab";
574     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
575     /// let result = state.match_char_by(|c| c.is_ascii());
576     /// assert!(result.is_ok());
577     /// assert_eq!(result.unwrap().position().pos(), 1);
578     ///
579     /// let input = "❤";
580     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
581     /// let result = state.match_char_by(|c| c.is_ascii());
582     /// assert!(result.is_err());
583     /// assert_eq!(result.unwrap_err().position().pos(), 0);
584     /// ```
585     #[inline]
match_char_by<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>> where F: FnOnce(char) -> bool,586     pub fn match_char_by<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>>
587     where
588         F: FnOnce(char) -> bool,
589     {
590         if self.position.match_char_by(f) {
591             Ok(self)
592         } else {
593             Err(self)
594         }
595     }
596 
597     /// Attempts to match the given string. Returns `Ok` with the updated `Box<ParserState>` if
598     /// successful, or `Err` with the updated `Box<ParserState>` otherwise.
599     ///
600     /// # Examples
601     ///
602     /// ```
603     /// # use pest;
604     /// # #[allow(non_camel_case_types)]
605     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
606     /// enum Rule {}
607     ///
608     /// let input = "ab";
609     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
610     /// let mut result = state.match_string("ab");
611     /// assert!(result.is_ok());
612     /// assert_eq!(result.unwrap().position().pos(), 2);
613     ///
614     /// state = pest::ParserState::new(input);
615     /// result = state.match_string("ac");
616     /// assert!(result.is_err());
617     /// assert_eq!(result.unwrap_err().position().pos(), 0);
618     /// ```
619     #[inline]
match_string(mut self: Box<Self>, string: &str) -> ParseResult<Box<Self>>620     pub fn match_string(mut self: Box<Self>, string: &str) -> ParseResult<Box<Self>> {
621         if self.position.match_string(string) {
622             Ok(self)
623         } else {
624             Err(self)
625         }
626     }
627 
628     /// Attempts to case-insensitively match the given string. Returns `Ok` with the updated
629     /// `Box<ParserState>` if successful, or `Err` with the updated `Box<ParserState>` otherwise.
630     ///
631     /// # Examples
632     ///
633     /// ```
634     /// # use pest;
635     /// # #[allow(non_camel_case_types)]
636     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
637     /// enum Rule {}
638     ///
639     /// let input = "ab";
640     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
641     /// let mut result = state.match_insensitive("AB");
642     /// assert!(result.is_ok());
643     /// assert_eq!(result.unwrap().position().pos(), 2);
644     ///
645     /// state = pest::ParserState::new(input);
646     /// result = state.match_insensitive("AC");
647     /// assert!(result.is_err());
648     /// assert_eq!(result.unwrap_err().position().pos(), 0);
649     /// ```
650     #[inline]
match_insensitive(mut self: Box<Self>, string: &str) -> ParseResult<Box<Self>>651     pub fn match_insensitive(mut self: Box<Self>, string: &str) -> ParseResult<Box<Self>> {
652         if self.position.match_insensitive(string) {
653             Ok(self)
654         } else {
655             Err(self)
656         }
657     }
658 
659     /// Attempts to match a single character from the given range. Returns `Ok` with the updated
660     /// `Box<ParserState>` if successful, or `Err` with the updated `Box<ParserState>` otherwise.
661     ///
662     /// # Caution
663     /// The provided `range` is intepreted as inclusive.
664     ///
665     /// # Examples
666     ///
667     /// ```
668     /// # use pest;
669     /// # #[allow(non_camel_case_types)]
670     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
671     /// enum Rule {}
672     ///
673     /// let input = "ab";
674     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
675     /// let mut result = state.match_range('a'..'z');
676     /// assert!(result.is_ok());
677     /// assert_eq!(result.unwrap().position().pos(), 1);
678     ///
679     /// state = pest::ParserState::new(input);
680     /// result = state.match_range('A'..'Z');
681     /// assert!(result.is_err());
682     /// assert_eq!(result.unwrap_err().position().pos(), 0);
683     /// ```
684     #[inline]
match_range(mut self: Box<Self>, range: Range<char>) -> ParseResult<Box<Self>>685     pub fn match_range(mut self: Box<Self>, range: Range<char>) -> ParseResult<Box<Self>> {
686         if self.position.match_range(range) {
687             Ok(self)
688         } else {
689             Err(self)
690         }
691     }
692 
693     /// Attempts to skip `n` characters forward. Returns `Ok` with the updated `Box<ParserState>`
694     /// if successful, or `Err` with the updated `Box<ParserState>` otherwise.
695     ///
696     /// # Examples
697     ///
698     /// ```
699     /// # use pest;
700     /// # #[allow(non_camel_case_types)]
701     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
702     /// enum Rule {}
703     ///
704     /// let input = "ab";
705     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
706     /// let mut result = state.skip(1);
707     /// assert!(result.is_ok());
708     /// assert_eq!(result.unwrap().position().pos(), 1);
709     ///
710     /// state = pest::ParserState::new(input);
711     /// result = state.skip(3);
712     /// assert!(result.is_err());
713     /// assert_eq!(result.unwrap_err().position().pos(), 0);
714     /// ```
715     #[inline]
skip(mut self: Box<Self>, n: usize) -> ParseResult<Box<Self>>716     pub fn skip(mut self: Box<Self>, n: usize) -> ParseResult<Box<Self>> {
717         if self.position.skip(n) {
718             Ok(self)
719         } else {
720             Err(self)
721         }
722     }
723 
724     /// Attempts to skip forward until one of the given strings is found. Returns `Ok` with the
725     /// updated `Box<ParserState>` whether or not one of the strings is found.
726     ///
727     /// # Examples
728     ///
729     /// ```
730     /// # use pest;
731     /// # #[allow(non_camel_case_types)]
732     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
733     /// enum Rule {}
734     ///
735     /// let input = "abcd";
736     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
737     /// let mut result = state.skip_until(&["c", "d"]);
738     /// assert!(result.is_ok());
739     /// assert_eq!(result.unwrap().position().pos(), 2);
740     /// ```
741     #[inline]
skip_until(mut self: Box<Self>, strings: &[&str]) -> ParseResult<Box<Self>>742     pub fn skip_until(mut self: Box<Self>, strings: &[&str]) -> ParseResult<Box<Self>> {
743         self.position.skip_until(strings);
744         Ok(self)
745     }
746 
747     /// Attempts to match the start of the input. Returns `Ok` with the current `Box<ParserState>`
748     /// if the parser has not yet advanced, or `Err` with the current `Box<ParserState>` otherwise.
749     ///
750     /// # Examples
751     ///
752     /// ```
753     /// # use pest;
754     /// # #[allow(non_camel_case_types)]
755     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
756     /// enum Rule {}
757     ///
758     /// let input = "ab";
759     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
760     /// let mut result = state.start_of_input();
761     /// assert!(result.is_ok());
762     ///
763     /// state = pest::ParserState::new(input);
764     /// state = state.match_string("ab").unwrap();
765     /// result = state.start_of_input();
766     /// assert!(result.is_err());
767     /// ```
768     #[inline]
start_of_input(self: Box<Self>) -> ParseResult<Box<Self>>769     pub fn start_of_input(self: Box<Self>) -> ParseResult<Box<Self>> {
770         if self.position.at_start() {
771             Ok(self)
772         } else {
773             Err(self)
774         }
775     }
776 
777     /// Attempts to match the end of the input. Returns `Ok` with the current `Box<ParserState>` if
778     /// there is no input remaining, or `Err` with the current `Box<ParserState>` otherwise.
779     ///
780     /// # Examples
781     ///
782     /// ```
783     /// # use pest;
784     /// # #[allow(non_camel_case_types)]
785     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
786     /// enum Rule {}
787     ///
788     /// let input = "ab";
789     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
790     /// let mut result = state.end_of_input();
791     /// assert!(result.is_err());
792     ///
793     /// state = pest::ParserState::new(input);
794     /// state = state.match_string("ab").unwrap();
795     /// result = state.end_of_input();
796     /// assert!(result.is_ok());
797     /// ```
798     #[inline]
end_of_input(self: Box<Self>) -> ParseResult<Box<Self>>799     pub fn end_of_input(self: Box<Self>) -> ParseResult<Box<Self>> {
800         if self.position.at_end() {
801             Ok(self)
802         } else {
803             Err(self)
804         }
805     }
806 
807     /// Starts a lookahead transformation provided by `f` from the `Box<ParserState>`. It returns
808     /// `Ok` with the current `Box<ParserState>` if `f` also returns an `Ok`, or `Err` with the current
809     /// `Box<ParserState>` otherwise. If `is_positive` is `false`, it swaps the `Ok` and `Err`
810     /// together, negating the `Result`.
811     ///
812     /// # Examples
813     ///
814     /// ```
815     /// # use pest;
816     /// # #[allow(non_camel_case_types)]
817     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
818     /// enum Rule {
819     ///     a
820     /// }
821     ///
822     /// let input = "a";
823     /// let pairs: Vec<_> = pest::state(input, |state| {
824     ///     state.lookahead(true, |state| {
825     ///         state.rule(Rule::a, |s| Ok(s))
826     ///     })
827     /// }).unwrap().collect();
828     ///
829     /// assert_eq!(pairs.len(), 0);
830     /// ```
831     #[inline]
lookahead<F>(mut self: Box<Self>, is_positive: bool, f: F) -> ParseResult<Box<Self>> where F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,832     pub fn lookahead<F>(mut self: Box<Self>, is_positive: bool, f: F) -> ParseResult<Box<Self>>
833     where
834         F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
835     {
836         self = self.inc_call_check_limit()?;
837         let initial_lookahead = self.lookahead;
838 
839         self.lookahead = if is_positive {
840             match initial_lookahead {
841                 Lookahead::None | Lookahead::Positive => Lookahead::Positive,
842                 Lookahead::Negative => Lookahead::Negative,
843             }
844         } else {
845             match initial_lookahead {
846                 Lookahead::None | Lookahead::Positive => Lookahead::Negative,
847                 Lookahead::Negative => Lookahead::Positive,
848             }
849         };
850 
851         let initial_pos = self.position;
852 
853         let result = f(self.checkpoint());
854 
855         let result_state = match result {
856             Ok(mut new_state) => {
857                 new_state.position = initial_pos;
858                 new_state.lookahead = initial_lookahead;
859                 Ok(new_state.restore())
860             }
861             Err(mut new_state) => {
862                 new_state.position = initial_pos;
863                 new_state.lookahead = initial_lookahead;
864                 Err(new_state.restore())
865             }
866         };
867 
868         if is_positive {
869             result_state
870         } else {
871             match result_state {
872                 Ok(state) => Err(state),
873                 Err(state) => Ok(state),
874             }
875         }
876     }
877 
878     /// Transformation which stops `Token`s from being generated according to `is_atomic`.
879     ///
880     /// # Examples
881     ///
882     /// ```
883     /// # use pest::{self, Atomicity};
884     /// # #[allow(non_camel_case_types)]
885     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
886     /// enum Rule {
887     ///     a
888     /// }
889     ///
890     /// let input = "a";
891     /// let pairs: Vec<_> = pest::state(input, |state| {
892     ///     state.atomic(Atomicity::Atomic, |s| {
893     ///         s.rule(Rule::a, |s| Ok(s))
894     ///     })
895     /// }).unwrap().collect();
896     ///
897     /// assert_eq!(pairs.len(), 0);
898     /// ```
899     #[inline]
atomic<F>(mut self: Box<Self>, atomicity: Atomicity, f: F) -> ParseResult<Box<Self>> where F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,900     pub fn atomic<F>(mut self: Box<Self>, atomicity: Atomicity, f: F) -> ParseResult<Box<Self>>
901     where
902         F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
903     {
904         self = self.inc_call_check_limit()?;
905         let initial_atomicity = self.atomicity;
906         let should_toggle = self.atomicity != atomicity;
907 
908         if should_toggle {
909             self.atomicity = atomicity;
910         }
911 
912         let result = f(self);
913 
914         match result {
915             Ok(mut new_state) => {
916                 if should_toggle {
917                     new_state.atomicity = initial_atomicity;
918                 }
919                 Ok(new_state)
920             }
921             Err(mut new_state) => {
922                 if should_toggle {
923                     new_state.atomicity = initial_atomicity;
924                 }
925                 Err(new_state)
926             }
927         }
928     }
929 
930     /// Evaluates the result of closure `f` and pushes the span of the input consumed from before
931     /// `f` is called to after `f` is called to the stack. Returns `Ok(Box<ParserState>)` if `f` is
932     /// called successfully, or `Err(Box<ParserState>)` otherwise.
933     ///
934     /// # Examples
935     ///
936     /// ```
937     /// # use pest;
938     /// # #[allow(non_camel_case_types)]
939     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
940     /// enum Rule {}
941     ///
942     /// let input = "ab";
943     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
944     /// let mut result = state.stack_push(|state| state.match_string("a"));
945     /// assert!(result.is_ok());
946     /// assert_eq!(result.unwrap().position().pos(), 1);
947     /// ```
948     #[inline]
stack_push<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>> where F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,949     pub fn stack_push<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>>
950     where
951         F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
952     {
953         self = self.inc_call_check_limit()?;
954         let start = self.position;
955 
956         let result = f(self);
957 
958         match result {
959             Ok(mut state) => {
960                 let end = state.position;
961                 state.stack.push(start.span(&end));
962                 Ok(state)
963             }
964             Err(state) => Err(state),
965         }
966     }
967 
968     /// Peeks the top of the stack and attempts to match the string. Returns `Ok(Box<ParserState>)`
969     /// if the string is matched successfully, or `Err(Box<ParserState>)` otherwise.
970     ///
971     /// # Examples
972     ///
973     /// ```
974     /// # use pest;
975     /// # #[allow(non_camel_case_types)]
976     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
977     /// enum Rule {}
978     ///
979     /// let input = "aa";
980     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
981     /// let mut result = state.stack_push(|state| state.match_string("a")).and_then(
982     ///     |state| state.stack_peek()
983     /// );
984     /// assert!(result.is_ok());
985     /// assert_eq!(result.unwrap().position().pos(), 2);
986     /// ```
987     #[inline]
stack_peek(self: Box<Self>) -> ParseResult<Box<Self>>988     pub fn stack_peek(self: Box<Self>) -> ParseResult<Box<Self>> {
989         let string = self
990             .stack
991             .peek()
992             .expect("peek was called on empty stack")
993             .as_str();
994         self.match_string(string)
995     }
996 
997     /// Pops the top of the stack and attempts to match the string. Returns `Ok(Box<ParserState>)`
998     /// if the string is matched successfully, or `Err(Box<ParserState>)` otherwise.
999     ///
1000     /// # Examples
1001     ///
1002     /// ```
1003     /// # use pest;
1004     /// # #[allow(non_camel_case_types)]
1005     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1006     /// enum Rule {}
1007     ///
1008     /// let input = "aa";
1009     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1010     /// let mut result = state.stack_push(|state| state.match_string("a")).and_then(
1011     ///     |state| state.stack_pop()
1012     /// );
1013     /// assert!(result.is_ok());
1014     /// assert_eq!(result.unwrap().position().pos(), 2);
1015     /// ```
1016     #[inline]
stack_pop(mut self: Box<Self>) -> ParseResult<Box<Self>>1017     pub fn stack_pop(mut self: Box<Self>) -> ParseResult<Box<Self>> {
1018         let string = self
1019             .stack
1020             .pop()
1021             .expect("pop was called on empty stack")
1022             .as_str();
1023         self.match_string(string)
1024     }
1025 
1026     /// Matches part of the state of the stack.
1027     ///
1028     /// # Examples
1029     ///
1030     /// ```
1031     /// # use pest::{self, MatchDir};
1032     /// # #[allow(non_camel_case_types)]
1033     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1034     /// enum Rule {}
1035     ///
1036     /// let input = "abcd cd cb";
1037     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1038     /// let mut result = state
1039     ///     .stack_push(|state| state.match_string("a"))
1040     ///     .and_then(|state| state.stack_push(|state| state.match_string("b")))
1041     ///     .and_then(|state| state.stack_push(|state| state.match_string("c")))
1042     ///     .and_then(|state| state.stack_push(|state| state.match_string("d")))
1043     ///     .and_then(|state| state.match_string(" "))
1044     ///     .and_then(|state| state.stack_match_peek_slice(2, None, MatchDir::BottomToTop))
1045     ///     .and_then(|state| state.match_string(" "))
1046     ///     .and_then(|state| state.stack_match_peek_slice(1, Some(-1), MatchDir::TopToBottom));
1047     /// assert!(result.is_ok());
1048     /// assert_eq!(result.unwrap().position().pos(), 10);
1049     /// ```
1050     #[inline]
stack_match_peek_slice( mut self: Box<Self>, start: i32, end: Option<i32>, match_dir: MatchDir, ) -> ParseResult<Box<Self>>1051     pub fn stack_match_peek_slice(
1052         mut self: Box<Self>,
1053         start: i32,
1054         end: Option<i32>,
1055         match_dir: MatchDir,
1056     ) -> ParseResult<Box<Self>> {
1057         let range = match constrain_idxs(start, end, self.stack.len()) {
1058             Some(r) => r,
1059             None => return Err(self),
1060         };
1061         // return true if an empty sequence is requested
1062         if range.end <= range.start {
1063             return Ok(self);
1064         }
1065 
1066         let mut position = self.position;
1067         let result = {
1068             let mut iter_b2t = self.stack[range].iter();
1069             let matcher = |span: &Span<'_>| position.match_string(span.as_str());
1070             match match_dir {
1071                 MatchDir::BottomToTop => iter_b2t.all(matcher),
1072                 MatchDir::TopToBottom => iter_b2t.rev().all(matcher),
1073             }
1074         };
1075         if result {
1076             self.position = position;
1077             Ok(self)
1078         } else {
1079             Err(self)
1080         }
1081     }
1082 
1083     /// Matches the full state of the stack.
1084     ///
1085     /// # Examples
1086     ///
1087     /// ```
1088     /// # use pest;
1089     /// # #[allow(non_camel_case_types)]
1090     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1091     /// enum Rule {}
1092     ///
1093     /// let input = "abba";
1094     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1095     /// let mut result = state
1096     ///     .stack_push(|state| state.match_string("a"))
1097     ///     .and_then(|state| { state.stack_push(|state| state.match_string("b")) })
1098     ///     .and_then(|state| state.stack_match_peek());
1099     /// assert!(result.is_ok());
1100     /// assert_eq!(result.unwrap().position().pos(), 4);
1101     /// ```
1102     #[inline]
stack_match_peek(self: Box<Self>) -> ParseResult<Box<Self>>1103     pub fn stack_match_peek(self: Box<Self>) -> ParseResult<Box<Self>> {
1104         self.stack_match_peek_slice(0, None, MatchDir::TopToBottom)
1105     }
1106 
1107     /// Matches the full state of the stack. This method will clear the stack as it evaluates.
1108     ///
1109     /// # Examples
1110     ///
1111     /// ```
1112     /// /// # use pest;
1113     /// # #[allow(non_camel_case_types)]
1114     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1115     /// enum Rule {}
1116     ///
1117     /// let input = "aaaa";
1118     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1119     /// let mut result = state.stack_push(|state| state.match_string("a")).and_then(|state| {
1120     ///     state.stack_push(|state| state.match_string("a"))
1121     /// }).and_then(|state| state.stack_match_peek());
1122     /// assert!(result.is_ok());
1123     /// assert_eq!(result.unwrap().position().pos(), 4);
1124     /// ```
1125     #[inline]
stack_match_pop(mut self: Box<Self>) -> ParseResult<Box<Self>>1126     pub fn stack_match_pop(mut self: Box<Self>) -> ParseResult<Box<Self>> {
1127         let mut position = self.position;
1128         let mut result = true;
1129         while let Some(span) = self.stack.pop() {
1130             result = position.match_string(span.as_str());
1131             if !result {
1132                 break;
1133             }
1134         }
1135 
1136         if result {
1137             self.position = position;
1138             Ok(self)
1139         } else {
1140             Err(self)
1141         }
1142     }
1143 
1144     /// Drops the top of the stack. Returns `Ok(Box<ParserState>)` if there was a value to drop, or
1145     /// `Err(Box<ParserState>)` otherwise.
1146     ///
1147     /// # Examples
1148     ///
1149     /// ```
1150     /// # use pest;
1151     /// # #[allow(non_camel_case_types)]
1152     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1153     /// enum Rule {}
1154     ///
1155     /// let input = "aa";
1156     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1157     /// let mut result = state.stack_push(|state| state.match_string("a")).and_then(
1158     ///     |state| state.stack_drop()
1159     /// );
1160     /// assert!(result.is_ok());
1161     /// assert_eq!(result.unwrap().position().pos(), 1);
1162     /// ```
1163     #[inline]
stack_drop(mut self: Box<Self>) -> ParseResult<Box<Self>>1164     pub fn stack_drop(mut self: Box<Self>) -> ParseResult<Box<Self>> {
1165         match self.stack.pop() {
1166             Some(_) => Ok(self),
1167             None => Err(self),
1168         }
1169     }
1170 
1171     /// Restores the original state of the `ParserState` when `f` returns an `Err`. Currently,
1172     /// this method only restores the stack.
1173     ///
1174     /// # Examples
1175     ///
1176     /// ```
1177     /// # use pest;
1178     /// # #[allow(non_camel_case_types)]
1179     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1180     /// enum Rule {}
1181     ///
1182     /// let input = "ab";
1183     /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1184     /// let mut result = state.restore_on_err(|state| state.stack_push(|state|
1185     ///     state.match_string("a")).and_then(|state| state.match_string("a"))
1186     /// );
1187     ///
1188     /// assert!(result.is_err());
1189     ///
1190     /// // Since the the rule doesn't match, the "a" pushed to the stack will be removed.
1191     /// let catch_panic = std::panic::catch_unwind(|| result.unwrap_err().stack_pop());
1192     /// assert!(catch_panic.is_err());
1193     /// ```
1194     #[inline]
restore_on_err<F>(self: Box<Self>, f: F) -> ParseResult<Box<Self>> where F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,1195     pub fn restore_on_err<F>(self: Box<Self>, f: F) -> ParseResult<Box<Self>>
1196     where
1197         F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
1198     {
1199         match f(self.checkpoint()) {
1200             Ok(state) => Ok(state.checkpoint_ok()),
1201             Err(state) => Err(state.restore()),
1202         }
1203     }
1204 
1205     // Mark the current state as a checkpoint and return the `Box`.
1206     #[inline]
checkpoint(mut self: Box<Self>) -> Box<Self>1207     pub(crate) fn checkpoint(mut self: Box<Self>) -> Box<Self> {
1208         self.stack.snapshot();
1209         self
1210     }
1211 
1212     // The checkpoint was cleared successfully
1213     // so remove it without touching other stack state.
1214     #[inline]
checkpoint_ok(mut self: Box<Self>) -> Box<Self>1215     pub(crate) fn checkpoint_ok(mut self: Box<Self>) -> Box<Self> {
1216         self.stack.clear_snapshot();
1217         self
1218     }
1219 
1220     // Restore the current state to the most recent checkpoint.
1221     #[inline]
restore(mut self: Box<Self>) -> Box<Self>1222     pub(crate) fn restore(mut self: Box<Self>) -> Box<Self> {
1223         self.stack.restore();
1224         self
1225     }
1226 }
1227 
constrain_idxs(start: i32, end: Option<i32>, len: usize) -> Option<Range<usize>>1228 fn constrain_idxs(start: i32, end: Option<i32>, len: usize) -> Option<Range<usize>> {
1229     let start_norm = normalize_index(start, len)?;
1230     let end_norm = end.map_or(Some(len), |e| normalize_index(e, len))?;
1231     Some(start_norm..end_norm)
1232 }
1233 
1234 /// Normalizes the index using its sequence’s length.
1235 /// Returns `None` if the normalized index is OOB.
normalize_index(i: i32, len: usize) -> Option<usize>1236 fn normalize_index(i: i32, len: usize) -> Option<usize> {
1237     if i > len as i32 {
1238         None
1239     } else if i >= 0 {
1240         Some(i as usize)
1241     } else {
1242         let real_i = len as i32 + i;
1243         if real_i >= 0 {
1244             Some(real_i as usize)
1245         } else {
1246             None
1247         }
1248     }
1249 }
1250 
1251 #[cfg(test)]
1252 mod test {
1253     use super::*;
1254 
1255     #[test]
normalize_index_pos()1256     fn normalize_index_pos() {
1257         assert_eq!(normalize_index(4, 6), Some(4));
1258         assert_eq!(normalize_index(5, 5), Some(5));
1259         assert_eq!(normalize_index(6, 3), None);
1260     }
1261 
1262     #[test]
normalize_index_neg()1263     fn normalize_index_neg() {
1264         assert_eq!(normalize_index(-4, 6), Some(2));
1265         assert_eq!(normalize_index(-5, 5), Some(0));
1266         assert_eq!(normalize_index(-6, 3), None);
1267     }
1268 }
1269