use core::hash::Hash;
use nom::IResult;
use nom::Parser;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_until;
use nom::character::complete::char;
use nom::character::complete::space0;
use nom::combinator::complete;
use nom::combinator::map;
use nom::sequence::delimited;
use nom::sequence::preceded;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum MultiPartVal {
A(String),
C,
P(i128),
S(i128, Option<String>),
T(i128),
U(i128),
}
macro_rules! parse_mp_val {
($name:ident, $tag:literal, $variant:ident) => {
#[doc = "Extracts multipart"]
#[doc = stringify!($tag)]
#[doc = " parameter"]
#[doc = ""]
#[doc = "# Errors"]
#[doc = " When match fails."]
pub fn $name(i: &str) -> IResult<&str, MultiPartVal> {
map(
preceded((space0, tag($tag)), nom::character::complete::i128),
MultiPartVal::$variant,
)
.parse(i)
}
};
}
pub fn parse_mp_a(i: &str) -> IResult<&str, MultiPartVal> {
map(
complete(delimited(tag("A"), take_until("\n"), char('\n'))),
|s: &str| MultiPartVal::A(s.to_string()),
)
.parse(i)
}
pub fn parse_mp_c(i: &str) -> IResult<&str, MultiPartVal> {
map((space0, tag("C")), |_| MultiPartVal::C).parse(i)
}
pub fn parse_mp_s(i: &str) -> IResult<&str, MultiPartVal> {
map(
preceded(
(space0::<&str, _>, tag("S")),
(
nom::character::complete::i128,
nom::combinator::opt(preceded(
space0,
delimited(char('"'), take_until("\""), char('"')),
)),
),
),
|(s, name)| MultiPartVal::S(s, name.map(std::string::ToString::to_string)),
)
.parse(i)
}
parse_mp_val!(parse_mp_p, "P", P);
parse_mp_val!(parse_mp_t, "T", T);
parse_mp_val!(parse_mp_u, "U", U);
#[cfg(test)]
mod test {
use super::*;
#[test]
fn multipart_value_equality() {
assert_eq!(
parse_mp_a("Aa.stl\n"),
Ok(("", MultiPartVal::A(String::from("a.stl"))))
);
assert_eq!(parse_mp_c("C"), Ok(("", MultiPartVal::C)));
assert_eq!(parse_mp_s("S-1"), Ok(("", MultiPartVal::S(-1, None))));
}
}