noa_parser/
peeker.rs

1use crate::errors::ParseResult;
2use crate::peek::{PeekResult, Peekable, Peeking};
3use crate::scanner::Scanner;
4
5/// A [Peeker] is a type that is used to find the best group to forecast
6pub struct Peeker<'a, 'b, T, S, E> {
7    scanner: &'b Scanner<'a, T>,
8    /// Pool of [Peekable]
9    peekables: Vec<Box<dyn Peekable<'a, T, S, E> + 'a>>,
10}
11
12impl<'a, 'b, T, S, E> Peeker<'a, 'b, T, S, E> {
13    pub fn new(scanner: &'b Scanner<'a, T>) -> Self {
14        Self {
15            scanner,
16            peekables: vec![],
17        }
18    }
19}
20
21impl<'a, 'b, T, S, E> Peeker<'a, 'b, T, S, E> {
22    /// Add new [Peekable] element to the peeking pool
23    pub fn add_peekable<F: Peekable<'a, T, S, E> + 'a>(mut self, peekable: F) -> Self {
24        self.peekables.push(Box::new(peekable));
25        self
26    }
27
28    /// Run the [Forecast] pool, find the minimal group
29    pub fn peek(self) -> ParseResult<Option<Peeking<'b, T, S, E>>> {
30        let mut result = None;
31        // on boucle sur les possibilités de prédictions
32        for peekable in self.peekables.into_iter() {
33            let peek_result = peekable.peek(self.scanner)?;
34            // on tente de prédire l'élément
35            match peek_result {
36                // si l'on a trouvé quelque chose
37                PeekResult::Found {
38                    start,
39                    end,
40                    end_slice,
41                } => {
42                    // on récupère le groupe prédit
43                    let remaining = self.scanner.remaining();
44                    let data = &remaining[..end_slice];
45                    let new_forecast = Peeking {
46                        start,
47                        end,
48                        data,
49                        end_slice,
50                    };
51                    match &result {
52                        // si l'on n'a encore rien prédit du tout
53                        None => {
54                            // le groupe trouvé devient le résultat
55                            result = Some(new_forecast);
56                        }
57                        // s'il y a déjà une prédiction
58                        Some(min_forecast) => {
59                            // on compare la taille du groupe trouvé par rapport
60                            // à celui déjà trouvé
61                            if new_forecast.data.len() < min_forecast.data.len() {
62                                // il devient alors le nouveau groupe prédit
63                                result = Some(new_forecast);
64                            }
65                        }
66                    }
67                }
68                // si la prédiction échoue, on ne fait rien
69                PeekResult::NotFound => {}
70            }
71        }
72        Ok(result)
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use crate::bytes::token::Token;
79    use crate::peek::{Until, UntilEnd};
80    use crate::peeker::Peeker;
81    use crate::scanner::Scanner;
82
83    #[test]
84    fn test_peeker() {
85        let data = b"data\n";
86        let mut scanner = Scanner::new(data);
87        let peeker = Peeker::new(&mut scanner)
88            .add_peekable(Until::new(Token::Ln))
89            .add_peekable(UntilEnd::default());
90        let result = peeker
91            .peek()
92            .expect("failed to parse")
93            .expect("failed to peek");
94        assert_eq!(result.data, "data".as_bytes());
95
96        let data = b"data";
97        let mut scanner = Scanner::new(data);
98        let peeker = Peeker::new(&mut scanner)
99            .add_peekable(Until::new(Token::Ln))
100            .add_peekable(UntilEnd::default());
101        let result = peeker
102            .peek()
103            .expect("failed to parse")
104            .expect("failed to peek");
105        assert_eq!(result.data, "data".as_bytes());
106    }
107}