intuicio_parser/
inspect.rs1use 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(®istry, "foo").unwrap();
66 assert_eq!(rest, "");
67 assert_eq!(result.read::<String>().unwrap().as_str(), "foo");
68 }
69}