1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#[warn(clippy::pedantic)]
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Header {
    pub info: Vec<Elem>,
    pub players: Option<(PlayerAndPoint, PlayerAndPoint)>,
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct PlayerAndPoint {
    pub player_name: String,
    pub point: i64,
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub enum Elem {
    Value(String),
    KeyedValue(String, String),
}

use nom::combinator::opt;
use nom::error::{Error, ErrorKind};
use nom::multi::many0;
use nom::multi::many_m_n;
use nom::Err;
use nom::IResult;

fn elem_parser(s: &str) -> IResult<&str, Elem> {
    let (no_used, in_string) = super::parse_braced_string(s, '{', '}')?;
    Ok((no_used, {
        let mut splitter = in_string.splitn(2, ':');
        let first = splitter.next().unwrap();
        let second = splitter.next();
        match (first, second) {
            ("", Some(val)) | (val, None) => Elem::Value(val.to_owned()),
            (key, Some(value)) => Elem::KeyedValue(key.to_owned(), value.to_owned()),
        }
    }))
}

use super::skip_spaces_and_newlines;

fn player_and_point_parser(s: &str) -> IResult<&str, (String, Option<i64>)> {
    let (no_used, player_name) = super::parse_braced_string(s, '[', ']')?;
    let (no_used, _) = skip_spaces_and_newlines(no_used)?;
    let (no_used, opt_num) = opt(super::parse_numeral)(no_used)?;
    let (no_used, _) = skip_spaces_and_newlines(no_used)?;
    Ok((no_used, (player_name.to_owned(), opt_num)))
}

pub fn parse(input: &str) -> IResult<&str, Header> {
    let (no_used, _) = skip_spaces_and_newlines(input)?;
    let (no_used, info) = many0(elem_parser)(no_used)?;
    let (no_used, vec2) = many_m_n(0, 2, player_and_point_parser)(no_used)?;
    let players = match vec2.as_slice() {
        [] => None,
        [q, r] => {
            let (n1, p1) = q.clone();
            let (n2, p2) = r.clone();
            let (p1, p2) = match (p1, p2) {
                (Some(b), Some(d)) => (b, d),
                (Some(b), None) => (b, 40 - b),
                (None, Some(d)) => (40 - d, d),
                (None, None) => (20, 20),
            };

            Some((
                PlayerAndPoint {
                    player_name: n1,
                    point: p1,
                },
                PlayerAndPoint {
                    player_name: n2,
                    point: p2,
                },
            ))
        }
        _ => return Err(Err::Error(Error::new(no_used, ErrorKind::Verify))), /* only one player found */
    };

    Ok((no_used, Header { info, players }))
}

#[cfg(test)]
mod tests_;