1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
use crate::proto::message::{IrcMessage, Prefix};
use std::fmt::Write;
pub fn serialize(msg: &IrcMessage) -> String {
let mut out = String::with_capacity(512);
// tags
if !msg.tags.is_empty() {
out.push('@');
let mut first = true;
for (key, value) in &msg.tags {
if !first {
out.push(';');
}
first = false;
out.push_str(key);
if let Some(v) = value {
out.push('=');
escape_tag_value(&mut out, v);
}
}
out.push(' ');
}
// prefix
if let Some(prefix) = &msg.prefix {
out.push(':');
match prefix {
Prefix::Server(s) => out.push_str(s),
Prefix::User { nick, user, host } => {
out.push_str(nick);
if let Some(u) = user {
out.push('!');
out.push_str(u);
}
if let Some(h) = host {
out.push('@');
out.push_str(h);
}
}
}
out.push(' ');
}
// command
let _ = write!(out, "{}", msg.command);
// params
let last_idx = msg.params.len().saturating_sub(1);
for (i, param) in msg.params.iter().enumerate() {
out.push(' ');
// The last param must be trailing if it contains spaces or starts with ':'
let needs_trailing = i == last_idx
&& (param.contains(' ')
|| param.starts_with(':')
|| param.is_empty()
|| msg.params.len() > 1);
if needs_trailing {
out.push(':');
}
out.push_str(param);
}
out
}
fn escape_tag_value(out: &mut String, value: &str) {
for ch in value.chars() {
match ch {
';' => out.push_str(r"\:"),
' ' => out.push_str(r"\s"),
'\\' => out.push_str(r"\\"),
'\r' => out.push_str(r"\r"),
'\n' => out.push_str(r"\n"),
c => out.push(c),
}
}
}
|