|
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)) => { |