#![no_std]
#[cfg(test)]
extern crate alloc;
mod gen;
use core::cmp;
use core::convert;
use core::fmt;
use core::hash;
pub use crate::gen::Group;
#[derive(Debug)]
pub struct Emoji {
emoji: &'static str,
name: &'static str,
unicode_version: UnicodeVersion,
group: Group,
skin_tone: Option<(u16, u8, SkinTone)>,
aliases: Option<&'static [&'static str]>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UnicodeVersion {
major: u32,
minor: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub enum SkinTone {
Default,
Light,
MediumLight,
Medium,
MediumDark,
Dark,
LightAndMediumLight,
LightAndMedium,
LightAndMediumDark,
LightAndDark,
MediumLightAndLight,
MediumLightAndMedium,
MediumLightAndMediumDark,
MediumLightAndDark,
MediumAndLight,
MediumAndMediumLight,
MediumAndMediumDark,
MediumAndDark,
MediumDarkAndLight,
MediumDarkAndMediumLight,
MediumDarkAndMedium,
MediumDarkAndDark,
DarkAndLight,
DarkAndMediumLight,
DarkAndMedium,
DarkAndMediumDark,
}
impl UnicodeVersion {
#[inline]
pub const fn new(major: u32, minor: u32) -> Self {
Self { major, minor }
}
#[inline]
pub const fn major(self) -> u32 {
self.major
}
#[inline]
pub const fn minor(self) -> u32 {
self.minor
}
}
impl Emoji {
#[inline]
pub const fn as_str(&self) -> &str {
self.emoji
}
#[inline]
pub const fn as_bytes(&self) -> &[u8] {
self.emoji.as_bytes()
}
#[inline]
pub const fn name(&self) -> &str {
self.name
}
#[inline]
pub const fn unicode_version(&self) -> UnicodeVersion {
self.unicode_version
}
#[inline]
pub const fn group(&self) -> Group {
self.group
}
#[inline]
pub fn skin_tone(&self) -> Option<SkinTone> {
self.skin_tone.map(|(_, _, v)| v)
}
#[inline]
pub fn skin_tones(&self) -> Option<impl Iterator<Item = &Self> + Clone> {
let (i, n, _) = self.skin_tone?;
Some(crate::gen::EMOJIS[i as usize..].iter().take(n as usize))
}
#[inline]
pub fn with_skin_tone(&self, skin_tone: SkinTone) -> Option<&Self> {
self.skin_tones()?
.find(|emoji| emoji.skin_tone().unwrap() == skin_tone)
}
#[inline]
pub fn shortcode(&self) -> Option<&str> {
self.aliases.and_then(|aliases| aliases.first().copied())
}
#[inline]
pub fn shortcodes(&self) -> impl Iterator<Item = &str> + Clone {
self.aliases.into_iter().flatten().copied()
}
}
impl cmp::PartialEq<Emoji> for Emoji {
#[inline]
fn eq(&self, other: &Emoji) -> bool {
self.emoji == other.emoji
}
}
impl cmp::PartialEq<str> for Emoji {
#[inline]
fn eq(&self, s: &str) -> bool {
self.as_str() == s
}
}
impl cmp::PartialEq<&str> for Emoji {
#[inline]
fn eq(&self, s: &&str) -> bool {
self.as_str() == *s
}
}
impl cmp::Eq for Emoji {}
impl hash::Hash for Emoji {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.emoji.hash(state);
}
}
impl convert::AsRef<str> for Emoji {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl convert::AsRef<[u8]> for Emoji {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl fmt::Display for Emoji {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for &'static Emoji {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for &'static Emoji {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = &'static Emoji;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str("a string representing an emoji")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
crate::get(value).ok_or_else(|| E::custom("invalid emoji"))
}
}
deserializer.deserialize_str(Visitor)
}
}
impl Group {
#[inline]
pub fn iter() -> impl Iterator<Item = Group> + Clone {
[
Self::SmileysAndEmotion,
Self::PeopleAndBody,
Self::AnimalsAndNature,
Self::FoodAndDrink,
Self::TravelAndPlaces,
Self::Activities,
Self::Objects,
Self::Symbols,
Self::Flags,
]
.iter()
.copied()
}
#[inline]
pub fn emojis(&self) -> impl Iterator<Item = &'static Emoji> {
let group = *self;
iter()
.skip_while(move |emoji| emoji.group != group)
.take_while(move |emoji| emoji.group == group)
}
}
#[inline]
pub fn iter() -> impl Iterator<Item = &'static Emoji> + Clone {
crate::gen::EMOJIS
.iter()
.filter(|emoji| matches!(emoji.skin_tone(), Some(SkinTone::Default) | None))
}
#[inline]
pub fn get(s: &str) -> Option<&'static Emoji> {
crate::gen::unicode::MAP
.get(s)
.map(|&i| &crate::gen::EMOJIS[i])
}
#[inline]
pub fn get_by_shortcode(s: &str) -> Option<&'static Emoji> {
crate::gen::shortcode::MAP
.get(s)
.map(|&i| &crate::gen::EMOJIS[i])
}