//! # base_emoji
//!
//! Convert everything to Emojis (and back)!
//!
//! ๐ซ๐ฆ๐ฅ๐ฒ๐ฌ๐๐๐๐ฌ๐ฒ๐ฌ๐๐๐๐ง๐๐ฅ๐ช๐๐๐ฆ๐๐๐ฃ๐ฆ๐๐๐ค๐
//!
//! Reimplementation of [base_emoji](https://github.com/pfrazee/base-emoji) (JavaScript).
//!
//! ## Example
//!
//! ```rust
//! let input = [0xde, 0xad, 0xbe, 0xef];
//! let output = "โ๏ธ๐ผ๐๐
";
//!
//! assert_eq!(base_emoji::to_string(&input), output);
//! ```
//!
//! ## Encoding (same as original implementation)
//!
//! Citing [the README](https://github.com/pfrazee/base-emoji/blob/04b6c1e24ae5071804285cb358162628ea4a9bc8/README.md):
//!
//! > The emojis used are in `emojis.json`. There are 843 emojis there, but the
//! > converter reads sequences of 8 bits at a time, and so only maps the value to
//! > the first 256 of them. To stay consistent with other renderings, make sure you
//! > don't change the order of your emojis.json.
//!
//! ## Decoding
//!
//! Decoding requires the use of only the same 256 emojis used above.
//!
//! ## License
//!
//! MIT. See included `LICENSE` file.
extern crate phf;
extern crate unicode_segmentation;
include!(concat!(env!("OUT_DIR"), "/emojis.rs"));
#[derive(Debug)]
pub enum Error {
/// An invalid emoji was attempted to be decoded
InvalidEmoji,
}
/// Decode a base-emoji string slice to a vector of u8's
///
/// Returns an [`Error`] if the provided emojis could not be decoded
///
/// ```rust
/// let input = "โ๏ธ๐ผ๐๐
";
/// let output = [0xde, 0xad, 0xbe, 0xef];
///
/// assert_eq!(base_emoji::try_from_str(&input).unwrap().as_slice(), &output);
/// ```
pub fn try_from_str<T: AsRef<str>>(buf: T) -> Result<Vec<u8>, Error> {
use unicode_segmentation::UnicodeSegmentation;
buf.as_ref()
.graphemes(true)
.map(|c| {
EMOJIS_REVERSE
.get(c)
.map_or(Err(Error::InvalidEmoji), |b| Ok(*b))
})
.collect()
}
/// Encode buffer as a base-emoji string
///
/// ```rust
/// let input = [0xde, 0xad, 0xbe, 0xef];
/// let output = "โ๏ธ๐ผ๐๐
";
///
/// assert_eq!(base_emoji::to_string(&input), output);
/// ```
pub fn to_string<T: AsRef<[u8]>>(buf: T) -> String {
buf.as_ref()
.iter()
.map(|c| EMOJIS.get(c).unwrap().0)
.collect::<Vec<_>>()
.concat()
}
/// Encode buffer as a base-emoji buffer
///
/// ```rust
/// let input = [0xde, 0xad, 0xbe, 0xef];
/// let output = "โ๏ธ๐ผ๐๐
".as_bytes();
///
/// assert_eq!(base_emoji::to_bytes(&input), output);
/// ```
pub fn to_bytes<T: AsRef<[u8]>>(buf: T) -> Vec<u8> {
to_string(buf).into_bytes()
}
/// Encode buffer as a string of emoji names
///
/// ```rust
/// let input = [0xde, 0xad, 0xbe, 0xef];
/// let output = ":snowflake::panda_face::police_car::tongue:";
/// assert_eq!(base_emoji::to_names(&input), output);
/// ```
pub fn to_names<T: AsRef<[u8]>>(buf: T) -> String {
to_custom(buf, |_, name| format!(":{}:", name))
}
/// Encode buffer as custom-mapped string
///
/// ```rust
/// let input = [0xde];
/// let output = "<img src='/img/snowflake.png' alt='โ๏ธ' title='snowflake'>";
/// assert_eq!(
/// base_emoji::to_custom(&input, |ch, name| {
/// format!("<img src='/img/{}.png' alt='{}' title='{}'>",
/// name, ch, name)
/// }),
/// output);
/// ```
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::*;
#[test]
fn long() {
let res = "๐ฏ๐ข๐๐๐ฑ๐
ฐ๐กโ๏ธ๐ฝ๐โ๏ธ๐ผ๐ข๐ ๐๐โฌ๏ธโฌ
๏ธโก๏ธโฌ๏ธ๐จ๐ง๐ถ๐ผ๐๐๐โผ๏ธ๐๐๐๐๐๐ป๐๐บ๐๐๐ด๐๐๐๐ผ๐๐๐๐โต๏ธ๐ฃ๐๐๐ฅ๐ข๐๐ณ๐ฆ๐๐ฐ๐ผ๐๐๐ก๐๐ค๐ต๐ฐ๐๐ซ๐ฌ๐๐๐ฟ๐๐๐๐ซ๐๐๐ฌโ๏ธ๐ธโ๏ธ๐ป๐๐ง๐ช๐ฝ๐ซ๐๐๐๐ฎ๐๐๐๐ฏ๐จ๐ณ๐ซ๐๐ต๐ฌ๐ฉ๐ช๐ง๐๐๐๐๐ฃ๐ฅ๐ฆ๐พ๐๐๐ค๐๐ธ๐ฒ๐๐ป๐๐โณ๏ธ๐๐๐ธ๐ซ๐๐จ๐๐ฃ๐ฟ๐๐ ๐ดโ๏ธ๐จ๐๐๐๐จ๐๐๐๐ข๐๐ซ๐๐ฃ๐๐ค๐ฌ๐ฐ๐๐๐๐ฅ๐ช๐๐น๐ต๐๐ฐ๐โ๏ธ๐ซ๐๐ฉ๐๐๐๐๐ผโ
๏ธ๐พ๐๐๐ง๐ญโ๏ธ๐๐ฝ๐๐๐๐๐๐๐๐๐ฉ๐ฉ๐ฏ๐๐๐๐๐๐๐ป๐๐๐๐๐๐๐น๐จ๐๐๐
๐ก๐ทโ๏ธ๐๐๐ฟ๐๐๐๐โ๏ธโ๏ธ๐ญโฝ๏ธ๐๐พ๐ฌโญ๏ธ๐๐๐ฆ๐๐๐ญ๐พ๐ญ๐ฝ๐
๐ฉ๐ฅ๐๐บ๐ข๐ฆ๐ผ๐ฎ๐ปโ๏ธ๐๐ท๐บ๐งโก๏ธ๐ค";
let input = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d,
0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b,
0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1,
0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed,
0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
0xfc, 0xfd, 0xfe, 0xff,
];
assert_eq!(to_string(&input[..]), res);
}
#[test]
fn from_string() {
let input = "Convert everything to Emojis.";
let output = "๐ซ๐ฆ๐ฅ๐ฒ๐ฌ๐๐๐๐ฌ๐ฒ๐ฌ๐๐๐๐ง๐๐ฅ๐ช๐๐๐ฆ๐๐๐ฃ๐ฆ๐๐๐ค๐";
assert_eq!(to_string(input), output);
}
#[test]
fn there_and_back_again_single() {
for i in 0..=255 {
let s1 = &[i as u8];
let s2 = to_string(s1);
let s3 = try_from_str(&s2).unwrap();
assert_eq!(s1, &s3[..]);
}
}
#[test]
fn there_and_back_again_all() {
let input = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d,
0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b,
0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1,
0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed,
0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
0xfc, 0xfd, 0xfe, 0xff,
];
let encoded = to_string(&input[..]);
let output = try_from_str(&encoded).unwrap();
assert_eq!(&input[..], &output[..]);
}
}