noa_parser/acceptor.rs
1//! A helper type for scanning and accepting values.
2
3use crate::errors::{ParseError, ParseResult};
4use crate::scanner::Scanner;
5use crate::visitor::Visitor;
6
7/// A type that wraps a `Scanner` and holds a successfully accepted value.
8///
9/// When a value is successfully accepted, the `Acceptor` stores the value in its
10/// `data` field and returns itself. If a value is not accepted, the `Acceptor`
11/// rewinds the scanner to the previous position and returns itself.
12///
13/// # Type Parameters
14///
15/// * `T` - The type of the data to scan.
16/// * `V` - The type of the value to accept.
17/// * `'a` - The lifetime of the data to scan.
18/// * `'b` - The lifetime of the acceptor.
19#[derive(Debug)]
20pub struct Acceptor<'a, 'b, T, V> {
21 /// The accepted value, if any.
22 data: Option<V>,
23 /// The scanner to use when consuming input.
24 scanner: &'b mut Scanner<'a, T>,
25}
26
27impl<'a, 'b, T, V> Acceptor<'a, 'b, T, V> {
28 /// Create a new acceptor.
29 ///
30 /// # Arguments
31 ///
32 /// * `scanner` - The scanner to use when consuming input.
33 ///
34 /// # Returns
35 ///
36 /// A new acceptor that uses the given scanner.
37 pub fn new(scanner: &'b mut Scanner<'a, T>) -> Acceptor<'a, 'b, T, V> {
38 Acceptor {
39 data: None,
40 scanner,
41 }
42 }
43}
44
45impl<'a, T, V> Acceptor<'a, '_, T, V> {
46 /// Attempt to accept a `U` using the given `transformer`, and rewind the scanner
47 /// and return the current acceptor if it fails.
48 ///
49 /// # Arguments
50 ///
51 /// * `transformer` - A function that takes a `U` and returns a `ParseResult<V>`.
52 ///
53 /// # Returns
54 ///
55 /// If the `U` is successfully accepted and the `transformer` returns `Ok`, returns
56 /// the current acceptor with the resulting value in `data`. If the `U` is not
57 /// successfully accepted, returns the current acceptor with the current position
58 /// of the scanner rewound to the position at which the `U` was attempted, and
59 /// `data` is left `None`.
60 pub fn try_or<U: Visitor<'a, T>, F>(mut self, transformer: F) -> ParseResult<Self>
61 where
62 F: Fn(U) -> V,
63 {
64 let cursor = self.scanner.current_position();
65 // Propagate the data
66 if self.data.is_some() {
67 return Ok(self);
68 }
69
70 match U::accept(self.scanner) {
71 Ok(found) => {
72 self.data = Some(transformer(found));
73 }
74 Err(ParseError::UnexpectedToken) => {
75 self.scanner.jump_to(cursor);
76 }
77 Err(err) => {
78 return Err(err);
79 }
80 }
81
82 Ok(self)
83 }
84
85 /// Consume the acceptor and return the `V` that was accepted if the acceptor was
86 /// successful.
87 ///
88 /// # Returns
89 ///
90 /// If the acceptor was successful (i.e., `data` is `Some`), returns the `V` that
91 /// was accepted. Otherwise, returns `None`.
92 pub fn finish(self) -> Option<V> {
93 self.data
94 }
95}