iri-rs 3.3.4

Allocation-conscious URI/IRI (RFC 3986/3987) parser, resolver and normalizer with borrowed and owned types, optional compile-time macros and vocabulary enums.
Documentation

iri-rs

Crate Docs MSRV License

An allocation-conscious Rust implementation of URIs and IRIs (RFC 3986 / RFC 3987) — parse, access components, mutate in-place, resolve references, normalize, compare.

A URI/IRI is a sequence of characters split into distinguishable components:

  foo://user@example.com:8042/over/there?name=ferret#nose
  └┬┘   └──────────┬────────┘└────┬────┘└────┬─────┘└┬─┘
   │               │              │          │       │
 scheme        authority          path      query  fragment

This crate gives you typed borrowed and owned views over each of them.

use iri_rs::Iri;

let iri = Iri::parse("https://www.rust-lang.org/foo/bar?query#frag")?;
assert_eq!(iri.scheme(), "https");
assert_eq!(iri.authority(), Some("www.rust-lang.org"));
assert_eq!(iri.path(), "/foo/bar");
assert_eq!(iri.query(), Some("query"));
assert_eq!(iri.fragment(), Some("frag"));

Mutate in place, no per-component allocations:

use iri_rs::IriBuf;

let mut iri = IriBuf::new("https://rust-lang.org")?;
iri.set_authority(Some("rust-lang.org:40"))?;
iri.set_path("/foo/bar")?;
iri.set_query(Some("q"))?;
assert_eq!(iri, "https://rust-lang.org:40/foo/bar?q");

Why this fork

Fork of iref, static-iref, and iref-enum by Timothée Haudebourg. Public API and RFC behavior largely unchanged; this fork adds:

  • Workspace split into iri-rs-core, iri-rs-static, iri-rs-enum under the iri-rs facade.
  • Reworked IriEnum derive (iri-rs-enum) — compile-time prefix resolution, const-friendly output via from_raw_parts.
  • Reworked compile-time macros (iri!, uri!, iri_ref!, uri_ref!) — validate at macro expansion, emit const-friendly from_raw_parts with pre-computed component positions.
  • SIMD-accelerated UTF-8 validation via simdutf8, memchr-accelerated percent scan, SWAR/byte-level fast paths on new, eq, ord, hash, len.
  • Opt-in fast-hash feature for hashing without re-parsing.
  • Criterion bench suite (parse, accessors, resolve, normalize, mutate, normalize_eq, validate).
  • Rust 2024 edition, MSRV 1.85.
  • Renamed crates: irefiri-rs, static-irefiri-rs-static, iref-enumiri-rs-enum.

Credit and history preserved — see Attribution.

Install

cargo add iri-rs

Feature flags

Flag Default Enables
static Compile-time iri!, uri!, iri_ref!, uri_ref! macros
enum #[derive(IriEnum)] for vocabulary enums
serde Serialize / Deserialize for borrowed and owned types
fast-hash Skip re-parse on Hash — trades stricter invariants for speed

Compile-time IRIs

With static, IRIs are validated at macro expansion and emitted as const expressions — zero runtime parsing, zero allocation:

use iri_rs::{Iri, iri};

const HOME: Iri<&'static str> = iri!("https://www.rust-lang.org/");

Invalid literals fail to compile. Same for uri!, iri_ref!, uri_ref!.

Vocabulary enums

With enum, map a known vocabulary to a plain enum — cheap storage and comparison, compile-time prefix resolution:

use iri_rs::{iri, IriEnum};

#[derive(IriEnum, PartialEq, Debug)]
#[iri_prefix("schema" = "https://schema.org/")]
pub enum Vocab {
    #[iri("schema:name")] Name,
    #[iri("schema:knows")] Knows,
}

let term = Vocab::try_from(&iri!("https://schema.org/name")).unwrap();
assert_eq!(term, Vocab::Name);

References and resolution

IriRef / IriRefBuf cover absolute and relative references. A strict implementation of the RFC 3986 §5 reference resolution algorithm with Errata 4547:

use iri_rs::{Iri, IriRefBuf};

let base = Iri::parse("http://a/b/c/d;p?q")?;
let mut r = IriRefBuf::new("g;x=1/../y")?;
assert_eq!(r.resolved(&base)?, "http://a/b/c/y");

r.resolve(&base)?;
assert_eq!(r, "http://a/b/c/y");

Equivalence

Equality, ordering and hashing normalize:

  • Dot segmentsa/../a/./b/../b/ca/b/c.
  • Percent encodinghttp://example.orghttp://exa%6dple.org (via pct).
  • Protocol-agnostichttp://example.org and http://example.org:80 are not equal. This crate knows nothing about scheme defaults.
  • Every / counts/foo/bar and /foo/bar/ are not equal.

Two values whose as_str() differs can still hash equal — keep that in mind when used as map keys.

Examples

cargo run --example serde --features serde

Benchmarks

cargo bench -p iri-rs-core

Criterion output: target/criterion/.

MSRV

Rust 1.85 (edition 2024).

Workspace layout

  • iri-rs — facade crate. Re-exports everything behind feature flags. Start here.
  • iri-rs-core — types, parser, resolver, normalizer.
  • iri-rs-staticiri! / uri! / iri_ref! / uri_ref! compile-time macros.
  • iri-rs-enum#[derive(IriEnum)] for vocabulary enums.

Attribution

Original crates: iref, static-iref, and iref-enum by Timothée Haudebourg. Upstream commits are preserved in this repo's history under their original authorship. This fork is a workspace reorganization and a layer of performance work on top of the original design.

License

Dual-licensed, same as upstream. Pick whichever fits: