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}