1use std::fmt;
3use std::str::FromStr;
4
5#[derive(Clone, Eq, PartialEq, Debug)]
7pub enum Prefix {
8 ServerName(String),
10 Nickname(String, String, String),
14}
15
16impl Prefix {
17 pub fn new_from_str(s: &str) -> Prefix {
29 #[derive(Copy, Clone, Eq, PartialEq)]
30 enum Active {
31 Name,
32 User,
33 Host,
34 }
35
36 let mut name = String::new();
37 let mut user = String::new();
38 let mut host = String::new();
39 let mut active = Active::Name;
40 let mut is_server = false;
41
42 for c in s.chars() {
43 if c == '.' && active == Active::Name {
44 is_server = true;
47 }
48
49 match c {
50 '!' if active == Active::Name => {
51 is_server = false;
52 active = Active::User;
53 }
54
55 '@' if active != Active::Host => {
56 is_server = false;
57 active = Active::Host;
58 }
59
60 _ => {
61 match active {
63 Active::Name => &mut name,
64 Active::User => &mut user,
65 Active::Host => &mut host,
66 }
67 .push(c)
68 }
69 }
70 }
71
72 if is_server {
73 Prefix::ServerName(name)
74 } else {
75 Prefix::Nickname(name, user, host)
76 }
77 }
78}
79
80impl FromStr for Prefix {
82 type Err = ();
83
84 fn from_str(s: &str) -> Result<Self, Self::Err> {
85 Ok(Prefix::new_from_str(s))
86 }
87}
88
89impl fmt::Display for Prefix {
91 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92 match self {
93 Prefix::ServerName(name) => write!(f, "{}", name),
94 Prefix::Nickname(name, user, host) => match (&name[..], &user[..], &host[..]) {
95 ("", "", "") => write!(f, ""),
96 (name, "", "") => write!(f, "{}", name),
97 (name, user, "") => write!(f, "{}!{}", name, user),
98 (name, "", host) => write!(f, "{}@{}", name, host),
99 (name, user, host) => write!(f, "{}!{}@{}", name, user, host),
100 },
101 }
102 }
103}
104
105impl<'a> From<&'a str> for Prefix {
106 fn from(s: &str) -> Self {
107 Prefix::new_from_str(s)
108 }
109}
110
111#[cfg(test)]
112mod test {
113 use super::Prefix::{self, Nickname, ServerName};
114
115 fn test_parse(s: &str) -> Prefix {
117 let prefix = Prefix::new_from_str(s);
118 let s2 = format!("{}", prefix);
119 assert_eq!(s, &s2);
120 prefix
121 }
122
123 #[test]
124 fn print() {
125 let s = format!("{}", Nickname("nick".into(), "".into(), "".into()));
126 assert_eq!(&s, "nick");
127 let s = format!("{}", Nickname("nick".into(), "user".into(), "".into()));
128 assert_eq!(&s, "nick!user");
129 let s = format!("{}", Nickname("nick".into(), "user".into(), "host".into()));
130 assert_eq!(&s, "nick!user@host");
131 }
132
133 #[test]
134 fn parse_word() {
135 assert_eq!(
136 test_parse("only_nick"),
137 Nickname("only_nick".into(), String::new(), String::new())
138 )
139 }
140
141 #[test]
142 fn parse_host() {
143 assert_eq!(test_parse("host.tld"), ServerName("host.tld".into()))
144 }
145
146 #[test]
147 fn parse_nick_user() {
148 assert_eq!(
149 test_parse("test!nick"),
150 Nickname("test".into(), "nick".into(), String::new())
151 )
152 }
153
154 #[test]
155 fn parse_nick_user_host() {
156 assert_eq!(
157 test_parse("test!nick@host"),
158 Nickname("test".into(), "nick".into(), "host".into())
159 )
160 }
161
162 #[test]
163 fn parse_dot_and_symbols() {
164 assert_eq!(
165 test_parse("test.net@something"),
166 Nickname("test.net".into(), "".into(), "something".into())
167 )
168 }
169
170 #[test]
171 fn parse_danger_cases() {
172 assert_eq!(
173 test_parse("name@name!user"),
174 Nickname("name".into(), "".into(), "name!user".into())
175 );
176 assert_eq!(
177 "name!@".parse::<Prefix>().unwrap(),
179 Nickname("name".into(), "".into(), "".into())
180 );
181 assert_eq!(
182 "name!@hostname".parse::<Prefix>().unwrap(),
184 Nickname("name".into(), "".into(), "hostname".into())
185 );
186 assert_eq!(
187 test_parse("name!.user"),
188 Nickname("name".into(), ".user".into(), "".into())
189 );
190 assert_eq!(
191 test_parse("name!user.user"),
192 Nickname("name".into(), "user.user".into(), "".into())
193 );
194 assert_eq!(
195 test_parse("name!user@host.host"),
196 Nickname("name".into(), "user".into(), "host.host".into())
197 );
198 assert_eq!(
199 test_parse("!user"),
200 Nickname("".into(), "user".into(), "".into())
201 );
202 assert_eq!(
203 "!@host.host".parse::<Prefix>().unwrap(),
204 Nickname("".into(), "".into(), "host.host".into())
205 );
206 }
207}