use nom::{
bytes::complete::tag,
character::complete::{digit1, line_ending, space0},
combinator::opt,
IResult,
};
use std::str;
use crate::Side;
use crate::ParseError;
use crate::util::into_parse_error;
#[derive(Debug)]
pub struct Options {
pub first_line_number: usize,
pub starting_side: Side,
pub in_round: bool,
}
impl Default for Options {
fn default() -> Self {
let first_line_number = 1;
let starting_side = Side::RS;
let in_round = false;
Options {
first_line_number,
starting_side,
in_round,
}
}
}
impl Options {
fn parse_in_round<'a>(&mut self, line: &'a str) -> IResult<&'a str, ()> {
let (line, in_round) = opt(tag("in_round"))(line)?;
match in_round {
Some(_) => {
if !line.is_empty() {
line_ending(line)?;
}
self.in_round = true;
Ok((line, ()))
},
None => {
Ok((line, ()))
}
}
}
fn parse_start_wrong<'a>(&mut self, line: &'a str) -> IResult<&'a str, ()> {
let (line, start_wrong) = opt(tag("start_wrong_side"))(line)?;
match start_wrong {
Some(_) => {
if !line.is_empty() {
line_ending(line)?;
}
self.starting_side = Side::WS;
Ok((line, ()))
},
None => {
Ok((line, ()))
}
}
}
fn parse_first_line<'a>(&mut self, line: &'a str) -> IResult<&'a str, ()> {
let (line, first_line) = opt(tag("first_line="))(line)?;
match first_line {
Some(_) => {
let (line, first_line_number) = digit1(line)?;
if !line.is_empty() {
line_ending(line)?;
}
self.first_line_number = first_line_number.parse::<usize>().unwrap();
Ok((line, ()))
}
None => {
Ok((line, ()))
}
}
}
fn internal_parse<'a>(&mut self, line: &'a str) -> IResult<&'a str, ()> {
let (line, _) = space0(line)?;
let (line, _) = self.parse_in_round(line)?;
let (line, _) = self.parse_first_line(line)?;
let (line, _) = self.parse_start_wrong(line)?;
if !line.is_empty() {
line_ending(line)?;
}
Ok((line, ()))
}
pub fn parse_options(&mut self, line: &str, line_number: usize) -> Result<(), ParseError> {
let starting_line = line;
let line = &line[2..];
match self.internal_parse(line) {
Ok(_) => {
Ok(())
}
Err(_) => {
Err(into_parse_error(starting_line, line, line_number))
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn in_round() {
let mut options = Options::default();
options.parse_options("## in_round", 0).unwrap();
assert!(options.in_round);
}
#[test]
fn line_number() {
let mut options = Options::default();
options.parse_options("## first_line=3", 0).unwrap();
assert_eq!(options.first_line_number, 3);
}
#[test]
fn start_wrong() {
let mut options = Options::default();
options.parse_options("## start_wrong_side", 0).unwrap();
assert_eq!(options.starting_side, Side::WS);
}
}