irc_async/proto/
response.rs

1//! Enumeration of all the possible server responses.
2#![allow(non_camel_case_types)]
3use std::str::FromStr;
4
5macro_rules! make_response {
6    ($($(#[$attr:meta])+ $variant:ident = $value:expr),+) => {
7        /// List of all server responses as defined in
8        /// [RFC 2812](http://tools.ietf.org/html/rfc2812) and
9        /// [Modern docs](https://modern.ircdocs.horse/#numerics) (henceforth referred to as
10        /// Modern). All commands are documented with their expected form from the RFC, and any
11        /// useful, additional information about the response code.
12        #[derive(Clone, Copy, Debug, PartialEq)]
13        #[repr(u16)]
14        pub enum Response {
15            $($(#[$attr])+ $variant = $value),+
16        }
17
18        impl Response {
19            /// Generates a Response from a u16.
20            fn from_u16(val: u16) -> Option<Response> {
21                match val {
22                    $($value => Some(Response::$variant),)+
23                    _ => None
24                }
25            }
26        }
27    }
28}
29
30make_response! {
31    // Expected replies
32    /// `001 Welcome to the Internet Relay Network <nick>!<user>@<host>` (Source: RFC2812)
33    RPL_WELCOME         =   1,
34    /// `002 Your host is <servername>, running version <ver>` (Source: RFC2812)
35    RPL_YOURHOST        =   2,
36    /// `003 This server was created <date>` (Source: RFC2812)
37    RPL_CREATED         =   3,
38    /// `004 <servername> <version> <available user modes> <available channel modes>` (Source:
39    /// RFC2812)
40    ///
41    /// Various IRCds may choose to include additional arguments to `RPL_MYINFO`, and it's best to
42    /// check for certain what the servers you're targeting do. Typically, there are additional
43    /// parameters at the end for modes that have parameters, and server modes.
44    RPL_MYINFO          =   4,
45    /// `005 <servername> *(<feature>(=<value>)) :are supported by this server` (Source: Modern)
46    ///
47    /// [RPL_ISUPPORT](https://modern.ircdocs.horse/#rplisupport-005) replaces RPL_BOUNCE from
48    /// RFC2812, but does so consistently in modern IRCd implementations. RPL_BOUNCE has been moved
49    /// to `010`.
50    RPL_ISUPPORT        =   5,
51    /// `010 Try server <server name>, port <port number>` (Source: Modern)
52    RPL_BOUNCE          =  10,
53    /// Undefined format. (Source: Modern)
54    ///
55    /// RPL_NONE is a dummy numeric. It does not have a defined use nor format.
56    RPL_NONE            = 300,
57    /// `302 :*1<reply> *( " " <reply> )` (Source: RFC2812)
58    RPL_USERHOST        = 302,
59    /// `303 :*1<nick> *( " " <nick> )` (Source: RFC2812)
60    RPL_ISON            = 303,
61    /// `301 <nick> :<away message>` (Source: RFC2812)
62    RPL_AWAY            = 301,
63    /// `305 :You are no longer marked as being away` (Source: RFC2812)
64    RPL_UNAWAY          = 305,
65    /// `306 :You have been marked as being away` (Source: RFC2812)
66    RPL_NOWAWAY         = 306,
67    /// `311 <nick> <user> <host> * :<real name>` (Source: RFC2812)
68    RPL_WHOISUSER       = 311,
69    /// `312 <nick> <server> :<server info>` (Source: RFC2812)
70    RPL_WHOISSERVER     = 312,
71    /// `313 <nick> :is an IRC operator` (Source: RFC2812)
72    RPL_WHOISOPERATOR   = 313,
73    /// `317 <nick> <integer> :seconds idle` (Source: RFC2812)
74    RPL_WHOISIDLE       = 317,
75    /// `318 <nick> :End of WHOIS list` (Source: RFC2812)
76    RPL_ENDOFWHOIS      = 318,
77    /// `319 <nick> :*( ( "@" / "+" ) <channel> " " )` (Source: RFC2812)
78    RPL_WHOISCHANNELS   = 319,
79    /// `314 <nick> <user> <host> * :<real name>` (Source: RFC2812)
80    RPL_WHOWASUSER      = 314,
81    /// `369 <nick> :End of WHOWAS` (Source: RFC2812)
82    RPL_ENDOFWHOWAS     = 369,
83    /// Obsolete. Not used. (Source: RFC2812)
84    RPL_LISTSTART       = 321,
85    /// `322 <channel> <# visible> :<topic>` (Source: RFC2812)
86    RPL_LIST            = 322,
87    /// `323 :End of LIST (Source: RFC2812)
88    RPL_LISTEND         = 323,
89    /// `325 <channel> <nickname>` (Source: RFC2812)
90    RPL_UNIQOPIS        = 325,
91    /// `324 <channel> <mode> <mode params>` (Source: RFC2812)
92    RPL_CHANNELMODEIS   = 324,
93    /// `331 <channel> :No topic is set` (Source: RFC2812)
94    RPL_NOTOPIC         = 331,
95    /// `332 <channel> :<topic>` (Source: RFC2812)
96    RPL_TOPIC           = 332,
97    /// `333 <channel> <nick>!<user>@<host> <unix timestamp>` (Source: RFC2812)
98    RPL_TOPICWHOTIME    = 333,
99    /// `341 <channel> <nick>` (Source: RFC2812)
100    RPL_INVITING        = 341,
101    /// `342 <user> :Summoning user to IRC` (Source: RFC2812)
102    ///
103    /// According to Modern, this response is rarely implemented. In practice, people simply message
104    /// one another in a channel with their specified username in the message, rather than use the
105    /// `SUMMON` command.
106    RPL_SUMMONING       = 342,
107    /// `346 <channel> <invitemask>` (Source: RFC2812)
108    RPL_INVITELIST      = 346,
109    /// `347 <channel> :End of channel invite list` (Source: RFC2812)
110    ///
111    /// According to Modern, `RPL_ENDOFEXCEPTLIST` (349) is frequently deployed for this same
112    /// purpose and the difference will be noted in channel mode and the statement in the suffix.
113    RPL_ENDOFINVITELIST = 347,
114    /// `348 <channel> <exceptionmask>` (Source: RFC2812)
115    RPL_EXCEPTLIST      = 348,
116    /// `349 <channel> :End of channel exception list` (Source: RFC2812)
117    RPL_ENDOFEXCEPTLIST = 349,
118    /// `351 <version> <server> :<comments>` (Source: RFC2812/Modern)
119    RPL_VERSION         = 351,
120    /// `352 <channel> <user> <host> <server> <nick> ( "H" / "G" > ["*"] [ ( "@" / "+" ) ]
121    /// :<hopcount> <real name>` (Source: RFC2812)
122    RPL_WHOREPLY        = 352,
123    /// `315 <name> :End of WHO list` (Source: RFC2812)
124    RPL_ENDOFWHO        = 315,
125    /// `353 ( "=" / "*" / "@" ) <channel> :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )`
126    /// (Source: RFC2812)
127    RPL_NAMREPLY        = 353,
128    /// `366 <channel> :End of NAMES list` (Source: RFC2812)
129    RPL_ENDOFNAMES      = 366,
130    /// `364 <mask> <server> :<hopcount> <server info>` (Source: RFC2812)
131    RPL_LINKS           = 364,
132    /// `365 <mask> :End of LINKS list` (Source: RFC2812)
133    RPL_ENDOFLINKS      = 365,
134    /// `367 <channel> <banmask>` (Source: RFC2812)
135    RPL_BANLIST         = 367,
136    /// `368 <channel> :End of channel ban list` (Source: RFC2812)
137    RPL_ENDOFBANLIST    = 368,
138    /// `371 :<string>` (Source: RFC2812)
139    RPL_INFO            = 371,
140    /// `374 :End of INFO list` (Source: RFC2812)
141    RPL_ENDOFINFO       = 374,
142    /// `375 :- <server> Message of the day -` (Source: RFC2812)
143    RPL_MOTDSTART       = 375,
144    /// `372 :- <text>` (Source: RFC2812)
145    RPL_MOTD            = 372,
146    /// `376 :End of MOTD command` (Source: RFC2812)
147    RPL_ENDOFMOTD       = 376,
148    /// `381 :You are now an IRC operator` (Source: RFC2812)
149    RPL_YOUREOPER       = 381,
150    /// `382 <config file> :Rehashing` (Source: RFC2812)
151    RPL_REHASHING       = 382,
152    /// `383 You are service <servicename>` (Source: RFC2812)
153    RPL_YOURESERVICE    = 383,
154    /// `391 <server> :<string showing server's local time>` (Source: RFC2812)
155    RPL_TIME            = 391,
156    /// `392 :UserID   Terminal  Host` (Source: RFC2812)
157    RPL_USERSSTART      = 392,
158    /// `393 :<username> <ttyline> <hostname>` (Source: RFC2812)
159    RPL_USERS           = 393,
160    /// `394 :End of users` (Source: RFC2812)
161    RPL_ENDOFUSERS      = 394,
162    /// `395 :Nobody logged in` (Source: RFC2812)
163    RPL_NOUSERS         = 395,
164    /// `396 <nickname> <host> :is now your displayed host` (Source: InspIRCd)
165    ///
166    /// This response code is sent after a user enables the user mode +x (host masking), and it is
167    /// successfully enabled. The particular format described above is from InspIRCd, but the
168    /// response code should be common amongst servers that support host masks.
169    RPL_HOSTHIDDEN      = 396,
170    /// `200 Link <version & debug level> <destination> <next server> V<protocol version>
171    /// <link uptime in seconds> <backstream sendq> <upstream sendq>` (Source: RFC2812)
172    RPL_TRACELINK       = 200,
173    /// `201 Try. <class> <server>` (Source: RFC2812)
174    RPL_TRACECONNECTING = 201,
175    /// `202 H.S. <class> <server>` (Source: RFC2812)
176    RPL_TRACEHANDSHAKE  = 202,
177    /// `203 ???? <class> [<client IP address in dot form>]` (Source: RFC2812)
178    RPL_TRACEUKNOWN     = 203,
179    /// `204 Oper <class> <nick>` (Source: RFC2812)
180    RPL_TRACEOPERATOR   = 204,
181    /// `205 User <class> <nick>` (Source: RFC2812)
182    RPL_TRACEUSER       = 205,
183    /// `206 Serv <class> <int>S <int>C <server> <nick!user|*!*>@<host|server> V<protocol version>`
184    /// (Source: RFC2812)
185    RPL_TRACESERVER     = 206,
186    /// `207 Service <class> <name> <type> <active type>` (Source: RFC2812)
187    RPL_TRACESERVICE    = 207,
188    /// `208 <newtype> 0 <client name>` (Source: RFC2812)
189    RPL_TRACENEWTYPE    = 208,
190    /// `209 Class <class> <count>` (Source: RFC2812)
191    RPL_TRACECLASS      = 209,
192    /// Unused. (Source: RFC2812)
193    RPL_TRACERECONNECT  = 210,
194    /// `261 File <logfile> <debug level>` (Source: RFC2812)
195    RPL_TRACELOG        = 261,
196    /// `262 <server name> <version & debug level> :End of TRACE` (Source: RFC2812)
197    RPL_TRACEEND        = 262,
198    /// `211 <linkname> <sendq> <sent messages> <sent Kbytes> <received messages> <received Kbytes>
199    /// <time open>` (Source: RFC2812)
200    RPL_STATSLINKINFO   = 211,
201    /// `212 <command> <count> <byte count> <remote count>` (Source: RFC2812)
202    RPL_STATSCOMMANDS   = 212,
203    /// `219 <stats letter> :End of STATS report` (Source: RFC2812)
204    RPL_ENDOFSTATS      = 219,
205    /// `242 :Server Up %d days %d:%02d:%02d` (Source: RFC2812)
206    RPL_STATSUPTIME     = 242,
207    /// `243 O <hostmask> * <name>` (Source: RFC2812)
208    RPL_STATSOLINE      = 243,
209    /// `221 <user mode string>` (Source: RFC2812)
210    RPL_UMODEIS         = 221,
211    /// `234 <name> <server> <mask> <type> <hopcount> <info>` (Source: RFC2812)
212    RPL_SERVLIST        = 234,
213    /// `235 <mask> <type> :End of service listing` (Source: RFC2812)
214    RPL_SERVLISTEND     = 235,
215    /// `251 :There are <int> users and <int> services on <int> servers` (Source: RFC2812)
216    RPL_LUSERCLIENT     = 251,
217    /// `252 <integer> :operator(s) online` (Source: RFC2812)
218    RPL_LUSEROP         = 252,
219    /// `253 <integer> :unknown connection(s)` (Source: RFC2812)
220    RPL_LUSERUNKNOWN    = 253,
221    /// `254 <integer> :channels formed` (Source: RFC2812)
222    RPL_LUSERCHANNELS   = 254,
223    /// `255 :I have <integer> clients and <integer> servers` (Source: RFC2812)
224    RPL_LUSERME         = 255,
225    /// `256 <server> :Administrative info` (Source: RFC2812)
226    RPL_ADMINME         = 256,
227    /// `257 :<admin info>` (Source: RFC2812)
228    RPL_ADMINLOC1       = 257,
229    /// `258 :<admin info>` (Source: RFC2812)
230    RPL_ADMINLOC2       = 258,
231    /// `259 :<admin info>` (Source: RFC2812)
232    RPL_ADMINEMAIL      = 259,
233    /// `263 <command> :Please wait a while and try again.` (Source: RFC2812)
234    RPL_TRYAGAIN        = 263,
235    /// `265 <client> [<u> <m>] :Current local users <u>, max <m>` (Source: Modern)
236    RPL_LOCALUSERS      = 265,
237    /// `266 <client> [<u> <m>] :Current local users <u>, max <m>` (Source: Modern)
238    RPL_GLOBALUSERS     = 266,
239    /// `276 <client> <nick> :has client certificate fingerprint <fingerprint>` (Source: Modern)
240    RPL_WHOISCERTFP     = 276,
241    /// `730 <nick> :target[,target2]*` (Source: RFC2812)
242    RPL_MONONLINE       = 730,
243    /// `731 <nick> :target[,target2]*` (Source: RFC2812)
244    RPL_MONOFFLINE      = 731,
245    /// `732 <nick> :target[,target2]*` (Source: RFC2812)
246    RPL_MONLIST         = 732,
247    /// `733 <nick> :End of MONITOR list` (Source: RFC2812)
248    RPL_ENDOFMONLIST    = 733,
249    /// `760 <target> <key> <visibility> :<value>` (Source: RFC2812)
250    RPL_WHOISKEYVALUE   = 760,
251    /// `761 <target> <key> <visibility> :[<value>]` (Source: RFC2812)
252    RPL_KEYVALUE        = 761,
253    /// `762 :end of metadata` (Source: RFC2812)
254    RPL_METADATAEND     = 762,
255    /// `900 <nick> <nick>!<ident>@<host> <account> :You are now logged in as <user>` (Source:
256    /// IRCv3)
257    RPL_LOGGEDIN        = 900,
258    /// `901 <nick> <nick>!<ident>@<host> :You are now logged out` (Source: IRCv3)
259    RPL_LOGGEDOUT       = 901,
260    /// `903 <nick> :SASL authentication successful` (Source: IRCv3)
261    RPL_SASLSUCCESS     = 903,
262    /// `908 <nick> <mechanisms> :are available SASL mechanisms` (Source: IRCv3)
263    RPL_SASLMECHS       = 908,
264
265    // Error replies
266    /// `400 <client> <command>{ <subcommand>} :<info>` (Source: Modern)
267    ///
268    /// According to Modern, this error will be returned when the given command/subcommand could not
269    /// be processed. It's a very general error, and should only be used when more specific numerics
270    /// do not suffice.
271    ERR_UNKNOWNERROR        = 400,
272    /// `401 <nickname> :No such nick/channel` (Source: RFC2812)
273    ERR_NOSUCHNICK          = 401,
274    /// `402 <server name> :No such server` (Source: RFC2812)
275    ERR_NOSUCHSERVER        = 402,
276    /// `403 <channel name> :No such channel` (Source: RFC2812)
277    ERR_NOSUCHCHANNEL       = 403,
278    /// `404 <channel name> :Cannot send to channel` (Source: RFC2812)
279    ERR_CANNOTSENDTOCHAN    = 404,
280    /// `405 <channel name> :You have joined too many channels` (Source: RFC2812)
281    ERR_TOOMANYCHANNELS     = 405,
282    /// `406 <nickname> :There was no such nickname` (Source: RFC2812)
283    ERR_WASNOSUCHNICK       = 406,
284    /// `407 <target> :<error code> recipients. <abort message>` (Source: RFC2812)
285    ERR_TOOMANYTARGETS      = 407,
286    /// `408 <service name> :No such service` (Source: RFC2812)
287    ERR_NOSUCHSERVICE       = 408,
288    /// `409 :No origin specified` (Source: RFC2812)
289    ERR_NOORIGIN            = 409,
290    /// `411 :No recipient given (<command>)` (Source: RFC2812)
291    ERR_NORECIPIENT         = 411,
292    /// `412 :No text to send` (Source: RFC2812)
293    ERR_NOTEXTTOSEND        = 412,
294    /// `413 <mask> :No toplevel domain specified` (Source: RFC2812)
295    ERR_NOTOPLEVEL          = 413,
296    /// `414 <mask> :Wildcard in toplevel domain` (Source: RFC2812)
297    ERR_WILDTOPLEVEL        = 414,
298    /// `415 <mask> :Bad Server/host mask` (Source: RFC2812)
299    ERR_BADMASK             = 415,
300    /// `421 <command> :Unknown command` (Source: RFC2812)
301    ERR_UNKNOWNCOMMAND      = 421,
302    /// `422 :MOTD File is missing` (Source: RFC2812)
303    ERR_NOMOTD              = 422,
304    /// `423 <server> :No administrative info available` (Source: RFC2812)
305    ERR_NOADMININFO         = 423,
306    /// `424 :File error doing <file op> on <file>` (Source: RFC2812)
307    ERR_FILEERROR           = 424,
308    /// `431 :No nickname given` (Source: RFC2812)
309    ERR_NONICKNAMEGIVEN     = 431,
310    /// `432 <nick> :Erroneous nickname"` (Source: RFC2812)
311    ERR_ERRONEOUSNICKNAME   = 432,
312    /// `433 <nick> :Nickname is already in use` (Source: RFC2812)
313    ERR_NICKNAMEINUSE       = 433,
314    /// `436 <nick> :Nickname collision KILL from <user>@<host>` (Source: RFC2812)
315    ERR_NICKCOLLISION       = 436,
316    /// `437 <nick/channel> :Nick/channel is temporarily unavailable` (Source: RFC2812)
317    ERR_UNAVAILRESOURCE     = 437,
318    /// `441 <nick> <channel> :They aren't on that channel` (Source: RFC2812)
319    ERR_USERNOTINCHANNEL    = 441,
320    /// `442 <channel> :You're not on that channel` (Source: RFC2812)
321    ERR_NOTONCHANNEL        = 442,
322    /// `443 <user> <channel> :is already on channel` (Source: RFC2812)
323    ERR_USERONCHANNEL       = 443,
324    /// `444 <user> :User not logged in` (Source: RFC2812)
325    ERR_NOLOGIN             = 444,
326    /// `445 :SUMMON has been disabled` (Source: RFC2812)
327    ERR_SUMMONDISABLED      = 445,
328    /// `446 :USERS has been disabled` (Source: RFC2812)
329    ERR_USERSDISABLED       = 446,
330    /// `451 :You have not registered` (Source: RFC2812)
331    ERR_NOTREGISTERED       = 451,
332    /// `461 <command> :Not enough parameters` (Source: RFC2812)
333    ERR_NEEDMOREPARAMS      = 461,
334    /// `462 :Unauthorized command (already registered)` (Source: RFC2812)
335    ERR_ALREADYREGISTRED    = 462,
336    /// `463 :Your host isn't among the privileged` (Source: RFC2812)
337    ERR_NOPERMFORHOST       = 463,
338    /// `464 :Password incorrect` (Source: RFC2812)
339    ERR_PASSWDMISMATCH      = 464,
340    /// `465 :You are banned from this server` (Source: RFC2812)
341    ERR_YOUREBANNEDCREEP    = 465,
342    /// `466` (Source: RFC2812)
343    ERR_YOUWILLBEBANNED     = 466,
344    /// `467 <channel> :Channel key already set` (Source: RFC2812)
345    ERR_KEYSET              = 467,
346    /// `471 <channel> :Cannot join channel (+l)` (Source: RFC2812)
347    ERR_CHANNELISFULL       = 471,
348    /// `472 <char> :is unknown mode char to me for <channel>` (Source: RFC2812)
349    ERR_UNKNOWNMODE         = 472,
350    /// `473 <channel> :Cannot join channel (+i)` (Source: RFC2812)
351    ERR_INVITEONLYCHAN      = 473,
352    /// `474 <channel> :Cannot join channel (+b)` (Source: RFC2812)
353    ERR_BANNEDFROMCHAN      = 474,
354    /// `475 <channel> :Cannot join channel (+k)` (Source: RFC2812)
355    ERR_BADCHANNELKEY       = 475,
356    /// `476 <channel> :Bad Channel Mask` (Source: RFC2812)
357    ERR_BADCHANMASK         = 476,
358    /// `477 <channel> :Channel doesn't support modes` (Source: RFC2812)
359    ERR_NOCHANMODES         = 477,
360    /// `478 <channel> <char> :Channel list is full` (Source: RFC2812)
361    ERR_BANLISTFULL         = 478,
362    /// `481 :Permission Denied- You're not an IRC operator` (Source: RFC2812)
363    ERR_NOPRIVILEGES        = 481,
364    /// `482 <channel> :You're not channel operator` (Source: RFC2812)
365    ERR_CHANOPRIVSNEEDED    = 482,
366    /// `483 :You can't kill a server!` (Source: RFC2812)
367    ERR_CANTKILLSERVER      = 483,
368    /// `484 :Your connection is restricted!` (Source: RFC2812)
369    ERR_RESTRICTED          = 484,
370    /// `485 :You're not the original channel operator` (Source: RFC2812)
371    ERR_UNIQOPPRIVSNEEDED   = 485,
372    /// `491 :No O-lines for your host` (Source: RFC2812)
373    ERR_NOOPERHOST          = 491,
374    /// `501 :Unknown MODE flag` (Source: RFC2812)
375    ERR_UMODEUNKNOWNFLAG    = 501,
376    /// `502 :Cannot change mode for other users` (Source: RFC2812)
377    ERR_USERSDONTMATCH      = 502,
378    /// `723 <client> <priv> :Insufficient oper privileges.` (Source: Modern)
379    ///
380    /// Sent to an operator to indicate that they don't have the specific privileges to perform the
381    /// desired action. The format and meaning of the privilege string is server-defined.
382    ERR_NOPRIVS             = 723,
383    /// `734 <nick> <limit> <targets> :Monitor list is full.` (Source: RFC2812)
384    ERR_MONLISTFULL         = 734,
385    /// `764 <target> :metadata limit reached` (Source: RFC2812)
386    ERR_METADATALIMIT       = 764,
387    /// `765 <target> :invalid metadata target` (Source: RFC2812)
388    ERR_TARGETINVALID       = 765,
389    /// `766 <key> :no matching key` (Source: RFC2812)
390    ERR_NOMATCHINGKEY       = 766,
391    /// `767 <key> :invalid metadata key` (Source: RFC2812)
392    ERR_KEYINVALID          = 767,
393    /// `768 <target> <key> :key not set` (Source: RFC2812)
394    ERR_KEYNOTSET           = 768,
395    /// `769 <target> <key> :permission denied` (Source: RFC2812)
396    ERR_KEYNOPERMISSION     = 769,
397    /// `902 <nick> :You must use a nick assigned to you.` (Source: IRCv3)
398    ERR_NICKLOCKED          = 902,
399    /// `904 <nick> :SASL authentication failed` (Source: IRCv3)
400    ERR_SASLFAIL            = 904,
401    /// `905 <nick> :SASL message too long` (Source: IRCv3)
402    ERR_SASLTOOLONG         = 905,
403    /// `906 <nick> :SASL authentication aborted` (Source: IRCv3)
404    ERR_SASLABORT           = 906,
405    /// `907 <nick> :You have already authenticated using SASL` (Source: IRCv3)
406    ERR_SASLALREADY         = 907
407}
408
409impl Response {
410    /// Determines whether or not this response is an error response.
411    ///
412    /// This error consideration is according to RFC2812, but is rather simplistic. It considers all
413    /// response codes above 400 to be errors, which misclassifies some extensions (e.g. from IRCv3)
414    /// that add responses and errors both in the same range (typically 700s or 900s).
415    pub fn is_error(self) -> bool {
416        self as u16 >= 400
417    }
418}
419
420impl FromStr for Response {
421    type Err = &'static str;
422    fn from_str(s: &str) -> Result<Response, &'static str> {
423        if let Ok(rc) = s.parse() {
424            match Response::from_u16(rc) {
425                Some(r) => Ok(r),
426                None => Err("Failed to parse due to unknown response code."),
427            }
428        } else {
429            Err("Failed to parse response code.")
430        }
431    }
432}
433
434#[cfg(test)]
435mod test {
436    use super::Response;
437
438    #[test]
439    fn is_error() {
440        assert!(!Response::RPL_NAMREPLY.is_error());
441        assert!(Response::ERR_NICKNAMEINUSE.is_error());
442    }
443}