intuicio_parser/
slot.rs

1use crate::{
2    ParseResult, Parser, ParserExt, ParserHandle, ParserNoValue, ParserOutput, ParserRegistry,
3};
4use std::sync::RwLock;
5
6pub mod shorthand {
7    use super::*;
8
9    pub fn slot(parser: ParserHandle) -> ParserHandle {
10        SlotParser::new(parser).into_handle()
11    }
12
13    pub fn slot_empty() -> ParserHandle {
14        SlotParser::default().into_handle()
15    }
16}
17
18#[derive(Default)]
19pub struct SlotParser {
20    parser: RwLock<Option<ParserHandle>>,
21    parse_error_when_empty: bool,
22}
23
24impl Clone for SlotParser {
25    fn clone(&self) -> Self {
26        Self {
27            parser: RwLock::new(self.parser.read().unwrap().clone()),
28            parse_error_when_empty: self.parse_error_when_empty,
29        }
30    }
31}
32
33impl SlotParser {
34    pub fn new(parser: ParserHandle) -> Self {
35        Self {
36            parser: RwLock::new(Some(parser)),
37            parse_error_when_empty: false,
38        }
39    }
40
41    pub fn parse_error_when_empty(mut self) -> Self {
42        self.parse_error_when_empty = true;
43        self
44    }
45
46    pub fn has(&self) -> bool {
47        self.parser.read().map(|v| v.is_some()).unwrap_or_default()
48    }
49
50    pub fn set(&self, parser: ParserHandle) {
51        if let Ok(mut v) = self.parser.write() {
52            *v = Some(parser);
53        }
54    }
55
56    pub fn get(&self) -> Option<ParserHandle> {
57        self.parser.read().ok()?.clone()
58    }
59
60    pub fn transform(&self, mut f: impl FnMut(Option<ParserHandle>) -> Option<ParserHandle>) {
61        if let Ok(mut inner) = self.parser.write() {
62            *inner = f(inner.clone());
63        }
64    }
65}
66
67impl Parser for SlotParser {
68    fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
69        if let Ok(inner) = self.parser.read() {
70            if let Some(parser) = inner.as_ref() {
71                parser.parse(registry, input)
72            } else if self.parse_error_when_empty {
73                Err("SlotParser has no parser".into())
74            } else {
75                Ok((input, ParserOutput::new(ParserNoValue).ok().unwrap()))
76            }
77        } else {
78            Err("Slot parser cannot be accessed".into())
79        }
80    }
81
82    fn extend(&self, parser: ParserHandle) {
83        self.set(parser);
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use crate::{
90        shorthand::{lit, slot_empty},
91        slot::SlotParser,
92        ParserNoValue, ParserRegistry,
93    };
94
95    fn is_async<T: Send + Sync>() {}
96
97    #[test]
98    fn test_slot() {
99        is_async::<SlotParser>();
100
101        let registry = ParserRegistry::default();
102        let keyword_foo = lit("foo");
103        let slot = slot_empty();
104        let (rest, value) = slot.parse(&registry, "foobar").unwrap();
105        assert_eq!(rest, "foobar");
106        value.consume::<ParserNoValue>().ok().unwrap();
107        slot.extend(keyword_foo);
108        let (rest, value) = slot.parse(&registry, "foobar").unwrap();
109        assert_eq!(rest, "bar");
110        assert!(value.consume::<String>().is_ok());
111        assert_eq!(
112            format!("{}", slot.parse(&registry, "barfoo").err().unwrap()),
113            "Expected 'foo'"
114        );
115    }
116}