apple_clis/
shared.rs

1use crate::prelude::*;
2
3pub mod identifiers;
4pub mod types;
5
6pub(crate) use traits::*;
7pub(crate) use traits::impl_from_str_nom;
8pub use traits::PublicCommandOutput;
9mod traits;
10
11/// A combinator that takes a parser `inner` and produces a parser that also consumes both leading and
12/// trailing whitespace, returning the output of `inner`.
13pub(crate) fn ws<'a, F: 'a, O, E: nom::error::ParseError<&'a str>>(
14	inner: F,
15) -> impl FnMut(&'a str) -> IResult<&'a str, O, E>
16where
17	F: Fn(&'a str) -> IResult<&'a str, O, E>,
18{
19	delimited(multispace0, inner, multispace0)
20}
21
22/// Simplify testing
23/// ```ignore
24/// use apple_clis::prelude::*;
25/// 
26/// let examples = ["123", "456"]
27/// let func = |parsed| parsed.not_unimplemented();
28/// assert_nom_parses<YourT>(examples, func);
29/// ```
30#[cfg(any(test, doctest))]
31fn assert_nom_parses<T: NomFromStr + std::fmt::Display + std::fmt::Debug>(
32	examples: impl IntoIterator<Item = &'static str>,
33	successfully_parsed: impl Fn(&T) -> bool,
34) {
35	use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
36
37	let fmt_verbose_layer = tracing_subscriber::fmt::layer().pretty();
38
39	tracing_subscriber::registry()
40		.with(fmt_verbose_layer)
41		.try_init()
42		.ok();
43
44	for example in examples.into_iter() {
45		let example = example.to_string();
46		match T::nom_from_str(&example) {
47			Ok((remaining, parsed)) => {
48				assert!(
49					remaining.is_empty(),
50					"Leftover input {:?} while parsing {} into {:?}",
51					remaining,
52					example,
53					parsed
54				);
55				assert_eq!(
56					parsed.to_string(),
57					example,
58					"Parsing {} into {:?} didn't match Display of {}",
59					example,
60					parsed,
61					example
62				);
63				assert!(
64					successfully_parsed(&parsed),
65					"While parsing {}, got unimplemented variant {:?}",
66					example,
67					parsed
68				);
69			}
70			Err(err) => {
71				panic!("Failed to parse {:?}: {}", example, err);
72			}
73		}
74	}
75}