1 use nom::*; |
1 use nom::{*}; |
2 use std::str; |
2 use std::str; |
3 |
3 |
4 use super::messages::{*, EngineMessage::*, UnsyncedEngineMessage::*, SyncedEngineMessage::*, ConfigEngineMessage::*, KeystrokeAction::*}; |
4 use super::messages::{*, EngineMessage::*, UnsyncedEngineMessage::*, SyncedEngineMessage::*, ConfigEngineMessage::*, KeystrokeAction::*}; |
5 |
5 |
6 named!(length_specifier<&[u8], u16>, alt!( |
6 |
7 verify!(map!(take!(1), |a : &[u8]| a[0] as u16), |l| l < 64) |
|
8 | map!(take!(2), |a| (a[0] as u16 - 64) * 256 + a[1] as u16 + 64) |
|
9 ) |
|
10 ); |
|
11 |
7 |
12 named!(unrecognized_message<&[u8], EngineMessage>, |
8 named!(unrecognized_message<&[u8], EngineMessage>, |
13 do_parse!(rest >> (Unknown)) |
9 do_parse!(rest >> (Unknown)) |
14 ); |
10 ); |
15 |
11 |
16 named!(string_tail<&[u8], String>, map!(map_res!(rest, str::from_utf8), String::from)); |
12 named!(string_tail<&[u8], String>, map!(map_res!(rest, str::from_utf8), String::from)); |
17 |
13 |
|
14 named!(length_without_timestamp<&[u8], usize>, |
|
15 map_opt!(rest_len, |l| if l > 2 { Some(l - 2) } else { None } ) |
|
16 ); |
|
17 |
18 named!(synced_message<&[u8], SyncedEngineMessage>, alt!( |
18 named!(synced_message<&[u8], SyncedEngineMessage>, alt!( |
19 do_parse!(tag!("+l") >> (Left(Press))) |
19 do_parse!(tag!("L") >> (Left(Press))) |
20 )); |
20 )); |
|
21 |
|
22 named!(timestamped_message<&[u8], (SyncedEngineMessage, u16)>, |
|
23 do_parse!(msg: length_value!(length_without_timestamp, synced_message) |
|
24 >> timestamp: be_u16 |
|
25 >> ((msg, timestamp)) |
|
26 ) |
|
27 ); |
21 |
28 |
22 named!(unsynced_message<&[u8], UnsyncedEngineMessage>, alt!( |
29 named!(unsynced_message<&[u8], UnsyncedEngineMessage>, alt!( |
23 do_parse!(tag!("?") >> (Ping)) |
30 do_parse!(tag!("?") >> (Ping)) |
24 | do_parse!(tag!("!") >> (Ping)) |
31 | do_parse!(tag!("!") >> (Ping)) |
25 | do_parse!(tag!("esay ") >> s: string_tail >> (Say(s))) |
32 | do_parse!(tag!("esay ") >> s: string_tail >> (Say(s))) |
27 |
34 |
28 named!(config_message<&[u8], ConfigEngineMessage>, alt!( |
35 named!(config_message<&[u8], ConfigEngineMessage>, alt!( |
29 do_parse!(tag!("C") >> (ConfigRequest)) |
36 do_parse!(tag!("C") >> (ConfigRequest)) |
30 )); |
37 )); |
31 |
38 |
|
39 named!(unwrapped_message<&[u8], EngineMessage>, |
|
40 alt!( |
|
41 map!(timestamped_message, |(m, t)| Synced(m, t as u32)) |
|
42 | do_parse!(tag!("#") >> (Synced(TimeWrap, 65535))) |
|
43 | map!(unsynced_message, |m| Unsynced(m)) |
|
44 | map!(config_message, |m| Config(m)) |
|
45 | unrecognized_message |
|
46 )); |
|
47 |
|
48 |
|
49 |
|
50 named!(length_specifier<&[u8], u16>, alt!( |
|
51 verify!(map!(take!(1), |a : &[u8]| a[0] as u16), |l| l < 64) |
|
52 | map!(take!(2), |a| (a[0] as u16 - 64) * 256 + a[1] as u16 + 64) |
|
53 ) |
|
54 ); |
|
55 |
32 named!(empty_message<&[u8], EngineMessage>, |
56 named!(empty_message<&[u8], EngineMessage>, |
33 do_parse!(tag!("\0") >> (Empty)) |
57 do_parse!(tag!("\0") >> (Empty)) |
34 ); |
58 ); |
35 |
59 |
36 named!(non_empty_message<&[u8], EngineMessage>, length_value!(length_specifier, |
60 named!(non_empty_message<&[u8], EngineMessage>, |
37 alt!( |
61 length_value!(length_specifier, unwrapped_message)); |
38 map!(synced_message, |m| Synced(m, 0)) |
|
39 | map!(unsynced_message, |m| Unsynced(m)) |
|
40 | map!(config_message, |m| Config(m)) |
|
41 | unrecognized_message |
|
42 ) |
|
43 )); |
|
44 |
62 |
45 named!(message<&[u8], EngineMessage>, alt!( |
63 named!(message<&[u8], EngineMessage>, alt!( |
46 empty_message |
64 empty_message |
47 | non_empty_message |
65 | non_empty_message |
48 ) |
66 ) |
59 assert_eq!(length_specifier(b"\xff\xff"), Ok((&b""[..], 49215))); |
77 assert_eq!(length_specifier(b"\xff\xff"), Ok((&b""[..], 49215))); |
60 } |
78 } |
61 |
79 |
62 #[test] |
80 #[test] |
63 fn parse_synced_messages() { |
81 fn parse_synced_messages() { |
64 assert_eq!(message(b"\x04+l\x01\x01"), Ok((&b""[..], Synced(Left(Press), 0)))); |
82 assert_eq!(message(b"\x03L\x01\x02"), Ok((&b""[..], Synced(Left(Press), 258)))); |
65 } |
83 } |
66 |
84 |
67 #[test] |
85 #[test] |
68 fn parse_unsynced_messages() { |
86 fn parse_unsynced_messages() { |
69 assert_eq!(message(b"\x0aesay hello"), Ok((&b""[..], Unsynced(Say(String::from("hello")))))); |
87 assert_eq!(message(b"\x0aesay hello"), Ok((&b""[..], Unsynced(Say(String::from("hello")))))); |