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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations,
trivial_casts, trivial_numeric_casts, unsafe_code, unstable_features,
unused_import_braces, unused_qualifications)]
#![cfg_attr(feature="clippy", allow(unstable_features))]
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", deny(clippy_pedantic))]
#![cfg_attr(feature="clippy", allow(non_ascii_literal))]
extern crate phf;
extern crate unicode_segmentation;
use unicode_segmentation::UnicodeSegmentation;
include!(concat!(env!("OUT_DIR"), "/emojis.rs"));
pub fn to_string<T: AsRef<[u8]>>(buf: T) -> String {
buf.as_ref()
.iter()
.flat_map(|c| EMOJIS.get(c))
.map(|c| c.0)
.collect::<String>()
}
pub fn from_string(input: &str) -> Vec<u8> {
UnicodeSegmentation::graphemes(input, true)
.flat_map(|c| EMOJIS_REV.get(c))
.map(|c| c.to_owned())
.collect::<Vec<_>>()
}
pub fn to_names<T: AsRef<[u8]>>(buf: T) -> String {
to_custom(buf, |_, name| format!(":{}:", name))
}
pub fn to_custom<T: AsRef<[u8]>, F: Fn(&str, &str) -> String>(buf: T, f: F) -> String {
buf.as_ref()
.iter()
.map(|c| {
let emoji = EMOJIS.get(c).unwrap();
f(emoji.0, emoji.1)
})
.collect::<Vec<_>>()
.concat()
}
#[cfg(test)]
mod tests {
use super::*;
static ALL_EMOJIS: &'static str = "๐ฏ๐ข๐๐๐ฑ๐
ฐ๐กโ๏ธ๐ฝ๐โ๏ธ๐ผ๐ข๐ ๐๐โฌ๏ธโฌ
๏ธโก๏ธโฌ๏ธ๐จ๐ง๐ถ๐ผ๐๐๐โผ๏ธ๐๐๐๐๐๐ป๐๐บ๐๐๐ด๐๐๐๐ผ๐๐๐๐โต๏ธ๐ฃ๐๐๐ฅ\
๐ข๐๐ณ๐ฆ๐๐ฐ๐ผ๐๐๐ก๐๐ค๐ต๐ฐ๐๐ซ๐ฌ๐๐๐ฟ๐๐๐๐ซ๐๐๐ฌโ๏ธ๐ธโ๏ธ๐ป๐๐ง๐ช๐ฝ๐ซ๐๐๐๐ฎ๐๐๐๐ฏ๐จ๐ณ๐ซ๐๐ต๐ฌ๐ฉ๐ช๐ง๐๐๐๐๐ฃ\
๐ฅ๐ฆ๐พ๐๐๐ค๐๐ธ๐ฒ๐๐ป๐๐โณ๏ธ๐๐๐ธ๐ซ๐๐จ๐๐ฃ๐ฟ๐๐ ๐ดโ๏ธ๐จ๐๐๐๐จ๐๐๐๐ข๐๐ซ๐๐ฃ๐๐ค๐ฌ๐ฐ๐๐๐๐ฅ๐ช๐๐น๐ต๐๐ฐ๐โ๏ธ๐ซ\
๐๐ฉ๐๐๐๐๐ผโ
๏ธ๐พ๐๐๐ง๐ญโ๏ธ๐๐ฝ๐๐๐๐๐๐๐๐๐ฉ๐ฉ๐ฏ๐๐๐๐๐๐๐ป๐๐๐๐๐๐๐น๐จ๐๐๐
๐ก๐ทโ๏ธ๐๐๐ฟ๐๐๐๐โ๏ธ\
โ๏ธ๐ญโฝ๏ธ๐๐พ๐ฌโญ๏ธ๐๐๐ฆ๐๐๐ญ๐พ๐ญ๐ฝ๐
๐ฉ๐ฅ๐๐บ๐ข๐ฆ๐ผ๐ฎ๐ปโ๏ธ๐๐ท๐บ๐งโก๏ธ๐ค";
#[test]
fn all_bytes_to_emojis() {
let all_code_points = (0..256)
.collect::<Vec<_>>()
.iter()
.map(|cp| *cp as u8)
.collect::<Vec<_>>();
assert_eq!(to_string(&all_code_points[..]), ALL_EMOJIS);
}
#[test]
fn all_emojis_to_bytes() {
let all_code_points = (0..256)
.collect::<Vec<_>>()
.iter()
.map(|cp| *cp as u8)
.collect::<Vec<_>>();
assert_eq!(from_string(&ALL_EMOJIS)[..], all_code_points[..]);
}
#[test]
fn string_to_emojis() {
let input = "encoji is the way of the future!";
let output = "๐ฌ๐ฅ๐๐ฆ๐๐๐๐๐ค๐๐๐ง๐ฌ๐๐๐ณ๐๐๐ฆ๐ฉ๐๐๐ง๐ฌ๐๐ฉ๐ธ๐๐ธ๐๐ฌ๐ป";
assert_eq!(to_string(input), output);
}
#[test]
fn emojis_to_string() {
let input = "๐ฌ๐ฅ๐๐ฆ๐๐๐๐๐ค๐๐๐ง๐ฌ๐๐๐ณ๐๐๐ฆ๐ฉ๐๐๐ง๐ฌ๐๐ฉ๐ธ๐๐ธ๐๐ฌ๐ป";
let output = "encoji is the way of the future!";
assert_eq!(String::from_utf8_lossy(&from_string(&input)[..]), output);
}
#[test]
fn emojis_to_string_ingore_invalid_codepoints() {
let input = "๐ฌ๐ฅ๐๐ฆ๐๐๐๐๐ค๐๐๐ง๐ฌasdfasdf๐๐๐ณ๐๐๐ฆ๐ฉ๐๐๐ง๐ฌ๐๐ฉ๐ธ๐๐ธ๐๐ฌ๐ป\n";
let output = "encoji is the way of the future!";
assert_eq!(String::from_utf8_lossy(&from_string(&input)[..]), output);
}
}