1use core::hash::Hash;
2
3use nom::bytes::complete::tag;
4use nom::bytes::complete::take_until;
5use nom::character::complete::char;
6use nom::character::complete::space0;
7use nom::combinator::complete;
8use nom::combinator::map;
9use nom::sequence::delimited;
10use nom::sequence::preceded;
11use nom::IResult;
12use nom::Parser;
13
14#[derive(Clone, Debug, Eq, Hash, PartialEq)]
16pub enum MultiPartVal {
17 A(String),
20 C,
22 P(i128),
24 S(i128, Option<String>),
28 T(i128),
30 U(i128),
32}
33
34macro_rules! parse_mp_val {
35 ($name:ident, $tag:literal, $variant:ident) => {
36 #[doc = "Extracts multipart"]
37 #[doc = stringify!($tag)]
38 #[doc = " parameter"]
39 #[doc = ""]
40 #[doc = "# Errors"]
41 #[doc = " When match fails."]
42 pub fn $name(i: &str) -> IResult<&str, MultiPartVal> {
43 map(
44 preceded((space0, tag($tag)), nom::character::complete::i128),
45 MultiPartVal::$variant,
46 )
47 .parse(i)
48 }
49 };
50}
51
52pub fn parse_mp_a(i: &str) -> IResult<&str, MultiPartVal> {
59 map(
60 complete(delimited(tag("A"), take_until("\n"), char('\n'))),
61 |s: &str| MultiPartVal::A(s.to_string()),
62 )
63 .parse(i)
64}
65
66pub fn parse_mp_c(i: &str) -> IResult<&str, MultiPartVal> {
71 map((space0, tag("C")), |_| MultiPartVal::C).parse(i)
72}
73
74pub fn parse_mp_s(i: &str) -> IResult<&str, MultiPartVal> {
79 map(
80 preceded(
81 (space0::<&str, _>, tag("S")),
82 (
83 nom::character::complete::i128,
85 nom::combinator::opt(preceded(
86 space0,
87 delimited(char('"'), take_until("\""), char('"')),
88 )),
89 ),
90 ),
91 |(s, name)| MultiPartVal::S(s, name.map(std::string::ToString::to_string)),
92 )
93 .parse(i)
94}
95
96parse_mp_val!(parse_mp_p, "P", P);
97parse_mp_val!(parse_mp_t, "T", T);
101parse_mp_val!(parse_mp_u, "U", U);
102
103#[cfg(test)]
104mod test {
105 use super::*;
106
107 #[test]
108 fn multipart_value_equality() {
109 assert_eq!(
111 parse_mp_a("Aa.stl\n"),
112 Ok(("", MultiPartVal::A(String::from("a.stl"))))
113 );
114
115 assert_eq!(parse_mp_c("C"), Ok(("", MultiPartVal::C)));
117
118 assert_eq!(parse_mp_s("S-1"), Ok(("", MultiPartVal::S(-1, None))));
120 }
121}