sorug
sorug is an ultra-high-performance, zero-copy, WHATWG URL Living Standard-compliant URL parser written in Rust. It targets production parsers that need correctness and nanosecond-scale throughput — and currently outperforms both servo/rust-url and ada-url on the hot paths that matter.
Why sorug?
| Pillar | What it means |
|---|---|
| Zero-Copy | Canonical ASCII inputs stay borrowed (Backing::Borrowed); heap allocation only on first required mutation (CoW). |
| SIMD / SWAR | 64-bit scheme-prefix jumps + SWAR delimiter scans for short inputs; memchr for longer buffers. |
| Custom Punycode | In-crate Punycode + UTS #46 mapping; membership tables from vendored Unicode UCD (data/ucd/) + idna_overlay.txt — no ICU/idna runtime dep. |
| 891 / 891 WPT | Full pass of the Web Platform Tests urltestdata suite shipped in-tree. |
| 278 / 278 setters | Full pass of WPT setters_tests.json (component mutators). |
forbid(unsafe_code) |
Zero unsafe in library code. Correctness first; speed without memory-safety shortcuts. |
no_std + alloc |
Embedded / WASM friendly (default-features = false). |
Benchmarks
Criterion, Linux, release profile (lto = true, codegen-units = 1). Lower is better (nanoseconds / parse). Measured 2026-08-04.
| Workload | sorug | ada-url | servo/url |
|---|---|---|---|
Fast Path ASCII (https://example.com/api/v1/users) |
32.7 ns | 31.2 ns | 96.5 ns |
| Complex Query / Fragment | 55.6 ns | 140 ns | 199 ns |
| IDNA / Punycode | 190 ns | 244 ns | 226 ns |
| File Edge Case | 31.2 ns | 91.7 ns | 126 ns |
Reproduce locally:
Numbers are indicative. Absolute values vary by CPU; relative ordering is what we track. IDNA uses an in-tree UTS #46 path with a Latin-1/CJK/kana/Hangul identity fast path; membership tables are built from vendored Unicode UCD (no ICU/
idnacrate).
Quick start
[]
= "0.3"
use Url;
Relative resolution with join / make_relative:
use Url;
let base = parse?;
let joined = base.join?;
assert_eq!;
let target = parse?;
assert_eq!;
Mutate components (WHATWG / WPT setters) and edit the query as form-urlencoded pairs:
use ;
let mut url = parse?;
url.set_pathname;
url.set_search;
assert_eq!;
let mut params = parse;
params.append;
url.set_search_params;
assert_eq!;
Features
| Feature | Default | Purpose |
|---|---|---|
std |
yes | [std::error::Error] for ParseError; memchr std backend |
serde |
no | Serialize / deserialize Url as an href string |
http |
no | Convert between Url and http::Uri (implies std) |
# no_std + alloc
= { = "0.3", = false }
# with serde
= { = "0.3", = ["serde"] }
# with http::Uri bridge
= { = "0.3", = ["http"] }
http feature example:
use Uri;
use Url;
let url = parse.unwrap;
let uri: Uri = url.to_uri.unwrap;
let back = uri_to_url.unwrap;
assert_eq!;
Git dependency (tracking main):
[]
= { = "https://github.com/hocestnonsatis/sorug" }
Current Status & Roadmap
Today (0.3.0 on crates.io)
- Relative URL ops:
join/make_relative/path_segments/path_segments_mut/query_pairs(_mut). - Typed
Host(+Host::parse), rust-url-shaped getters (authority,domain,port, …),Hash/Ord, optionalserde/http,no_std+alloc. - IDNA: in-tree Punycode + UTS #46; membership tables from vendored Unicode UCD 16.0.0 +
data/idna_overlay.txt(Node/WPT). - WPT parser: 891 / 891; WPT setters: 278 / 278.
- Docs: docs.rs/sorug.
Next
- Continue refining toward a future
1.0(no API freeze yet). - Differential fuzzing against rust-url where intentional divergences are documented.
C FFI
Optional C bindings live in ffi/ (sorug-ffi, workspace member, not on crates.io yet). The main crate stays forbid(unsafe_code); the FFI package is the C ABI boundary (cdylib / staticlib). See ffi/README.md.
Not goals (for now)
- Matching every historical quirk of non-WHATWG parsers.
- Trading
forbid(unsafe_code)for micro-wins.
Design sketch
- Index-based record — component boundaries are
u32offsets into the WHATWGhrefserialization. - Lazy / CoW serialization — borrow when input is already canonical; upgrade to owned on mutation.
- Strict state machine — transitions follow the URL Living Standard basic URL parser.
Testing
See CONTRIBUTING.md for policies, style, and review expectations.
License
Licensed under either of
at your option.
Code of Conduct
Participation is governed by our Code of Conduct.