1use crate::{ParseResult, Parser, ParserExt, ParserHandle, ParserOutput, ParserRegistry};
2use std::{
3 error::Error,
4 sync::{Arc, RwLock},
5};
6
7pub mod shorthand {
8 use super::*;
9
10 pub fn map<I: 'static, O: 'static>(
11 parser: ParserHandle,
12 f: impl FnMut(I) -> O + Send + Sync + 'static,
13 ) -> ParserHandle {
14 MapParser::new(parser, f).into_handle()
15 }
16
17 pub fn omap(
18 parser: ParserHandle,
19 f: impl FnMut(ParserOutput) -> ParserOutput + Send + Sync + 'static,
20 ) -> ParserHandle {
21 OutputMapParser::new(parser, f).into_handle()
22 }
23
24 pub fn map_err(
25 parser: ParserHandle,
26 f: impl FnMut(Box<dyn Error>) -> Box<dyn Error> + Send + Sync + 'static,
27 ) -> ParserHandle {
28 MapErrorParser::new(parser, f).into_handle()
29 }
30}
31
32pub struct MapParser<I, O> {
33 parser: ParserHandle,
34 closure: Arc<RwLock<dyn FnMut(I) -> O + Send + Sync>>,
35}
36
37impl<I, O> MapParser<I, O> {
38 pub fn new(parser: ParserHandle, f: impl FnMut(I) -> O + Send + Sync + 'static) -> Self {
39 Self {
40 parser,
41 closure: Arc::new(RwLock::new(f)),
42 }
43 }
44}
45
46impl<I: 'static, O: 'static> Parser for MapParser<I, O> {
47 fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
48 let (input, result) = self.parser.parse(registry, input)?;
49 let result = match self.closure.write() {
50 Ok(mut closure) => match result.consume::<I>() {
51 Ok(result) => (closure)(result),
52 Err(_) => {
53 return Err(format!(
54 "MapParser cannot downcast input from `{}` type",
55 std::any::type_name::<I>()
56 )
57 .into())
58 }
59 },
60 Err(_) => return Err("MapParser cannot access closure mutably".into()),
61 };
62 Ok((input, ParserOutput::new(result).ok().unwrap()))
63 }
64}
65
66pub struct OutputMapParser {
67 parser: ParserHandle,
68 closure: Arc<RwLock<dyn FnMut(ParserOutput) -> ParserOutput + Send + Sync>>,
69}
70
71impl OutputMapParser {
72 pub fn new(
73 parser: ParserHandle,
74 f: impl FnMut(ParserOutput) -> ParserOutput + Send + Sync + 'static,
75 ) -> Self {
76 Self {
77 parser,
78 closure: Arc::new(RwLock::new(f)),
79 }
80 }
81}
82
83impl Parser for OutputMapParser {
84 fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
85 let (input, result) = self.parser.parse(registry, input)?;
86 let result = match self.closure.write() {
87 Ok(mut closure) => (closure)(result),
88 Err(_) => return Err("OutputMapParser cannot access closure mutably".into()),
89 };
90 Ok((input, result))
91 }
92}
93
94pub struct MapErrorParser {
95 parser: ParserHandle,
96 #[allow(clippy::type_complexity)]
97 closure: Arc<RwLock<dyn FnMut(Box<dyn Error>) -> Box<dyn Error> + Send + Sync>>,
98}
99
100impl MapErrorParser {
101 pub fn new(
102 parser: ParserHandle,
103 f: impl FnMut(Box<dyn Error>) -> Box<dyn Error> + Send + Sync + 'static,
104 ) -> Self {
105 Self {
106 parser,
107 closure: Arc::new(RwLock::new(f)),
108 }
109 }
110}
111
112impl Parser for MapErrorParser {
113 fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
114 match self.parser.parse(registry, input) {
115 Ok(result) => Ok(result),
116 Err(error) => match self.closure.write() {
117 Ok(mut closure) => Err((closure)(error)),
118 Err(_) => Err("MapErrorParser cannot access closure mutably".into()),
119 },
120 }
121 }
122
123 fn extend(&self, parser: ParserHandle) {
124 self.parser.extend(parser);
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use crate::{
131 map::{MapErrorParser, MapParser, OutputMapParser},
132 shorthand::{map, map_err, number_float, omap},
133 ParserOutput, ParserRegistry,
134 };
135
136 fn is_async<T: Send + Sync>() {}
137
138 #[test]
139 fn test_map() {
140 is_async::<MapParser<(), ()>>();
141
142 let registry = ParserRegistry::default();
143 let number = map(number_float(), |value: String| {
144 value.parse::<f32>().unwrap()
145 });
146 assert_eq!(
147 number
148 .parse(®istry, "-4.2e1")
149 .unwrap()
150 .1
151 .consume::<f32>()
152 .ok()
153 .unwrap(),
154 -42.0
155 );
156 }
157
158 #[test]
159 fn test_omap() {
160 is_async::<OutputMapParser>();
161
162 let registry = ParserRegistry::default();
163 let number = omap(number_float(), |value| {
164 ParserOutput::new(
165 value
166 .consume::<String>()
167 .ok()
168 .unwrap()
169 .parse::<f32>()
170 .unwrap(),
171 )
172 .ok()
173 .unwrap()
174 });
175 assert_eq!(
176 number
177 .parse(®istry, "-4.2e1")
178 .unwrap()
179 .1
180 .consume::<f32>()
181 .ok()
182 .unwrap(),
183 -42.0
184 );
185 }
186
187 #[test]
188 fn test_map_error() {
189 is_async::<MapErrorParser>();
190
191 let registry = ParserRegistry::default();
192 let number = map_err(number_float(), |_| "Expected float number".into());
193 assert_eq!(
194 format!("{}", number.parse(®istry, "foo").err().unwrap()),
195 "Expected float number"
196 );
197 }
198}