idna_adapter

A pinned Unicode back end abstraction that lets Cargo choose ICU4X, unicode-rs, or a no-op stub for the idna crate.

Library
Cargo
v1.2.2
6stars
Apache-2.0 OR MIT

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
16/100Needs Attention
Development Activity12
Maintenance0
Community8
Maturity44
Momentum0

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
52/100Fair
Architecture78
Code Quality40
Innovation55
Learning Curve35

idna_adapter is a small, no_std Rust crate that works around a specific Cargo limitation: the lack of global, workspace-wide feature selection. It sits between the idna crate and one of several interchangeable Unicode back ends, letting a top-level application’s Cargo.lock pin exactly which back end gets compiled in via cargo update -p idna_adapter --precise <version>, without idna itself needing to expose that choice as a public feature flag.

Because IDNA (Internationalized Domain Name) processing depends on Unicode normalization, bidi classification, and joining-type data, any implementation needs a concrete data source. idna_adapter exposes a minimal Adapter type with normalization and Unicode property lookups, backed by whichever version stream is pinned: 1.2.x uses ICU4X, 1.1.x uses unicode-rs, and 1.0.x is a stub with no Unicode data at all, trading off compile time, binary size, and runtime performance depending on the choice.

What You Get

  • Version-pinned back end selection - Cargo.lock pins to the 1.2.x (ICU4X), 1.1.x (unicode-rs), or 1.0.x (no-op stub) stream without idna needing a public feature flag.
  • UTS 46 normalization - map_normalize and normalize_validate delegate directly to icu_normalizer’s UTS 46 mapper for domain label normalization.
  • Unicode property masks - precomputed bitmasks for bidi classes and joining types used by IDNA’s bidi-domain and Arabic joining-type validation rules.
  • no_std compatibility - zero std dependency, keeping the crate usable anywhere idna itself needs to run.

Common Use Cases

  • Domain name validation - libraries like idna and url use it internally to normalize and validate internationalized domain names per UTS 46.
  • Binary-size-conscious builds - projects needing a smaller footprint pin the unicode-rs or stub version streams instead of ICU4X.
  • Reproducible Unicode data versions - teams that need deterministic domain-name behavior pin an exact idna_adapter version to lock in a specific Unicode Consortium data snapshot.
  • Opting out of IDNA support - applications that intentionally want to reject non-ASCII domains pin to the 1.0.x stub.

Under The Hood

Architecture The crate is a single 279-line lib.rs acting as a thin facade: an Adapter struct wraps icu_normalizer’s Uts46MapperBorrowed plus three icu_properties::CodePointMapDataBorrowed lookups (GeneralCategory, BidiClass, JoiningType), and newtype wrappers (BidiClass, JoiningType, and their *Mask counterparts) constrain callers to the exact operations idna needs — intersecting precomputed masks rather than exposing raw ICU4X enums. Because idna is the sole consumer and the public surface is deliberately minimal, a change to Adapter’s methods would break idna directly, but the facade’s narrowness is what makes the version-stream-swap trick (Cargo.lock pinning a different idna_adapter version to change the underlying implementation) work at all.

Tech Stack Pure Rust, no_std, targeting the 2024 edition with an MSRV of 1.86. It depends on icu_normalizer 2.2 and icu_properties 2.2 with default-features = false, gated behind an optional compiled_data feature that embeds Unicode data directly into the binary via a const fn constructor. There is no build tooling beyond Cargo and no external services or integrations — it is published to crates.io as a dependency-only crate.

Code Quality No test files, tests/ directory, or CI configuration are present in the repository; correctness is presumably validated indirectly through idna’s own test suite and downstream users of the url crate. What the crate does lean on is Rust’s type system: #[repr(transparent)] newtypes and mask types prevent bidi-class and joining-type values from being conflated with raw integers, and const fn mask construction pushes some validation to compile time. Naming is consistent and closely mirrors Unicode/UTS 46 terminology throughout.

API Design The public API is deliberately tiny — six methods on Adapter (is_virama, is_mark, bidi_class, joining_type, map_normalize, normalize_validate) that map one-to-one onto what idna needs, each documented with a link to the underlying icu_normalizer/icu_properties method it wraps. Getting started requires zero configuration when the default compiled_data feature is enabled (Adapter::new() is a const fn). The unusual part of the DX is that most consumers never call this API directly at all — the primary interaction is cargo update -p idna_adapter --precise <version> to select a back end, a pattern explained only in the top-level README rather than in any inline documentation.

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