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(®istry, "foobar").unwrap();
105 assert_eq!(rest, "foobar");
106 value.consume::<ParserNoValue>().ok().unwrap();
107 slot.extend(keyword_foo);
108 let (rest, value) = slot.parse(®istry, "foobar").unwrap();
109 assert_eq!(rest, "bar");
110 assert!(value.consume::<String>().is_ok());
111 assert_eq!(
112 format!("{}", slot.parse(®istry, "barfoo").err().unwrap()),
113 "Expected 'foo'"
114 );
115 }
116}