Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

iri-rfc3987

Crates.io Documentation CI License: MIT OR Apache-2.0 Downloads

Zero-copy parsing, validation, and resolution for Internationalized Resource Identifiers (IRIs), based on RFC 3987 and RFC 3986.

Why this crate

IRIs are structured identifiers, not arbitrary strings. Parsing at the boundary lets applications reject malformed values early while retaining the original text and avoiding an allocation when the input is already borrowed.

iri-rfc3987 keeps the public API deliberately small:

  • parsing is explicit and fallible;
  • borrowed and owned forms use the same generic types;
  • relative references can be resolved against an absolute base;
  • parse and resolution failures are typed and carry useful context;
  • URI-only types and builder APIs are outside the scope of this crate.

The crate provides two validated types:

  • Iri<T> for an absolute IRI with a required scheme.
  • IriRef<T> for an IRI reference, including relative references.

Both types support borrowed parsing with &str and owned storage with String:

use iri_rfc3987::{Iri, IriRef};

let iri = Iri::parse("https://example.org/resource")?;
assert_eq!(iri.as_str(), "https://example.org/resource");

let reference = IriRef::parse("../other")?;
assert!(!reference.has_scheme());
# Ok::<(), iri_rfc3987::IriParseError>(())

Borrowed and owned values

Parsing an &str produces a zero-copy Iri<&str> or IriRef<&str>. Convert to an owned value only when it must outlive the source string:

use iri_rfc3987::{Iri, IriRef};

let borrowed: Iri<&str> = Iri::parse("https://example.org/resource")?;
let owned: Iri<String> = borrowed.to_owned();
assert_eq!(owned.as_str(), "https://example.org/resource");

let reference: IriRef<String> = IriRef::parse_owned("../other".to_owned()).unwrap();
assert_eq!(reference.as_str(), "../other");
# Ok::<(), iri_rfc3987::IriParseError>(())

Resolving references

IriRef accepts absolute and relative references. Resolution follows the path-merging rules from RFC 3986:

use iri_rfc3987::{Iri, IriRef};

let base = Iri::parse("https://example.org/a/b/").unwrap();
let reference = IriRef::parse("../image.svg").unwrap();
let resolved = reference.resolve_against(&base).unwrap();

assert_eq!(resolved.as_str(), "https://example.org/a/image.svg");

An absolute reference is returned as its own resolved IRI, while an empty or relative reference inherits the appropriate components from the base. A base with a fragment and invalid opaque-base combinations are rejected with a typed ResolveError.

Validation errors

Parsing never silently accepts an invalid value. IriParseError::index identifies the byte position where validation stopped:

use iri_rfc3987::Iri;

let error = Iri::<&str>::parse("not an absolute iri").unwrap_err();
assert_eq!(error.index(), 3);
# Ok::<(), iri_rfc3987::IriParseError>(())

For a known compile-time constant, Iri::known is available when a panic is preferable to carrying a construction error:

use iri_rfc3987::Iri;

let rdf_type = Iri::known("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
assert_eq!(rdf_type.as_str(), "http://www.w3.org/1999/02/22-rdf-syntax-ns#type");

Serde

Iri and IriRef serialize as their validated string representation and validate again when deserialized:

use iri_rfc3987::Iri;

let iri = Iri::parse_owned("https://example.org/resource".to_owned()).unwrap();
let encoded = serde_json::to_string(&iri)?;
let decoded: Iri<String> = serde_json::from_str(&encoded)?;

assert_eq!(decoded, iri);
# Ok::<(), Box<dyn std::error::Error>>(())

API overview

Type Purpose
Iri<T> Absolute IRI with a required scheme.
IriRef<T> Absolute or relative IRI reference.
IriParseError Typed parse failure with a byte index.
ResolveError Typed failure while resolving a reference.
TryIntoIri Fallible conversion into Iri<String>.

The implementation retains the IRI-specific portion of the parser adapted from fluent-uri 0.4.1. URI-only types and builder APIs are intentionally not included.

License

Copyright © 2026 DataRoad Inc, Delaware, USA, trading as Legra.

Licensed under either of:

at your option.

About

Zero-copy RFC 3987 IRI parsing and resolution for Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages