rust/hedgewars-engine-messages/src/parser.rs
changeset 16011 cf580d9ff7ef
parent 15831 c3971b38bbfa
equal deleted inserted replaced
16010:5ba4d3a0c3eb 16011:cf580d9ff7ef
       
     1 use std::str;
       
     2 
       
     3 use nom::branch::alt;
       
     4 use nom::bytes::streaming::*;
       
     5 use nom::combinator::*;
       
     6 use nom::error::{ErrorKind, ParseError};
       
     7 use nom::multi::*;
       
     8 use nom::number::streaming::*;
       
     9 use nom::sequence::{pair, preceded, terminated, tuple};
       
    10 use nom::{Err, IResult, Parser};
       
    11 
     1 use crate::messages::{
    12 use crate::messages::{
     2     ConfigEngineMessage::*, EngineMessage::*, KeystrokeAction::*, SyncedEngineMessage::*,
    13     ConfigEngineMessage::*, EngineMessage::*, KeystrokeAction::*, SyncedEngineMessage::*,
     3     UnorderedEngineMessage::*, *,
    14     UnorderedEngineMessage::*, *,
     4 };
    15 };
     5 use nom::{Err::Error, *};
    16 
     6 use std::str;
    17 fn eof_slice<I>(i: I) -> IResult<I, I>
     7 
    18 where
     8 macro_rules! eof_slice (
    19     I: nom::InputLength + Clone,
     9   ($i:expr,) => (
    20 {
    10     {
    21     if i.input_len() == 0 {
    11       if ($i).input_len() == 0 {
    22         Ok((i.clone(), i))
    12         Ok(($i, $i))
    23     } else {
    13       } else {
    24         Err(Err::Error(nom::error::Error::new(i, ErrorKind::Eof)))
    14         Err(Error(error_position!($i, ErrorKind::Eof::<u32>)))
    25     }
    15       }
    26 }
    16     }
    27 fn unrecognized_message(input: &[u8]) -> IResult<&[u8], EngineMessage> {
    17   );
    28     map(rest, |i: &[u8]| Unknown(i.to_owned()))(input)
    18 );
    29 }
    19 
    30 
    20 named!(unrecognized_message<&[u8], EngineMessage>,
    31 fn string_tail(input: &[u8]) -> IResult<&[u8], String> {
    21     do_parse!(rest >> (Unknown))
    32     map_res(rest, str::from_utf8)(input).map(|(i, s)| (i, s.to_owned()))
    22 );
    33 }
    23 
    34 
    24 named!(string_tail<&[u8], String>, map!(map_res!(rest, str::from_utf8), String::from));
    35 fn length_without_timestamp(input: &[u8]) -> IResult<&[u8], usize> {
    25 
    36     map_opt(rest_len, |l| if l > 2 { Some(l - 2) } else { None })(input)
    26 named!(length_without_timestamp<&[u8], usize>,
    37 }
    27     map_opt!(rest_len, |l| if l > 2 { Some(l - 2) } else { None } )
    38 
    28 );
    39 fn synced_message(input: &[u8]) -> IResult<&[u8], SyncedEngineMessage> {
    29 
    40     alt((
    30 named!(synced_message<&[u8], SyncedEngineMessage>, alt!(
    41         alt((
    31         do_parse!(tag!("L") >> (Left(Press)))
    42             map(tag(b"L"), |_| Left(Press)),
    32       | do_parse!(tag!("l") >> ( Left(Release) ))
    43             map(tag(b"l"), |_| Left(Release)),
    33       | do_parse!(tag!("R") >> ( Right(Press) ))
    44             map(tag(b"R"), |_| Right(Press)),
    34       | do_parse!(tag!("r") >> ( Right(Release) ))
    45             map(tag(b"r"), |_| Right(Release)),
    35       | do_parse!(tag!("U") >> ( Up(Press) ))
    46             map(tag(b"U"), |_| Up(Press)),
    36       | do_parse!(tag!("u") >> ( Up(Release) ))
    47             map(tag(b"u"), |_| Up(Release)),
    37       | do_parse!(tag!("D") >> ( Down(Press) ))
    48             map(tag(b"D"), |_| Down(Press)),
    38       | do_parse!(tag!("d") >> ( Down(Release) ))
    49             map(tag(b"d"), |_| Down(Release)),
    39       | do_parse!(tag!("Z") >> ( Precise(Press) ))
    50             map(tag(b"Z"), |_| Precise(Press)),
    40       | do_parse!(tag!("z") >> ( Precise(Release) ))
    51             map(tag(b"z"), |_| Precise(Release)),
    41       | do_parse!(tag!("A") >> ( Attack(Press) ))
    52             map(tag(b"A"), |_| Attack(Press)),
    42       | do_parse!(tag!("a") >> ( Attack(Release) ))
    53             map(tag(b"a"), |_| Attack(Release)),
    43       | do_parse!(tag!("N") >> ( NextTurn ))
    54             map(tag(b"N"), |_| NextTurn),
    44       | do_parse!(tag!("j") >> ( LongJump ))
    55             map(tag(b"j"), |_| LongJump),
    45       | do_parse!(tag!("J") >> ( HighJump ))
    56             map(tag(b"J"), |_| HighJump),
    46       | do_parse!(tag!("S") >> ( Switch ))
    57             map(tag(b"S"), |_| Switch),
    47       | do_parse!(tag!(",") >> ( Skip ))
    58         )),
    48       | do_parse!(tag!("1") >> ( Timer(1) ))
    59         alt((
    49       | do_parse!(tag!("2") >> ( Timer(2) ))
    60             map(tag(b","), |_| Skip),
    50       | do_parse!(tag!("3") >> ( Timer(3) ))
    61             map(tag(b"1"), |_| Timer(1)),
    51       | do_parse!(tag!("4") >> ( Timer(4) ))
    62             map(tag(b"2"), |_| Timer(2)),
    52       | do_parse!(tag!("5") >> ( Timer(5) ))
    63             map(tag(b"3"), |_| Timer(3)),
    53       | do_parse!(tag!("p") >> x: be_i24 >> y: be_i24 >> ( Put(x, y) ))
    64             map(tag(b"4"), |_| Timer(4)),
    54       | do_parse!(tag!("P") >> x: be_i24 >> y: be_i24 >> ( CursorMove(x, y) ))
    65             map(tag(b"5"), |_| Timer(5)),
    55       | do_parse!(tag!("f") >> s: string_tail >> ( SyncedEngineMessage::TeamControlLost(s) ))
    66             map(tuple((tag(b"p"), be_i24, be_i24)), |(_, x, y)| Put(x, y)),
    56       | do_parse!(tag!("g") >> s: string_tail >> ( SyncedEngineMessage::TeamControlGained(s) ))
    67             map(tuple((tag(b"P"), be_i24, be_i24)), |(_, x, y)| {
    57       | do_parse!(tag!("t") >> t: be_u8 >> ( Taunt(t) ))
    68                 CursorMove(x, y)
    58       | do_parse!(tag!("w") >> w: be_u8 >> ( SetWeapon(w) ))
    69             }),
    59       | do_parse!(tag!("~") >> s: be_u8 >> ( Slot(s) ))
    70             map(preceded(tag(b"f"), string_tail), TeamControlLost),
    60       | do_parse!(tag!("+") >> ( Heartbeat ))
    71             map(preceded(tag(b"g"), string_tail), TeamControlGained),
    61 ));
    72             map(preceded(tag(b"t"), be_u8), Taunt),
    62 
    73             map(preceded(tag(b"w"), be_u8), SetWeapon),
    63 named!(unsynced_message<&[u8], UnsyncedEngineMessage>, alt!(
    74             map(preceded(tag(b"~"), be_u8), Slot),
    64         do_parse!(tag!("F") >> s: string_tail >> ( UnsyncedEngineMessage::TeamControlLost(s) ))
    75             map(tag(b"+"), |_| Heartbeat),
    65       | do_parse!(tag!("G") >> s: string_tail >> ( UnsyncedEngineMessage::TeamControlGained(s) ))
    76         )),
    66       | do_parse!(tag!("h") >> s: string_tail >> ( UnsyncedEngineMessage::HogSay(s) ))
    77     ))(input)
    67       | do_parse!(tag!("s") >> s: string_tail >> ( UnsyncedEngineMessage::ChatMessage(s)) )
    78 }
    68       | do_parse!(tag!("b") >> s: string_tail >> ( UnsyncedEngineMessage::TeamMessage(s)) ) // TODO: wtf is the format
    79 
    69 ));
    80 fn unsynced_message(input: &[u8]) -> IResult<&[u8], UnsyncedEngineMessage> {
    70 
    81     alt((
    71 named!(unordered_message<&[u8], UnorderedEngineMessage>, alt!(
    82         map(
    72       do_parse!(tag!("?") >> ( Ping ))
    83             preceded(tag(b"F"), string_tail),
    73     | do_parse!(tag!("!") >> ( Pong ))
    84             UnsyncedEngineMessage::TeamControlLost,
    74     | do_parse!(tag!("E") >> s: string_tail >> ( UnorderedEngineMessage::Error(s)) )
    85         ),
    75     | do_parse!(tag!("W") >> s: string_tail >> ( Warning(s)) )
    86         map(
    76     | do_parse!(tag!("M") >> s: string_tail >> ( GameSetupChecksum(s)) )
    87             preceded(tag(b"G"), string_tail),
    77     | do_parse!(tag!("o") >> ( StopSyncing ))
    88             UnsyncedEngineMessage::TeamControlGained,
    78     | do_parse!(tag!("I") >> ( PauseToggled ))
    89         ),
    79 ));
    90         map(
    80 
    91             preceded(tag(b"h"), string_tail),
    81 named!(config_message<&[u8], ConfigEngineMessage>, alt!(
    92             UnsyncedEngineMessage::HogSay,
    82     do_parse!(tag!("C") >> (ConfigRequest))
    93         ),
    83     | do_parse!(tag!("eseed ") >> s: string_tail >> ( SetSeed(s)) )
    94         map(
    84     | do_parse!(tag!("e$feature_size ") >> s: string_tail >> ( SetFeatureSize(s.parse::<u8>().unwrap())) )
    95             preceded(tag(b"s"), string_tail),
    85 ));
    96             UnsyncedEngineMessage::ChatMessage,
    86 
    97         ),
    87 named!(timestamped_message<&[u8], (SyncedEngineMessage, u16)>,
    98         map(
    88     do_parse!(msg: length_value!(length_without_timestamp, terminated!(synced_message, eof_slice!()))
    99             preceded(tag(b"b"), string_tail),
    89         >> timestamp: be_u16
   100             UnsyncedEngineMessage::TeamMessage,
    90         >> ((msg, timestamp))
   101         ),
    91     )
   102     ))(input)
    92 );
   103 }
    93 
   104 
    94 named!(unwrapped_message<&[u8], EngineMessage>,
   105 fn unordered_message(input: &[u8]) -> IResult<&[u8], UnorderedEngineMessage> {
    95     alt!(
   106     alt((
    96         map!(timestamped_message, |(m, t)| Synced(m, t as u32))
   107         map(tag(b"?"), |_| Ping),
    97         | do_parse!(tag!("#") >> (Synced(TimeWrap, 65535)))
   108         map(tag(b"!"), |_| Pong),
    98         | map!(unordered_message, |m| Unordered(m))
   109         map(preceded(tag(b"E"), string_tail), Error),
    99         | map!(unsynced_message, |m| Unsynced(m))
   110         map(preceded(tag(b"W"), string_tail), Warning),
   100         | map!(config_message, |m| Config(m))
   111         map(preceded(tag(b"M"), string_tail), GameSetupChecksum),
   101         | unrecognized_message
   112         map(tag(b"o"), |_| StopSyncing),
   102 ));
   113         map(tag(b"I"), |_| PauseToggled),
   103 
   114     ))(input)
   104 named!(length_specifier<&[u8], u16>, alt!(
   115 }
   105     verify!(map!(take!(1), |a : &[u8]| a[0] as u16), |l| l < 64)
   116 
   106     | map!(take!(2), |a| (a[0] as u16 - 64) * 256 + a[1] as u16 + 64)
   117 fn config_message(input: &[u8]) -> IResult<&[u8], ConfigEngineMessage> {
   107     )
   118     alt((
   108 );
   119         map(tag(b"C"), |_| ConfigRequest),
   109 
   120         map(preceded(tag(b"eseed "), string_tail), SetSeed),
   110 named!(empty_message<&[u8], EngineMessage>,
   121         map(preceded(tag(b"e$feature_size "), string_tail), |s| {
   111     do_parse!(tag!("\0") >> (Empty))
   122             SetFeatureSize(s.parse().unwrap_or_default())
   112 );
   123         }),
   113 
   124     ))(input)
   114 named!(non_empty_message<&[u8], EngineMessage>,
   125 }
   115     length_value!(length_specifier, terminated!(unwrapped_message, eof_slice!())));
   126 
   116 
   127 fn timestamped_message(input: &[u8]) -> IResult<&[u8], (SyncedEngineMessage, u16)> {
   117 named!(message<&[u8], EngineMessage>, alt!(
   128     terminated(pair(synced_message, be_u16), eof_slice)(input)
   118       empty_message
   129 }
   119     | non_empty_message
   130 fn unwrapped_message(input: &[u8]) -> IResult<&[u8], EngineMessage> {
   120     )
   131     alt((
   121 );
   132         map(timestamped_message, |(m, t)| {
   122 
   133             EngineMessage::Synced(m, t as u32)
   123 named!(pub extract_messages<&[u8], Vec<EngineMessage> >, many0!(complete!(message)));
   134         }),
       
   135         map(tag(b"#"), |_| Synced(TimeWrap, 65535u32)),
       
   136         map(unordered_message, Unordered),
       
   137         map(unsynced_message, Unsynced),
       
   138         map(config_message, Config),
       
   139         unrecognized_message,
       
   140     ))(input)
       
   141 }
       
   142 
       
   143 fn length_specifier(input: &[u8]) -> IResult<&[u8], u16> {
       
   144     alt((
       
   145         verify(map(take(1usize), |a: &[u8]| a[0] as u16), |&l| l < 64),
       
   146         map(take(2usize), |a: &[u8]| {
       
   147             (a[0] as u16 - 64) * 256 + a[1] as u16 + 64
       
   148         }),
       
   149     ))(input)
       
   150 }
       
   151 
       
   152 fn empty_message(input: &[u8]) -> IResult<&[u8], EngineMessage> {
       
   153     map(tag(b"\0"), |_| Empty)(input)
       
   154 }
       
   155 
       
   156 fn non_empty_message(input: &[u8]) -> IResult<&[u8], EngineMessage> {
       
   157     map_parser(length_data(length_specifier), unwrapped_message)(input)
       
   158 }
       
   159 
       
   160 fn message(input: &[u8]) -> IResult<&[u8], EngineMessage> {
       
   161     alt((empty_message, non_empty_message))(input)
       
   162 }
       
   163 
       
   164 pub fn extract_messages(input: &[u8]) -> IResult<&[u8], Vec<EngineMessage>> {
       
   165     many0(complete(message))(input)
       
   166 }
   124 
   167 
   125 pub fn extract_message(buf: &[u8]) -> Option<(usize, EngineMessage)> {
   168 pub fn extract_message(buf: &[u8]) -> Option<(usize, EngineMessage)> {
   126     let parse_result = message(buf);
   169     let parse_result = message(buf);
   127     match parse_result {
   170     match parse_result {
   128         Ok((tail, msg)) => {
   171         Ok((tail, msg)) => {
   176     }
   219     }
   177 
   220 
   178     #[test]
   221     #[test]
   179     fn parse_incorrect_messages() {
   222     fn parse_incorrect_messages() {
   180         assert_eq!(message(b"\x00"), Ok((&b""[..], Empty)));
   223         assert_eq!(message(b"\x00"), Ok((&b""[..], Empty)));
   181         assert_eq!(message(b"\x01\x00"), Ok((&b""[..], Unknown)));
   224         assert_eq!(message(b"\x01\x00"), Ok((&b""[..], Unknown(vec![0]))));
   182 
   225 
   183         // garbage after correct message
   226         // garbage after correct message
   184         assert_eq!(message(b"\x04La\x01\x02"), Ok((&b""[..], Unknown)));
   227         assert_eq!(
       
   228             message(b"\x04La\x01\x02"),
       
   229             Ok((&b""[..], Unknown(vec![76, 97, 1, 2])))
       
   230         );
   185     }
   231     }
   186 
   232 
   187     #[test]
   233     #[test]
   188     fn parse_config_messages() {
   234     fn parse_config_messages() {
   189         assert_eq!(message(b"\x01C"), Ok((&b""[..], Config(ConfigRequest))));
   235         assert_eq!(message(b"\x01C"), Ok((&b""[..], Config(ConfigRequest))));
   192     #[test]
   238     #[test]
   193     fn parse_test_general() {
   239     fn parse_test_general() {
   194         assert_eq!(string_tail(b"abc"), Ok((&b""[..], String::from("abc"))));
   240         assert_eq!(string_tail(b"abc"), Ok((&b""[..], String::from("abc"))));
   195 
   241 
   196         assert_eq!(extract_message(b"\x02#"), None);
   242         assert_eq!(extract_message(b"\x02#"), None);
       
   243 
       
   244         assert_eq!(synced_message(b"L"), Ok((&b""[..], Left(Press))));
       
   245 
   197         assert_eq!(
   246         assert_eq!(
   198             extract_message(b"\x01#"),
   247             extract_message(b"\x01#"),
   199             Some((2, Synced(TimeWrap, 65535)))
   248             Some((2, Synced(TimeWrap, 65535)))
   200         );
   249         );
   201     }
   250     }