rust/hedgewars-server/src/protocol/parser.rs
changeset 15075 e935b1ad23f3
parent 15074 c5a6e8566425
child 15111 1e45db229f9f
equal deleted inserted replaced
15074:c5a6e8566425 15075:e935b1ad23f3
    12     ops::Range,
    12     ops::Range,
    13     str,
    13     str,
    14     str::{FromStr, Utf8Error},
    14     str::{FromStr, Utf8Error},
    15 };
    15 };
    16 
    16 
    17 use super::{
    17 use super::messages::{HwProtocolMessage, HwProtocolMessage::*};
    18     messages::{HWProtocolMessage, HWProtocolMessage::*},
       
    19 };
       
    20 use crate::core::types::{
    18 use crate::core::types::{
    21     GameCfg, HedgehogInfo, ServerVar, TeamInfo, VoteType, MAX_HEDGEHOGS_PER_TEAM,
    19     GameCfg, HedgehogInfo, ServerVar, TeamInfo, VoteType, MAX_HEDGEHOGS_PER_TEAM,
    22 };
    20 };
    23 
    21 
    24 #[derive(Debug, PartialEq)]
    22 #[derive(Debug, PartialEq)]
    25 pub struct HWProtocolError {}
    23 pub struct HwProtocolError {}
    26 
    24 
    27 impl HWProtocolError {
    25 impl HwProtocolError {
    28     fn new() -> Self {
    26     fn new() -> Self {
    29         HWProtocolError {}
    27         HwProtocolError {}
    30     }
    28     }
    31 }
    29 }
    32 
    30 
    33 impl<I> ParseError<I> for HWProtocolError {
    31 impl<I> ParseError<I> for HwProtocolError {
    34     fn from_error_kind(input: I, kind: ErrorKind) -> Self {
    32     fn from_error_kind(input: I, kind: ErrorKind) -> Self {
    35         HWProtocolError::new()
    33         HwProtocolError::new()
    36     }
    34     }
    37 
    35 
    38     fn append(input: I, kind: ErrorKind, other: Self) -> Self {
    36     fn append(input: I, kind: ErrorKind, other: Self) -> Self {
    39         HWProtocolError::new()
    37         HwProtocolError::new()
    40     }
    38     }
    41 }
    39 }
    42 
    40 
    43 impl From<Utf8Error> for HWProtocolError {
    41 impl From<Utf8Error> for HwProtocolError {
    44     fn from(_: Utf8Error) -> Self {
    42     fn from(_: Utf8Error) -> Self {
    45         HWProtocolError::new()
    43         HwProtocolError::new()
    46     }
    44     }
    47 }
    45 }
    48 
    46 
    49 impl From<ParseIntError> for HWProtocolError {
    47 impl From<ParseIntError> for HwProtocolError {
    50     fn from(_: ParseIntError) -> Self {
    48     fn from(_: ParseIntError) -> Self {
    51         HWProtocolError::new()
    49         HwProtocolError::new()
    52     }
    50     }
    53 }
    51 }
    54 
    52 
    55 pub type HWResult<'a, O> = IResult<&'a [u8], O, HWProtocolError>;
    53 pub type HwResult<'a, O> = IResult<&'a [u8], O, HwProtocolError>;
    56 
    54 
    57 fn end_of_message(input: &[u8]) -> HWResult<&[u8]> {
    55 fn end_of_message(input: &[u8]) -> HwResult<&[u8]> {
    58     tag("\n\n")(input)
    56     tag("\n\n")(input)
    59 }
    57 }
    60 
    58 
    61 fn convert_utf8(input: &[u8]) -> HWResult<&str> {
    59 fn convert_utf8(input: &[u8]) -> HwResult<&str> {
    62     match str::from_utf8(input) {
    60     match str::from_utf8(input) {
    63         Ok(str) => Ok((b"", str)),
    61         Ok(str) => Ok((b"", str)),
    64         Err(utf_err) => Result::Err(Err::Failure(utf_err.into())),
    62         Err(utf_err) => Result::Err(Err::Failure(utf_err.into())),
    65     }
    63     }
    66 }
    64 }
    67 
    65 
    68 fn convert_from_str<T>(str: &str) -> HWResult<T>
    66 fn convert_from_str<T>(str: &str) -> HwResult<T>
    69 where
    67 where
    70     T: FromStr<Err = ParseIntError>,
    68     T: FromStr<Err = ParseIntError>,
    71 {
    69 {
    72     match T::from_str(str) {
    70     match T::from_str(str) {
    73         Ok(x) => Ok((b"", x)),
    71         Ok(x) => Ok((b"", x)),
    74         Err(format_err) => Result::Err(Err::Failure(format_err.into())),
    72         Err(format_err) => Result::Err(Err::Failure(format_err.into())),
    75     }
    73     }
    76 }
    74 }
    77 
    75 
    78 fn str_line(input: &[u8]) -> HWResult<&str> {
    76 fn str_line(input: &[u8]) -> HwResult<&str> {
    79     let (i, text) = not_line_ending(input)?;
    77     let (i, text) = not_line_ending(input)?;
    80     Ok((i, convert_utf8(text)?.1))
    78     Ok((i, convert_utf8(text)?.1))
    81 }
    79 }
    82 
    80 
    83 fn a_line(input: &[u8]) -> HWResult<String> {
    81 fn a_line(input: &[u8]) -> HwResult<String> {
    84     let (i, str) = str_line(input)?;
    82     let (i, str) = str_line(input)?;
    85     Ok((i, str.to_string()))
    83     Ok((i, str.to_string()))
    86 }
    84 }
    87 
    85 
    88 fn hw_tag<'a>(tag_str: &'a str) -> impl Fn(&'a [u8]) -> HWResult<'a, ()> {
    86 fn hw_tag<'a>(tag_str: &'a str) -> impl Fn(&'a [u8]) -> HwResult<'a, ()> {
    89     move |i| tag(tag_str)(i).map(|(i, _)| (i, ()))
    87     move |i| tag(tag_str)(i).map(|(i, _)| (i, ()))
    90 }
    88 }
    91 
    89 
    92 fn hw_tag_no_case<'a>(tag_str: &'a str) -> impl Fn(&'a [u8]) -> HWResult<'a, ()> {
    90 fn hw_tag_no_case<'a>(tag_str: &'a str) -> impl Fn(&'a [u8]) -> HwResult<'a, ()> {
    93     move |i| tag_no_case(tag_str)(i).map(|(i, _)| (i, ()))
    91     move |i| tag_no_case(tag_str)(i).map(|(i, _)| (i, ()))
    94 }
    92 }
    95 
    93 
    96 fn cmd_arg(input: &[u8]) -> HWResult<String> {
    94 fn cmd_arg(input: &[u8]) -> HwResult<String> {
    97     let delimiters = b" \n";
    95     let delimiters = b" \n";
    98     let (i, str) = take_while(move |c| !delimiters.contains(&c))(input)?;
    96     let (i, str) = take_while(move |c| !delimiters.contains(&c))(input)?;
    99     Ok((i, convert_utf8(str)?.1.to_string()))
    97     Ok((i, convert_utf8(str)?.1.to_string()))
   100 }
    98 }
   101 
    99 
   102 fn u8_line(input: &[u8]) -> HWResult<u8> {
   100 fn u8_line(input: &[u8]) -> HwResult<u8> {
   103     let (i, str) = str_line(input)?;
   101     let (i, str) = str_line(input)?;
   104     Ok((i, convert_from_str(str)?.1))
   102     Ok((i, convert_from_str(str)?.1))
   105 }
   103 }
   106 
   104 
   107 fn u16_line(input: &[u8]) -> HWResult<u16> {
   105 fn u16_line(input: &[u8]) -> HwResult<u16> {
   108     let (i, str) = str_line(input)?;
   106     let (i, str) = str_line(input)?;
   109     Ok((i, convert_from_str(str)?.1))
   107     Ok((i, convert_from_str(str)?.1))
   110 }
   108 }
   111 
   109 
   112 fn u32_line(input: &[u8]) -> HWResult<u32> {
   110 fn u32_line(input: &[u8]) -> HwResult<u32> {
   113     let (i, str) = str_line(input)?;
   111     let (i, str) = str_line(input)?;
   114     Ok((i, convert_from_str(str)?.1))
   112     Ok((i, convert_from_str(str)?.1))
   115 }
   113 }
   116 
   114 
   117 fn yes_no_line(input: &[u8]) -> HWResult<bool> {
   115 fn yes_no_line(input: &[u8]) -> HwResult<bool> {
   118     alt((
   116     alt((
   119         |i| tag_no_case(b"YES")(i).map(|(i, _)| (i, true)),
   117         |i| tag_no_case(b"YES")(i).map(|(i, _)| (i, true)),
   120         |i| tag_no_case(b"NO")(i).map(|(i, _)| (i, false)),
   118         |i| tag_no_case(b"NO")(i).map(|(i, _)| (i, false)),
   121     ))(input)
   119     ))(input)
   122 }
   120 }
   123 
   121 
   124 fn opt_arg<'a>(input: &'a [u8]) -> HWResult<'a, Option<String>> {
   122 fn opt_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> {
   125     alt((
   123     alt((
   126         |i: &'a [u8]| peek!(i, end_of_message).map(|(i, _)| (i, None)),
   124         |i: &'a [u8]| peek!(i, end_of_message).map(|(i, _)| (i, None)),
   127         |i| precededc(i, hw_tag("\n"), a_line).map(|(i, v)| (i, Some(v))),
   125         |i| precededc(i, hw_tag("\n"), a_line).map(|(i, v)| (i, Some(v))),
   128     ))(input)
   126     ))(input)
   129 }
   127 }
   130 
   128 
   131 fn spaces(input: &[u8]) -> HWResult<&[u8]> {
   129 fn spaces(input: &[u8]) -> HwResult<&[u8]> {
   132     precededc(input, hw_tag(" "), |i| take_while(|c| c == b' ')(i))
   130     precededc(input, hw_tag(" "), |i| take_while(|c| c == b' ')(i))
   133 }
   131 }
   134 
   132 
   135 fn opt_space_arg<'a>(input: &'a [u8]) -> HWResult<'a, Option<String>> {
   133 fn opt_space_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> {
   136     alt((
   134     alt((
   137         |i: &'a [u8]| peek!(i, end_of_message).map(|(i, _)| (i, None)),
   135         |i: &'a [u8]| peek!(i, end_of_message).map(|(i, _)| (i, None)),
   138         |i| precededc(i, spaces, a_line).map(|(i, v)| (i, Some(v))),
   136         |i| precededc(i, spaces, a_line).map(|(i, v)| (i, Some(v))),
   139     ))(input)
   137     ))(input)
   140 }
   138 }
   141 
   139 
   142 fn hedgehog_array(input: &[u8]) -> HWResult<[HedgehogInfo; 8]> {
   140 fn hedgehog_array(input: &[u8]) -> HwResult<[HedgehogInfo; 8]> {
   143     fn hedgehog_line(input: &[u8]) -> HWResult<HedgehogInfo> {
   141     fn hedgehog_line(input: &[u8]) -> HwResult<HedgehogInfo> {
   144         let (i, name) = terminatedc(input, a_line, eol)?;
   142         let (i, name) = terminatedc(input, a_line, eol)?;
   145         let (i, hat) = a_line(i)?;
   143         let (i, hat) = a_line(i)?;
   146         Ok((i, HedgehogInfo { name, hat }))
   144         Ok((i, HedgehogInfo { name, hat }))
   147     }
   145     }
   148 
   146 
   156     let (i, h8) = hedgehog_line(i)?;
   154     let (i, h8) = hedgehog_line(i)?;
   157 
   155 
   158     Ok((i, [h1, h2, h3, h4, h5, h6, h7, h8]))
   156     Ok((i, [h1, h2, h3, h4, h5, h6, h7, h8]))
   159 }
   157 }
   160 
   158 
   161 fn voting(input: &[u8]) -> HWResult<VoteType> {
   159 fn voting(input: &[u8]) -> HwResult<VoteType> {
   162     alt((
   160     alt((
   163         |i| tag_no_case("PAUSE")(i).map(|(i, _)| (i, VoteType::Pause)),
   161         |i| tag_no_case("PAUSE")(i).map(|(i, _)| (i, VoteType::Pause)),
   164         |i| tag_no_case("NEWSEED")(i).map(|(i, _)| (i, VoteType::NewSeed)),
   162         |i| tag_no_case("NEWSEED")(i).map(|(i, _)| (i, VoteType::NewSeed)),
   165         |i| {
   163         |i| {
   166             precededc(i, |i| precededc(i, hw_tag_no_case("KICK"), spaces), a_line)
   164             precededc(i, |i| precededc(i, hw_tag_no_case("KICK"), spaces), a_line)
   176         },
   174         },
   177         |i| precededc(i, hw_tag_no_case("MAP"), opt_space_arg).map(|(i, v)| (i, VoteType::Map(v))),
   175         |i| precededc(i, hw_tag_no_case("MAP"), opt_space_arg).map(|(i, v)| (i, VoteType::Map(v))),
   178     ))(input)
   176     ))(input)
   179 }
   177 }
   180 
   178 
   181 fn no_arg_message(input: &[u8]) -> HWResult<HWProtocolMessage> {
   179 fn no_arg_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   182     fn messagec<'a>(
   180     fn messagec<'a>(
   183         input: &'a [u8],
   181         input: &'a [u8],
   184         name: &'a str,
   182         name: &'a str,
   185         msg: HWProtocolMessage,
   183         msg: HwProtocolMessage,
   186     ) -> HWResult<'a, HWProtocolMessage> {
   184     ) -> HwResult<'a, HwProtocolMessage> {
   187         tag(name)(input).map(|(i, _)| (i, msg.clone()))
   185         tag(name)(input).map(|(i, _)| (i, msg.clone()))
   188     }
   186     }
   189 
   187 
   190     alt((
   188     alt((
   191         |i| messagec(i, "PING", Ping),
   189         |i| messagec(i, "PING", Ping),
   199         |i| messagec(i, "TOGGLE_RESTRICT_TEAMS", ToggleRestrictTeams),
   197         |i| messagec(i, "TOGGLE_RESTRICT_TEAMS", ToggleRestrictTeams),
   200         |i| messagec(i, "TOGGLE_REGISTERED_ONLY", ToggleRegisteredOnly),
   198         |i| messagec(i, "TOGGLE_REGISTERED_ONLY", ToggleRegisteredOnly),
   201     ))(input)
   199     ))(input)
   202 }
   200 }
   203 
   201 
   204 fn single_arg_message(input: &[u8]) -> HWResult<HWProtocolMessage> {
   202 fn single_arg_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   205     fn messagec<'a, T, F, G>(
   203     fn messagec<'a, T, F, G>(
   206         input: &'a [u8],
   204         input: &'a [u8],
   207         name: &'a str,
   205         name: &'a str,
   208         parser: F,
   206         parser: F,
   209         constructor: G,
   207         constructor: G,
   210     ) -> HWResult<'a, HWProtocolMessage>
   208     ) -> HwResult<'a, HwProtocolMessage>
   211     where
   209     where
   212         F: Fn(&[u8]) -> HWResult<T>,
   210         F: Fn(&[u8]) -> HwResult<T>,
   213         G: Fn(T) -> HWProtocolMessage,
   211         G: Fn(T) -> HwProtocolMessage,
   214     {
   212     {
   215         precededc(input, hw_tag(name), parser).map(|(i, v)| (i, constructor(v)))
   213         precededc(input, hw_tag(name), parser).map(|(i, v)| (i, constructor(v)))
   216     }
   214     }
   217 
   215 
   218     alt((
   216     alt((
   231         |i| messagec(i, "PROTO\n", u16_line, Proto),
   229         |i| messagec(i, "PROTO\n", u16_line, Proto),
   232         |i| messagec(i, "QUIT", opt_arg, Quit),
   230         |i| messagec(i, "QUIT", opt_arg, Quit),
   233     ))(input)
   231     ))(input)
   234 }
   232 }
   235 
   233 
   236 fn cmd_message<'a>(input: &'a [u8]) -> HWResult<'a, HWProtocolMessage> {
   234 fn cmd_message<'a>(input: &'a [u8]) -> HwResult<'a, HwProtocolMessage> {
   237     fn cmdc_no_arg<'a>(
   235     fn cmdc_no_arg<'a>(
   238         input: &'a [u8],
   236         input: &'a [u8],
   239         name: &'a str,
   237         name: &'a str,
   240         msg: HWProtocolMessage,
   238         msg: HwProtocolMessage,
   241     ) -> HWResult<'a, HWProtocolMessage> {
   239     ) -> HwResult<'a, HwProtocolMessage> {
   242         tag_no_case(name)(input).map(|(i, _)| (i, msg.clone()))
   240         tag_no_case(name)(input).map(|(i, _)| (i, msg.clone()))
   243     }
   241     }
   244 
   242 
   245     fn cmdc_single_arg<'a, T, F, G>(
   243     fn cmdc_single_arg<'a, T, F, G>(
   246         input: &'a [u8],
   244         input: &'a [u8],
   247         name: &'a str,
   245         name: &'a str,
   248         parser: F,
   246         parser: F,
   249         constructor: G,
   247         constructor: G,
   250     ) -> HWResult<'a, HWProtocolMessage>
   248     ) -> HwResult<'a, HwProtocolMessage>
   251     where
   249     where
   252         F: Fn(&'a [u8]) -> HWResult<'a, T>,
   250         F: Fn(&'a [u8]) -> HwResult<'a, T>,
   253         G: Fn(T) -> HWProtocolMessage,
   251         G: Fn(T) -> HwProtocolMessage,
   254     {
   252     {
   255         precededc(input, |i| pairc(i, hw_tag_no_case(name), spaces), parser)
   253         precededc(input, |i| pairc(i, hw_tag_no_case(name), spaces), parser)
   256             .map(|(i, v)| (i, constructor(v)))
   254             .map(|(i, v)| (i, constructor(v)))
   257     }
   255     }
   258 
   256 
   259     fn cmd_no_arg_message(input: &[u8]) -> HWResult<HWProtocolMessage> {
   257     fn cmd_no_arg_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   260         alt((
   258         alt((
   261             |i| cmdc_no_arg(i, "STATS", Stats),
   259             |i| cmdc_no_arg(i, "STATS", Stats),
   262             |i| cmdc_no_arg(i, "FIX", Fix),
   260             |i| cmdc_no_arg(i, "FIX", Fix),
   263             |i| cmdc_no_arg(i, "UNFIX", Unfix),
   261             |i| cmdc_no_arg(i, "UNFIX", Unfix),
   264             |i| cmdc_no_arg(i, "REGISTERED_ONLY", ToggleServerRegisteredOnly),
   262             |i| cmdc_no_arg(i, "REGISTERED_ONLY", ToggleServerRegisteredOnly),
   265             |i| cmdc_no_arg(i, "SUPER_POWER", SuperPower),
   263             |i| cmdc_no_arg(i, "SUPER_POWER", SuperPower),
   266         ))(input)
   264         ))(input)
   267     }
   265     }
   268 
   266 
   269     fn cmd_single_arg_message(input: &[u8]) -> HWResult<HWProtocolMessage> {
   267     fn cmd_single_arg_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   270         alt((
   268         alt((
   271             |i| cmdc_single_arg(i, "RESTART_SERVER", |i| tag("YES")(i), |_| RestartServer),
   269             |i| cmdc_single_arg(i, "RESTART_SERVER", |i| tag("YES")(i), |_| RestartServer),
   272             |i| cmdc_single_arg(i, "DELEGATE", a_line, Delegate),
   270             |i| cmdc_single_arg(i, "DELEGATE", a_line, Delegate),
   273             |i| cmdc_single_arg(i, "DELETE", a_line, Delete),
   271             |i| cmdc_single_arg(i, "DELETE", a_line, Delete),
   274             |i| cmdc_single_arg(i, "SAVEROOM", a_line, SaveRoom),
   272             |i| cmdc_single_arg(i, "SAVEROOM", a_line, SaveRoom),
   310             },
   308             },
   311         )),
   309         )),
   312     )
   310     )
   313 }
   311 }
   314 
   312 
   315 fn config_message<'a>(input: &'a [u8]) -> HWResult<'a, HWProtocolMessage> {
   313 fn config_message<'a>(input: &'a [u8]) -> HwResult<'a, HwProtocolMessage> {
   316     fn cfgc_single_arg<'a, T, F, G>(
   314     fn cfgc_single_arg<'a, T, F, G>(
   317         input: &'a [u8],
   315         input: &'a [u8],
   318         name: &'a str,
   316         name: &'a str,
   319         parser: F,
   317         parser: F,
   320         constructor: G,
   318         constructor: G,
   321     ) -> HWResult<'a, GameCfg>
   319     ) -> HwResult<'a, GameCfg>
   322     where
   320     where
   323         F: Fn(&[u8]) -> HWResult<T>,
   321         F: Fn(&[u8]) -> HwResult<T>,
   324         G: Fn(T) -> GameCfg,
   322         G: Fn(T) -> GameCfg,
   325     {
   323     {
   326         precededc(input, |i| terminatedc(i, hw_tag(name), eol), parser)
   324         precededc(input, |i| terminatedc(i, hw_tag(name), eol), parser)
   327             .map(|(i, v)| (i, constructor(v)))
   325             .map(|(i, v)| (i, constructor(v)))
   328     }
   326     }
   371         )),
   369         )),
   372     )?;
   370     )?;
   373     Ok((i, Cfg(cfg)))
   371     Ok((i, Cfg(cfg)))
   374 }
   372 }
   375 
   373 
   376 fn server_var_message(input: &[u8]) -> HWResult<HWProtocolMessage> {
   374 fn server_var_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   377     precededc(
   375     precededc(
   378         input,
   376         input,
   379         hw_tag("SET_SERVER_VAR\n"),
   377         hw_tag("SET_SERVER_VAR\n"),
   380         alt((
   378         alt((
   381             |i| {
   379             |i| {
   392             },
   390             },
   393         )),
   391         )),
   394     )
   392     )
   395 }
   393 }
   396 
   394 
   397 fn complex_message(input: &[u8]) -> HWResult<HWProtocolMessage> {
   395 fn complex_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   398     alt((
   396     alt((
   399         |i| {
   397         |i| {
   400             precededc(
   398             precededc(
   401                 i,
   399                 i,
   402                 |i| terminatedc(i, hw_tag("PASSWORD"), eol),
   400                 |i| terminatedc(i, hw_tag("PASSWORD"), eol),
   531             )
   529             )
   532         },
   530         },
   533     ))(input)
   531     ))(input)
   534 }
   532 }
   535 
   533 
   536 pub fn malformed_message(input: &[u8]) -> HWResult<()> {
   534 pub fn malformed_message(input: &[u8]) -> HwResult<()> {
   537     let (i, _) = terminatedc(input, |i| take_until(&b"\n\n"[..])(i), end_of_message)?;
   535     let (i, _) = terminatedc(input, |i| take_until(&b"\n\n"[..])(i), end_of_message)?;
   538     Ok((i, ()))
   536     Ok((i, ()))
   539 }
   537 }
   540 
   538 
   541 pub fn message(input: &[u8]) -> HWResult<HWProtocolMessage> {
   539 pub fn message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   542     precededc(
   540     precededc(
   543         input,
   541         input,
   544         |i| take_while(|c| c == b'\n')(i),
   542         |i| take_while(|c| c == b'\n')(i),
   545         |i| {
   543         |i| {
   546             terminatedc(
   544             terminatedc(
   557             )
   555             )
   558         },
   556         },
   559     )
   557     )
   560 }
   558 }
   561 
   559 
   562 fn extract_messages(input: &[u8]) -> HWResult<Vec<HWProtocolMessage>> {
   560 fn extract_messages(input: &[u8]) -> HwResult<Vec<HwProtocolMessage>> {
   563     many0(message)(input)
   561     many0(message)(input)
   564 }
   562 }
   565 
   563 
   566 #[cfg(test)]
   564 #[cfg(test)]
   567 mod test {
   565 mod test {
   568     use super::{extract_messages, message};
   566     use super::{extract_messages, message};
   569     use crate::protocol::parser::HWProtocolError;
   567     use crate::protocol::parser::HwProtocolError;
   570     use crate::protocol::{messages::HWProtocolMessage::*, test::gen_proto_msg};
   568     use crate::protocol::{messages::HwProtocolMessage::*, test::gen_proto_msg};
   571     use proptest::{proptest, proptest_helper};
   569     use proptest::{proptest, proptest_helper};
   572 
   570 
   573     #[cfg(test)]
   571     #[cfg(test)]
   574     proptest! {
   572     proptest! {
   575         #[test]
   573         #[test]
   614             Ok((&b""[..], Rnd(vec![String::from("A"), String::from("B")])))
   612             Ok((&b""[..], Rnd(vec![String::from("A"), String::from("B")])))
   615         );
   613         );
   616 
   614 
   617         assert_eq!(
   615         assert_eq!(
   618             message(b"QUIT\n1\n2\n\n"),
   616             message(b"QUIT\n1\n2\n\n"),
   619             Err(nom::Err::Error(HWProtocolError::new()))
   617             Err(nom::Err::Error(HwProtocolError::new()))
   620         );
   618         );
   621 
   619 
   622         assert_eq!(
   620         assert_eq!(
   623             extract_messages(b"\n\n\n\nPING\n\n"),
   621             extract_messages(b"\n\n\n\nPING\n\n"),
   624             Ok((&b""[..], vec![Ping]))
   622             Ok((&b""[..], vec![Ping]))