1use std::collections::VecDeque;
4
5use openrpc_types::ParamStructure;
6use serde::Deserialize;
7use serde_json::{Value, json};
8
9use super::{jsonrpc_types::RequestParameters, util::Optional as _};
10use crate::rpc::error::ServerError;
11
12#[derive(Debug)]
16pub struct Parser<'a> {
17 params: Option<ParserInner>,
18 argument_names: &'a [&'a str],
20 call_count: usize,
22 n_required: usize,
24 has_errored: bool,
26}
27
28#[derive(Debug)]
29enum ParserInner {
30 ByPosition(VecDeque<Value>), ByName(serde_json::Map<String, Value>),
32}
33
34impl Drop for Parser<'_> {
35 fn drop(&mut self) {
36 if !std::thread::panicking() && !self.has_errored {
37 assert!(
38 self.call_count >= self.argument_names.len(),
39 "`Parser` has unhandled parameters - did you forget to call `parse`?"
40 );
41 }
42 }
43}
44
45impl<'a> Parser<'a> {
46 pub fn new(
51 params: Option<RequestParameters>,
52 names: &'a [&'a str], calling_convention: ParamStructure,
54 n_required: usize,
55 ) -> Result<Self, ServerError> {
56 Self::_new(params, names, calling_convention, n_required).map_err(Into::into)
57 }
58 fn _new(
59 params: Option<RequestParameters>,
60 names: &'a [&'a str],
61 calling_convention: ParamStructure,
62 n_required: usize,
63 ) -> Result<Self, ParseError<'a>> {
64 let params = match (params, calling_convention) {
65 (None, _) => None,
67 (Some(params), _) if names.is_empty() && params.is_empty() => None,
68 (Some(RequestParameters::ByPosition(_)), ParamStructure::ByName) => {
70 return Err(ParseError::MustBeNamed);
71 }
72 (Some(RequestParameters::ByName(_)), ParamStructure::ByPosition) => {
73 return Err(ParseError::MustBePositional);
74 }
75 (Some(RequestParameters::ByPosition(it)), _) if names.is_empty() && !it.is_empty() => {
80 return Err(ParseError::UnexpectedPositional(it.len()));
81 }
82 (Some(RequestParameters::ByName(it)), _) if names.is_empty() && !it.is_empty() => {
83 return Err(ParseError::UnexpectedNamed(
84 it.into_iter().map(|(it, _)| it).collect(),
85 ));
86 }
87 (Some(RequestParameters::ByPosition(it)), _) => {
89 Some(ParserInner::ByPosition(VecDeque::from(it)))
90 }
91 (Some(RequestParameters::ByName(it)), _) => Some(ParserInner::ByName(it)),
92 };
93
94 Ok(Self {
95 params,
96 argument_names: names,
97 call_count: 0,
98 n_required,
99 has_errored: false,
100 })
101 }
102 fn error<T>(&mut self, e: ParseError<'a>) -> Result<T, ParseError<'a>> {
103 self.has_errored = true;
104 Err(e)
105 }
106 pub fn parse<T>(&mut self) -> Result<T, ServerError>
107 where
108 T: for<'de> Deserialize<'de>,
109 {
110 self._parse().map_err(Into::into)
111 }
112 fn _parse<T>(&mut self) -> Result<T, ParseError<'a>>
113 where
114 T: for<'de> Deserialize<'de>,
115 {
116 let index = self.call_count;
117 self.call_count += 1;
118 let name = match self.argument_names.get(index) {
119 Some(it) => *it,
120 None => panic!(
121 "`Parser` was initialized with {} arguments, but `parse` was called {} times",
122 self.argument_names.len(),
123 self.call_count
124 ),
125 };
126 let ty = std::any::type_name::<T>();
127 let missing_parameter = ParseError::Missing {
128 index,
129 n_required: self.n_required,
130 name,
131 ty,
132 };
133 let deserialize_error = |error| ParseError::Deser {
134 index,
135 name,
136 ty,
137 error,
138 };
139 let t = match &mut self.params {
140 None => match T::optional() {
141 true => T::unwrap_none(),
142 false => self.error(missing_parameter)?,
143 },
144 Some(ParserInner::ByName(it)) => match it.remove(name) {
145 Some(it) => match serde_json::from_value::<T>(it) {
146 Ok(it) => it,
147 Err(e) => self.error(deserialize_error(e))?,
148 },
149 None => match T::optional() {
150 true => T::unwrap_none(),
151 false => self.error(missing_parameter)?,
152 },
153 },
154 Some(ParserInner::ByPosition(it)) => match it.pop_front() {
155 Some(it) => match serde_json::from_value::<T>(it) {
156 Ok(it) => it,
157 Err(e) => self.error(deserialize_error(e))?,
158 },
159 None => match T::optional() {
160 true if self.call_count > self.n_required => T::unwrap_none(),
161 _ => self.error(missing_parameter)?,
162 },
163 },
164 };
165 let final_arg = self.call_count >= self.argument_names.len();
166 if final_arg {
167 match self.params.take() {
168 Some(ParserInner::ByName(it)) => match it.is_empty() {
169 true => {}
170 false => self.error(ParseError::UnexpectedNamed(
171 it.into_iter().map(|(k, _)| k).collect(),
172 ))?,
173 },
174 Some(ParserInner::ByPosition(it)) => match it.len() {
175 0 => {}
176 n => self.error(ParseError::UnexpectedPositional(n))?,
177 },
178 None => {}
179 };
180 }
181 Ok(t)
182 }
183}
184
185#[derive(Debug)]
187enum ParseError<'a> {
188 Missing {
189 index: usize,
190 n_required: usize,
191 name: &'a str,
192 ty: &'a str,
193 },
194 Deser {
195 index: usize,
196 name: &'a str,
197 ty: &'a str,
198 error: serde_json::Error,
199 },
200 UnexpectedPositional(usize),
201 UnexpectedNamed(Vec<String>),
202 MustBeNamed,
203 MustBePositional,
204}
205
206impl<'a> From<ParseError<'a>> for ServerError {
207 fn from(value: ParseError<'a>) -> Self {
208 match value {
209 ParseError::Missing {
210 index,
211 n_required,
212 name,
213 ty,
214 } => ServerError::invalid_params(
215 "missing required parameter",
216 json!({
217 "index": index,
218 "n_required": n_required,
219 "name": name,
220 "type": ty
221 }),
222 ),
223 ParseError::Deser {
224 index,
225 name,
226 ty,
227 error,
228 } => ServerError::invalid_params(
229 "error deserializing parameter",
230 json!({
231 "index": index,
232 "name": name,
233 "type": ty,
234 "error": error.to_string()
235 }),
236 ),
237 ParseError::UnexpectedPositional(n) => {
238 ServerError::invalid_params("unexpected trailing arguments", json!({"count": n}))
239 }
240 ParseError::UnexpectedNamed(names) => {
241 ServerError::invalid_params("unexpected named arguments", json!(names))
242 }
243 ParseError::MustBeNamed => {
244 ServerError::invalid_params("this method only accepts arguments by-name", None)
245 }
246 ParseError::MustBePositional => {
247 ServerError::invalid_params("this method only accepts arguments by-position", None)
248 }
249 }
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 macro_rules! from_value {
258 ($tt:tt) => {
259 serde_json::from_value(serde_json::json!($tt)).unwrap()
260 };
261 }
262
263 #[test]
264 fn optional() {
265 let mut parser = Parser::_new(None, &["p0"], ParamStructure::Either, 0).unwrap();
267 assert_eq!(None::<i32>, parser._parse::<Option<i32>>().unwrap());
268
269 let mut parser =
271 Parser::_new(from_value!([]), &["opt"], ParamStructure::Either, 0).unwrap();
272 assert_eq!(None::<i32>, parser._parse::<Option<i32>>().unwrap());
273
274 let mut parser =
276 Parser::_new(from_value!({}), &["opt"], ParamStructure::Either, 0).unwrap();
277 assert_eq!(None::<i32>, parser._parse::<Option<i32>>().unwrap());
278
279 let mut parser =
281 Parser::_new(from_value!([0]), &["p0", "opt"], ParamStructure::Either, 0).unwrap();
282 assert_eq!(Some(0), parser._parse::<Option<i32>>().unwrap());
283 assert_eq!(None::<i32>, parser._parse::<Option<i32>>().unwrap());
284
285 let mut parser = Parser::_new(
287 from_value!({"p0": 0}),
288 &["p0", "opt"],
289 ParamStructure::Either,
290 0,
291 )
292 .unwrap();
293 assert_eq!(Some(0), parser._parse::<Option<i32>>().unwrap());
294 assert_eq!(None::<i32>, parser._parse::<Option<i32>>().unwrap());
295 }
296
297 #[test]
298 fn missing() {
299 let mut parser = Parser::_new(from_value!({}), &["p0"], ParamStructure::Either, 0).unwrap();
301 assert!(matches!(
302 parser._parse::<i32>().unwrap_err(),
303 ParseError::Missing { name: "p0", .. },
304 ));
305
306 let mut parser = Parser::_new(from_value!([]), &["p0"], ParamStructure::Either, 0).unwrap();
308 assert!(matches!(
309 parser._parse::<i32>().unwrap_err(),
310 ParseError::Missing { name: "p0", .. },
311 ));
312
313 let mut parser = Parser::_new(from_value!([]), &["p0"], ParamStructure::Either, 1).unwrap();
315 assert!(matches!(
316 parser._parse::<Option<i32>>().unwrap_err(),
317 ParseError::Missing { name: "p0", .. },
318 ));
319
320 let mut parser = Parser::_new(
322 from_value!({"p0": 0}),
323 &["p0", "p1"],
324 ParamStructure::Either,
325 0,
326 )
327 .unwrap();
328 assert_eq!(0, parser._parse::<i32>().unwrap());
329 assert!(matches!(
330 parser._parse::<i32>().unwrap_err(),
331 ParseError::Missing { name: "p1", .. },
332 ));
333
334 let mut parser =
336 Parser::_new(from_value!([0]), &["p0", "p1"], ParamStructure::Either, 0).unwrap();
337 assert_eq!(0, parser._parse::<i32>().unwrap());
338 assert!(matches!(
339 parser._parse::<i32>().unwrap_err(),
340 ParseError::Missing { name: "p1", .. },
341 ));
342 }
343
344 #[test]
345 fn unexpected() {
346 assert!(matches!(
348 Parser::_new(from_value!({ "surprise": () }), &[], ParamStructure::Either,0).unwrap_err(),
349 ParseError::UnexpectedNamed(it) if it == ["surprise"],
350 ));
351
352 assert!(matches!(
354 Parser::_new(from_value!(["surprise"]), &[], ParamStructure::Either, 0).unwrap_err(),
355 ParseError::UnexpectedPositional(1),
356 ));
357
358 let mut parser = Parser::_new(
360 from_value!({ "p0": 0, "surprise": () }),
361 &["p0"],
362 ParamStructure::Either,
363 0,
364 )
365 .unwrap();
366 assert!(matches!(
367 parser._parse::<i32>().unwrap_err(),
368 ParseError::UnexpectedNamed(it) if it == ["surprise"]
369 ));
370
371 let mut parser = Parser::_new(
373 from_value!([1, "surprise"]),
374 &["p0"],
375 ParamStructure::Either,
376 0,
377 )
378 .unwrap();
379 assert!(matches!(
380 parser._parse::<i32>().unwrap_err(),
381 ParseError::UnexpectedPositional(1),
382 ));
383 }
384
385 #[test]
386 #[should_panic = "`Parser` was initialized with 0 arguments, but `parse` was called 1 times"]
387 fn called_too_much() {
388 let mut parser = Parser::_new(None, &[], ParamStructure::Either, 0).unwrap();
389 let _ = parser._parse::<()>();
390 unreachable!()
391 }
392
393 #[test]
394 #[should_panic = "`Parser` has unhandled parameters - did you forget to call `parse`?"]
395 fn called_too_little() {
396 Parser::_new(None, &["p0"], ParamStructure::Either, 0).unwrap();
397 }
398}