emojis

O(1) emoji lookup, metadata, and GitHub shortcode matching for Rust, backed by static Unicode data.

Library
Cargo
v0.9.0
78stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
49/100Fair
Development Activity60
Maintenance20
Community36
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
88/100Excellent
Architecture88
Code Quality92
Innovation87
Learning Curve85

emojis is a small, no_std Rust crate that lets you look up emoji by Unicode value or by GitHub-style shortcode (:rocket:) in constant time, then read back rich metadata: CLDR name, Unicode emoji group, emoji/Unicode spec version, skin tone, and gemoji shortcodes. All of the underlying data is generated at build time from the Unicode emoji specification and the gemoji dataset and compiled directly into the binary as static perfect-hash tables, so there is no parsing, network access, or heap allocation involved in a lookup.

The crate is aimed at anyone building text-processing tools that need to understand emoji as first-class data rather than opaque Unicode sequences: chat clients normalizing :shortcode: syntax into real glyphs, linters or formatters that need to strip or count emoji, or CLI tools (like the crate’s own examples/replace.rs) that substitute gemoji names for their rendered characters. Its narrow, well-documented API and complete doctest coverage make it easy to drop into an existing project with a single cargo add emojis.

What You Get

  • Constant-time lookups - get("🚀") and get_by_shortcode("rocket") both resolve via generated phf perfect-hash maps in O(1) time.
  • Rich per-emoji metadata - name, Group (e.g. Smileys & Emotion, Flags), EmojiVersion, UnicodeVersion, and SkinTone are all available as typed accessors on Emoji.
  • Skin tone variant handling - skin_tones() iterates every skin-tone variant of an emoji, and with_skin_tone()-style lookups let you select a specific tone.
  • Full emoji iteration - iter() walks every default-skin-tone emoji in Unicode CLDR order, filterable by unicode_version() to target a specific Unicode release.
  • Group-scoped iteration - Group::FoodAndDrink.emojis() and similar let you iterate just the emoji in one CLDR category.
  • Optional serde support - the serde feature derives Serialize/Deserialize for &'static Emoji and the version/group/skin-tone types without imposing the dependency by default.

Common Use Cases

  • Shortcode-to-emoji rendering - chat apps, forums, or Markdown renderers converting :tada:-style gemoji shortcodes typed by users into real Unicode emoji.
  • Emoji-aware text processing - linters, formatters, or content moderation tools that need to detect, classify, or strip emoji from arbitrary text.
  • Unicode-version-gated emoji pickers - building an emoji picker UI that only shows emoji supported by a target platform’s Unicode version.
  • Skin-tone selection UI - implementing a skin-tone selector for a chat or social app by iterating skin_tones() for a chosen emoji.
  • CLI and scripting utilities - the crate’s own examples/replace.rs shows a stdin-to-stdout filter that expands gemoji shortcodes, a pattern reusable for git hooks or changelog generators.

Under The Hood

Architecture emojis is a no_std single-purpose crate with a companion generate workspace member (generate/src/main.rs, generate/src/unicode/*.rs, generate/src/github.rs) that runs offline to scrape the Unicode emoji specification and the gemoji shortcode dataset, then emits three generated files into src/gen/ (mod.rs’s flat EMOJIS static slice, unicode.rs’s phf::Map, shortcode.rs’s phf::Map) that are checked into the repository and marked “DO NOT EDIT.” At runtime the shipped crate does nothing but two O(1) phf::Map lookups — get() indexes gen::unicode::MAP and then the flat gen::EMOJIS slice by position, get_by_shortcode() does the same via gen::shortcode::MAP — returning &'static Emoji references with no allocation. This is an unusually clean split: all ingestion complexity lives in the generate workspace member and never ships to consumers, while the published crate is a single flat module plus its generated gen/ directory. Skin-tone relationships are encoded positionally as (id, count, tone) index triples into the EMOJIS slice rather than as pointers, so changing the core Emoji struct’s layout requires regenerating all three generated files together.

Tech Stack Written in Rust (edition 2021, MSRV 1.66), #![no_std] with alloc only under #[cfg(test)]. Runtime dependencies are minimal: phf 0.13 (default-features disabled) for the perfect-hash maps, plus an optional serde 1.0 (with derive) gated behind a serde feature so non-serde consumers pay nothing. Dev-dependencies (serde_json, toml) support the test suite. The generate workspace member is a separate, unpublished internal tool with its own dependency tree for fetching Unicode/gemoji source data, isolated from the published crate’s dependency graph entirely. CI (.github/workflows/build.yaml) runs rustfmt --check, cargo clippy --workspace --all-targets --all-features, and cargo test (including --doc) across stable, beta, and nightly toolchains, plus separate msrv-check (1.66) and msrv-test (1.85) jobs, all under RUSTFLAGS=--deny warnings.

Code Quality tests/smoke.rs (212 lines) and tests/serde.rs (79 lines) cover equality, ordering, unqualified/variation-sequence normalization, default-skin-tone-only iteration, and serde round-tripping; nearly every public method in src/lib.rs additionally carries a runnable doctest exercised by cargo test --doc in CI, so documentation and coverage overlap substantially. The public API is Option-based and panic-free (get/get_by_shortcode return Option<&'static Emoji>), naming follows CLDR/Unicode terminology consistently throughout, and typing is deliberately strong — Group and SkinTone are enums rather than raw integers (SkinTone is #[non_exhaustive] to allow future additions without a breaking change), and UnicodeVersion/EmojiVersion are dedicated comparable structs instead of bare tuples. CI enforces rustfmt, clippy across all targets and features, and both an MSRV check and MSRV test job in addition to the stable/beta/nightly matrix — a notably rigorous setup for a data-oriented crate of this size.

API Design The public surface is deliberately tiny and memorable: two free functions (get, get_by_shortcode) and one iterator entry point (iter()), with everything else discovered through methods on the returned &'static Emoji (name(), group(), skin_tone(), skin_tones(), unicode_version(), emoji_version(), shortcode()/shortcodes()). Getting started requires no boilerplate beyond cargo add emojis and a single call. The crate intentionally withholds Clone, Copy, and any public constructor from Emoji, steering consumers toward holding &'static Emoji references rather than owned copies — a choice explained directly in the README’s “Storing the Emoji type” section rather than left implicit. Every public item ships a doctested usage example, and the optional serde feature is fully opt-in. The one real friction point is that the internal skin-tone encoding is invisible from the API, so understanding default-vs-variant skin-tone semantics requires reading the docs rather than being self-evident from the type signatures alone.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search