{"id":29569195,"url":"https://github.com/vloldik/rlibphonenumber","last_synced_at":"2026-05-10T04:06:40.700Z","repository":{"id":304533018,"uuid":"1019101908","full_name":"vloldik/rlibphonenumber","owner":"vloldik","description":"A high-performance Rust port of Google's libphonenumber for parsing, formatting, and validating international phone numbers","archived":false,"fork":false,"pushed_at":"2026-02-27T12:07:19.000Z","size":9271,"stargazers_count":19,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-27T17:50:53.161Z","etag":null,"topics":["libphonenumber","parsing","phone-number","rust"],"latest_commit_sha":null,"homepage":"https://docs.rs/rlibphonenumber","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vloldik.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-07-13T18:32:40.000Z","updated_at":"2026-02-27T15:24:09.000Z","dependencies_parsed_at":"2025-10-02T07:25:03.542Z","dependency_job_id":null,"html_url":"https://github.com/vloldik/rlibphonenumber","commit_stats":null,"previous_names":["vloldik/rlibphonenumber"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/vloldik/rlibphonenumber","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vloldik%2Frlibphonenumber","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vloldik%2Frlibphonenumber/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vloldik%2Frlibphonenumber/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vloldik%2Frlibphonenumber/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vloldik","download_url":"https://codeload.github.com/vloldik/rlibphonenumber/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vloldik%2Frlibphonenumber/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29976272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T16:35:47.903Z","status":"ssl_error","status_checked_at":"2026-03-01T16:35:44.899Z","response_time":124,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["libphonenumber","parsing","phone-number","rust"],"created_at":"2025-07-19T01:38:34.025Z","updated_at":"2026-05-10T04:06:40.676Z","avatar_url":"https://github.com/vloldik.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rlibphonenumber v2\n\n[![Crates.io](https://img.shields.io/crates/v/rlibphonenumber.svg)](https://crates.io/crates/rlibphonenumber)\n[![Docs.rs](https://docs.rs/rlibphonenumber/badge.svg)](https://docs.rs/rlibphonenumber)\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![WASM Preview](https://img.shields.io/badge/Live-WASM_Preview-success.svg)](https://vloldik.github.io/rlibphonenumber-wasm/)\n\nA zero-allocation, high-performance Rust port of Google's `libphonenumber` library for parsing, formatting, extracting, and validating international phone numbers. \n\n**Used metadata version:** `latest-supported`  \n**Package version**: `2.0.1`\n**Base libphonenumber:** `9.0.8`  \n**Min supported Rust version:** `1.88.0`\n---\n\n## 🚀 What's New in v2 (Migration Guide \u0026 Breaking Changes)\n\nVersion 2 brings a completely redesigned core, shedding legacy implementations in favor of idiomatic, zero-cost Rust abstractions.\n\n*   **Migrated from `rust-protobuf` to `prost`**: The internal representation now uses `prost`, resulting in a smaller footprint, faster decoding, and more idiomatic Rust types.\n*   **Unified `parse` API with `Region` Enum**: `parse` and `parse_with_region` have been merged. The API **no longer accepts string slices** for regions. You must now pass a strictly typed `Region` enum (e.g., `Region::US`).\n*   **O(1) Branchless Region Parsing**: The `Region` enum is generated at compile-time using bitwise shifts (mapping 2-letter ASCII codes to 16-bit discriminants). Parsing `\"US\"` into `Region::US` now takes exactly 1 CPU cycle without a single `match` branch or `if/else`. Generating a string back is done via a zero-allocation, 4-byte stack structure (`RegionStr`).\n*   **Redesigned Public API Wrapper**: We implemented a custom procedural macro that generates a clean, infallible public API while keeping the complex generic and lifetime-heavy implementations completely internal.\n*   **AOT Metadata Validation**: Custom metadata is now strictly validated at compile time (checking lengths \u003c 64, compiling all regexes to prevent runtime panics).\n*   **Initialization Speedup**: Bootstrapping `PhoneNumberUtil::new()` is now **~10% faster**, taking only **~4.97 ms**.\n\n## ✨ Enterprise Features\n\n### 🔍 Streaming Matcher (Number Extraction)\n*   **Exact Grouping Leniency:** Validates not just the digits, but whether the user formatted the number exactly according to the country's telecom rules (e.g., rejecting `12-34-567-890` while accepting `(123) 456-7890`).\n*   **Extension Traits:** Simply call `\"Call +1 555-0199\".find_phone_numbers()` to start extracting.\n*   *Correctness:* The matcher has passed **500,000 iterations of Differential Fuzzing** directly against Google's C++ ICU implementation with zero mismatches.\n\n### 🛡️ Data Loss Prevention (Masking \u0026 Hashing)\nThe new `PhoneMaskUtil` is designed for GDPR/PII compliance in high-throughput environments:\n*   **Zero-Allocation Pipeline:** Uses a custom `LenWrite` trait to predict output lengths and write masked numbers or XML tokens directly into `stdout` or file buffers without heap allocations.\n*   **Cryptographic Hashing:** Supports `HMAC` and `SHA256` hashing directly into stack-allocated 64-byte arrays.\n*   **Smart Obfuscation:** Automatically detects and fully masks RFC3966 URIs and phone extensions, leaving only the requested digits visible (e.g., `***-***-1234`).\n\n## ⚙️ CI/CD \u0026 Dagger Pipelines\n\nThe repository is fully automated using **Dagger** (Infrastructure as Code). Our pipelines automatically:\n1. Fetch the latest `v9.0.x` XML metadata from Google.\n2. Compile and validate the regexes.\n3. Perform Differential Fuzzing against a compiled C++ container.\n4. Auto-bump crate versions.\n\n---\n\n## 📦 Installation \u0026 Feature Flags\n\nAdd `rlibphonenumber` to your `Cargo.toml`:\n\n```toml\n[dependencies]\nrlibphonenumber = \"2.0.1\"\n```\n\n### Available Features\n\n| Feature | Description | Default |\n|---|---|---|\n| `builtin_metadata` | Embeds the compiled `.bin` metadata into the binary. **Required for `global_static`.** | ✅ |\n| `global_static` | Enables the lazy-loaded global `PHONE_NUMBER_UTIL` and `FindNumberExt` string traits. | ✅ |\n| `regex` | Uses the standard `regex` crate for maximum speed. | ✅ |\n| `lite` | Uses `regex-lite`. Optimizes for binary size (ideal for WASM/Embedded). | ❌ |\n| `digest` | Enables cryptographic hashing of phone numbers (e.g., SHA256) into stack buffers. | ❌ |\n| `digest_mac` | Enables keyed hashing (HMAC) for phone numbers. Depends on `digest`. | ❌ |\n| `serde` | Enables `Serialize`/`Deserialize` for `PhoneNumber`. | ❌ |\n\n---\n\n## 🛠️ CLI \u0026 Custom Metadata Management\n\n`rlibphonenumber` includes a powerful CLI for masking files on the fly and compiling custom metadata (e.g., filtering out pager rules via CEL expressions to shrink binary size).\n\n📖 **[Read the dedicated CLI Documentation here.](./crates/rlibphonenumber_cli/Readme.md)**\n\n---\n\n## 🚀 Getting Started\n\n### Parsing \u0026 Formatting\n```rust\nuse rlibphonenumber::{PHONE_NUMBER_UTIL, PhoneNumber, PhoneNumberFormat, enums::Region};\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    // 1. Parse the number (v2 requires the Region enum)\n    let number = PHONE_NUMBER_UTIL.parse(\"555-0199\", Some(Region::US))?;\n\n    // 2. Validate\n    if number.is_valid() {\n        // 3. Format\n        println!(\"E.164: {}\", number.format_as(PhoneNumberFormat::E164)); // +15550199\n    }\n\n    Ok(())\n}\n```\n\n### Finding Numbers in Text (Matcher)\n```rust\nuse rlibphonenumber::phonenumber_matcher::FindNumberExt;\n\nfn main() {\n    let text = \"Contact us at +1 (202) 555-0173 or drop a fax at 020 7183 8750.\";\n    \n    // Extension trait directly on \u0026str\n    for match_result in text.find_phone_numbers() {\n        println!(\"Found: {} at index {}\", match_result.number, match_result.start);\n    }\n}\n```\n\n### High-Performance Masking \u0026 Hashing\n*(Requires `digest_mac` feature)*\n```rust\nuse rlibphonenumber::{PHONE_NUMBER_UTIL, phonenumber_mask::{PhoneMaskUtil, MaskDigitsConfig, PhoneMacHasher}};\nuse hmac::{Hmac, Mac};\nuse sha2::Sha256;\n\nfn main() {\n    let mask_util = PhoneMaskUtil::new();\n    let number = PHONE_NUMBER_UTIL.parse(\"+12025550173\", None).unwrap();\n\n    // 1. Partial Masking (***-***-0173)\n    let config = MaskDigitsConfig::new('*', 4, 4); // mask at least 4, leave last 4\n    let masked = mask_util.mask_digits_to_string(\"+1 202-555-0173 ext. 89\", config);\n    println!(\"Masked: {}\", masked);\n\n    // 2. Semantic Tokenization with HMAC\n    let mut mac = Hmac::\u003cSha256\u003e::new_from_slice(b\"my_secret_salt\").unwrap();\n    let token = mask_util.tokenize_to_string(\u0026number, PhoneMacHasher(mac)).unwrap();\n    \n    // \u003cPhone country=\"US\" hash=\"a1b2c3d4...\"\u003e\n    println!(\"Token: {}\", token); \n}\n```\n\n---\n\n## ⚡ Performance\n\nBenchmarks use `criterion` measuring the average time to process a **single phone number** using native toolchains (C++ `google/benchmark` with RE2 vs Rust `rlibphonenumber`). \n\nBoth benchmarks bypass CPU branch-predictor memorization.\n\n| Operation | C++ (`libphonenumber` + RE2) | Rust (`rlibphonenumber`) | Speedup |\n| :--- | :--- | :--- | :--- |\n| **Parsing** | ~2.28 µs *(2279 ns)* | **~0.50 µs *(500 ns)*** | **~4.5x** |\n| **Format (E.164)** | ~63 ns | **~33 ns** | **~1.9x** |\n| **Format (International)** | ~2.03 µs *(2028 ns)* | **~0.43 µs *(432 ns)*** | **~4.7x** |\n| **Format (National)** | ~2.48 µs *(2484 ns)* | **~0.56 µs *(558 ns)*** | **~4.4x** |\n| **Format (RFC3966)** | ~2.42 µs *(2417 ns)* | **~0.61 µs *(606 ns)*** | **~4.0x** |\n\n### Under the Hood: Why is it so fast?\n* **Zero-Allocation Formatter:** Intermediate heap allocations are eliminated using `Cow\u003cstr\u003e` and stack-allocated zero-padding buffers.\n* **O(1) Pre-Anchored Regexes:** Instead of runtime string concatenation (`\"^(?:\" + pattern + \")$\"`), validation metadata is compiled AOT (Ahead-of-Time). Rust uses `[..]` string slicing to fast-fail boundary checks, bypassing O(N) regex engine sweeps.\n* **`FxHash` Maps:** We replaced standard `SipHash` with `rustc_hash` for ultra-low latency metadata lookups.\n* **Lazy Compilation:** Regexes are compiled lazily inside the metadata wrappers via `OnceLock`, removing centralized cache contention.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvloldik%2Frlibphonenumber","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvloldik%2Frlibphonenumber","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvloldik%2Frlibphonenumber/lists"}