intuicio_parser/
inspect.rs

1use crate::{ParseResult, Parser, ParserExt, ParserHandle, ParserOutput, ParserRegistry};
2use std::sync::{Arc, RwLock};
3
4pub mod shorthand {
5    use super::*;
6
7    pub fn inspect(
8        parser: ParserHandle,
9        f: impl FnMut(&ParserOutput) + Send + Sync + 'static,
10    ) -> ParserHandle {
11        InspectParser::new(parser, f).into_handle()
12    }
13}
14
15pub struct InspectParser {
16    parser: ParserHandle,
17    #[allow(clippy::type_complexity)]
18    closure: Arc<RwLock<dyn FnMut(&ParserOutput) + Send + Sync>>,
19}
20
21impl InspectParser {
22    pub fn new(parser: ParserHandle, f: impl FnMut(&ParserOutput) + Send + Sync + 'static) -> Self {
23        Self {
24            parser,
25            closure: Arc::new(RwLock::new(f)),
26        }
27    }
28}
29
30impl Parser for InspectParser {
31    fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
32        let (input, result) = self.parser.parse(registry, input)?;
33        match self.closure.write() {
34            Ok(mut closure) => {
35                (closure)(&result);
36            }
37            Err(_) => return Err("InspectParser cannot access closure mutably".into()),
38        }
39        Ok((input, result))
40    }
41
42    fn extend(&self, parser: ParserHandle) {
43        self.parser.extend(parser);
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use crate::{
50        inspect::InspectParser,
51        shorthand::{inspect, lit},
52        ParserRegistry,
53    };
54
55    fn is_async<T: Send + Sync>() {}
56
57    #[test]
58    fn test_inspect() {
59        is_async::<InspectParser>();
60
61        let registry = ParserRegistry::default();
62        let sentence = inspect(lit("foo"), |output| {
63            assert!(output.is::<String>());
64        });
65        let (rest, result) = sentence.parse(&registry, "foo").unwrap();
66        assert_eq!(rest, "");
67        assert_eq!(result.read::<String>().unwrap().as_str(), "foo");
68    }
69}