noa_parser/
recognizer.rs

1//! Defines how to recognize an object.
2
3use crate::errors::{ParseError, ParseResult};
4use crate::matcher::{Match, MatchSize};
5use crate::scanner::Scanner;
6
7/// A trait that defines how to recognize an object.
8///
9/// # Type Parameters
10/// * `V` - The type of the object to recognize
11/// * `T` - The type of the data to scan
12/// * `'a` - The lifetime of the data to scan
13pub trait Recognizable<'a, T, V>: MatchSize {
14    /// Try to recognize the object for the given scanner.
15    ///
16    /// # Type Parameters
17    /// V - The type of the object to recognize
18    ///
19    /// # Arguments
20    /// * `scanner` - The scanner to recognize the object for.
21    ///
22    /// # Returns
23    /// * `Ok(Some(V))` if the object was recognized,
24    /// * `Ok(None)` if the object was not recognized,
25    /// * `Err(ParseError)` if an error occurred
26    ///
27    fn recognize(self, scanner: &mut Scanner<'a, T>) -> ParseResult<Option<V>>;
28}
29
30pub trait RecognizeSelf<'a, T, V>: MatchSize {
31    /// Try to recognize the object for the given scanner.
32    ///
33    /// # Arguments
34    /// * `scanner` - The scanner to recognize the object for.
35    ///
36    /// # Returns
37    /// * `Ok(Some(V))` if the object was recognized,
38    /// * `Ok(None)` if the object was not recognized,
39    /// * `Err(ParseError)` if an error occurred
40    fn recognize_self(self, scanner: &mut Scanner<'a, T>) -> ParseResult<Option<V>>;
41}
42
43/// Recognize an object for the given scanner.
44///
45/// # Type Parameters
46/// * `V` - The type of the object to recognize
47/// * `R` - The type of the recognizable object
48///
49/// # Arguments
50/// * `recognizable` - The recognizable object to use for recognition
51/// * `scanner` - The scanner to recognize the object for
52///
53/// # Returns
54/// * `Ok(V)` if the object was recognized,
55/// * `Err(ParseError)` if an error occurred
56///
57/// This function calls the `recognize` method of the recognizable object and
58/// returns its result. If the recognizable object was not recognized, an
59/// `Err(ParseError::UnexpectedToken)` is returned. If the scanner is at the end
60/// of its input and the recognizable object is longer than the remaining input,
61/// an `Err(ParseError::UnexpectedEndOfInput)` is returned.
62pub fn recognize<'a, T, V, R: Recognizable<'a, T, V>>(
63    recognizable: R,
64    scanner: &mut Scanner<'a, T>,
65) -> ParseResult<V> {
66    if recognizable.size() > scanner.remaining().len() {
67        return Err(ParseError::UnexpectedEndOfInput);
68    }
69    recognizable
70        .recognize(scanner)?
71        .ok_or(ParseError::UnexpectedToken)
72}
73
74/// Recognize an object for the given scanner.
75/// Return a slice of the recognized object.
76impl<'a, T, M: Match<T> + MatchSize> RecognizeSelf<'a, T, M> for M {
77    fn recognize_self(self, scanner: &mut Scanner<'a, T>) -> ParseResult<Option<M>> {
78        if scanner.is_empty() {
79            return Err(ParseError::UnexpectedEndOfInput);
80        }
81
82        let data = scanner.remaining();
83
84        let (result, size) = self.matcher(data);
85        if !result {
86            return Ok(None);
87        }
88        if !scanner.is_empty() {
89            scanner.bump_by(size);
90        }
91        Ok(Some(self))
92    }
93}
94
95/// A `Recognizer` is a type that wraps a `Scanner` and holds a successfully
96/// recognized value.
97///
98/// When a value is successfully recognized, the `Recognizer` stores the value in
99/// its `data` field and returns itself. If a value is not recognized, the
100/// `Recognizer` rewinds the scanner to the previous position and returns itself.
101///
102/// # Type Parameters
103///
104/// * `T` - The type of the data to scan.
105/// * `U` - The type of the value to recognize.
106/// * `'a` - The lifetime of the data to scan.
107/// * `'container` - The lifetime of the `Recognizer`.
108pub struct Recognizer<'a, 'container, T, U> {
109    data: Option<U>,
110    scanner: &'container mut Scanner<'a, T>,
111}
112
113impl<'a, 'b, T, R: RecognizeSelf<'a, T, R>> Recognizer<'a, 'b, T, R> {
114    /// Create a new `Recognizer` with the given scanner.
115    ///
116    /// # Arguments
117    ///
118    /// * `scanner` - The scanner to use when recognizing input.
119    ///
120    /// # Returns
121    ///
122    /// A new `Recognizer` that uses the given scanner.
123    pub fn new(scanner: &'b mut Scanner<'a, T>) -> Self {
124        Recognizer {
125            data: None,
126            scanner,
127        }
128    }
129
130    /// Attempt to recognize a `U` using the given `element`, and return the
131    /// current recognizer if it fails.
132    ///
133    /// # Arguments
134    ///
135    /// * `element` - A `Recognizable` that recognizes a `U`.
136    ///
137    /// # Returns
138    ///
139    /// If the `U` is successfully recognized, returns the current recognizer with
140    /// the resulting value in `data`. If the `U` is not successfully recognized,
141    /// returns the current recognizer with the current position of the scanner
142    /// rewound to the position at which the `U` was attempted, and `data` is left
143    /// `None`.
144    pub fn try_or(mut self, element: R) -> ParseResult<Recognizer<'a, 'b, T, R>> {
145        // Propagate result
146        if self.data.is_some() {
147            return Ok(self);
148        }
149        // Or apply current recognizer
150        if let Some(found) = element.recognize_self(self.scanner)? {
151            self.data = Some(found);
152        }
153        Ok(self)
154    }
155
156    /// Consume the recognizer and return the `U` that was recognized if the
157    /// recognizer was successful.
158    ///
159    /// # Returns
160    ///
161    /// If the recognizer was successful (i.e., `data` is `Some`), returns the
162    /// `U` that was recognized. Otherwise, returns `None`.
163    pub fn finish(self) -> Option<R> {
164        self.data
165    }
166
167    /// Consume the recognizer and return the `U` that was recognized if the
168    /// recognizer was successful, or run the given closure if the recognizer was
169    /// not successful.
170    ///
171    /// # Arguments
172    ///
173    /// * `closure` - A function that takes the `Scanner` and returns a
174    ///   `ParseResult<U>`.
175    ///
176    /// # Returns
177    ///
178    /// If the recognizer was successful (i.e., `data` is `Some`), returns the
179    /// `U` that was recognized. If the recognizer was not successful, the
180    /// `closure` is called with the `Scanner` and the result of the closure is
181    /// returned.
182    pub fn finish_with<F>(self, closure: F) -> ParseResult<R>
183    where
184        F: FnOnce(&mut Scanner<'a, T>) -> ParseResult<R>,
185    {
186        match self.data {
187            None => closure(self.scanner),
188            Some(token) => Ok(token),
189        }
190    }
191}
192
193#[cfg(test)]
194mod tests {
195    use crate::bytes::token::Token;
196    use crate::errors::ParseResult;
197    use crate::recognizer::{RecognizeSelf, Recognizer};
198
199    #[test]
200    fn test_recognizer() {
201        let data = b">";
202        let mut scanner = crate::scanner::Scanner::new(data);
203        let result = Token::GreaterThan
204            .recognize_self(&mut scanner)
205            .expect("failed to parse");
206        assert_eq!(result, Some(Token::GreaterThan));
207    }
208
209    #[test]
210    fn test_recognizer_multiple() -> ParseResult<()> {
211        let data = b">>";
212        let mut scanner = crate::scanner::Scanner::new(data);
213        let result = Recognizer::new(&mut scanner)
214            .try_or(Token::LessThan)?
215            .try_or(Token::GreaterThan)?
216            .finish()
217            .expect("failed to parse");
218        assert_eq!(result, Token::GreaterThan);
219        Ok(())
220    }
221}