use nom::{
branch::alt,
bytes::complete::{is_not, tag},
character::complete::char,
combinator::{map, opt},
error::ErrorKind,
sequence::delimited,
sequence::preceded,
Err,
IResult,
};
use crate::{Modifier, State};
const QUOTE_CHAR: char = '"';
const QUOTE_STR: &str = "\"";
fn parse_comment(i: &str) -> IResult<&str, &str> {
delimited(
char(QUOTE_CHAR),
alt((is_not(QUOTE_STR), tag(""))),
char(QUOTE_CHAR),
)(i)
}
#[test]
fn parse_comment_test_empty() {
assert_eq!(parse_comment("\"\""), Ok(("", "")));
}
#[test]
fn parse_comment_test_good() {
assert_eq!(parse_comment("\"this is good\""), Ok(("", "this is good")));
}
#[test]
fn parse_comment_test_non_comment() {
assert_eq!(
parse_comment("foo"),
Err(Err::Error(("foo", ErrorKind::Char)))
);
}
#[test]
fn parse_comment_test_with_quote() {
assert_eq!(
parse_comment("\"this \" isn't good\""),
Ok((" isn't good\"", "this "))
);
}
fn parse_state(i: &str) -> IResult<&str, State> {
map(
alt((tag("open"), tag("closed"), tag("off"), tag("unknown"))),
|s: &str| match s {
"open" => State::Open,
"closed" => State::Closed,
"off" => State::Closed,
"unknown" => State::Unknown,
_ => State::Unknown, },
)(i)
}
#[test]
fn parse_state_test() {
assert_eq!(parse_state("open"), Ok(("", State::Open)));
assert_eq!(parse_state("closed"), Ok(("", State::Closed)));
assert_eq!(parse_state("off"), Ok(("", State::Closed)));
assert_eq!(parse_state("unknown"), Ok(("", State::Unknown)));
assert_eq!(parse_state(""), Err(Err::Error(("", ErrorKind::Tag))));
}
fn parse_modifier(i: &str) -> IResult<&str, Modifier> {
let (i, state_opt) = opt(parse_state)(i)?;
let (i, _) = opt(tag(" "))(i)?;
let (i, c_opt) = opt(parse_comment)(i)?;
Ok((
i,
Modifier {
state: state_opt.unwrap_or(State::Open),
comment: c_opt.unwrap_or("").to_owned(),
},
))
}
#[test]
fn parse_modifier_test_open_no_comment() {
assert_eq!(
parse_modifier("open"),
Ok((
"",
Modifier {
state: State::Open,
comment: "".to_owned(),
}
))
);
}
#[test]
fn parse_modifier_test_open_comment() {
assert_eq!(
parse_modifier("open \"hi\""),
Ok((
"",
Modifier {
state: State::Open,
comment: "hi".to_owned(),
}
))
);
}
#[test]
fn parse_modifier_test_only_comment() {
assert_eq!(
parse_modifier("\"comment\""),
Ok((
"",
Modifier {
state: State::Open,
comment: "comment".to_owned(),
}
))
);
}