{"id":36956582,"url":"https://github.com/fbinkert/relabs","last_synced_at":"2026-01-13T14:01:20.049Z","repository":{"id":328232090,"uuid":"1107152869","full_name":"fbinkert/relabs","owner":"fbinkert","description":"Zero-overhead, compile-time validation for absolute vs. relative paths in Rust.","archived":false,"fork":false,"pushed_at":"2026-01-01T21:05:48.000Z","size":166,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-07T04:57:11.201Z","etag":null,"topics":["compile-time","filesystem","path","rust","type-safety","zero-cost"],"latest_commit_sha":null,"homepage":"https://docs.rs/relabs","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fbinkert.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-11-30T17:18:55.000Z","updated_at":"2026-01-01T21:05:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fbinkert/relabs","commit_stats":null,"previous_names":["fbinkert/relabs"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fbinkert/relabs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbinkert%2Frelabs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbinkert%2Frelabs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbinkert%2Frelabs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbinkert%2Frelabs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fbinkert","download_url":"https://codeload.github.com/fbinkert/relabs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbinkert%2Frelabs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28387596,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T13:42:20.960Z","status":"ssl_error","status_checked_at":"2026-01-13T13:42:03.276Z","response_time":56,"last_error":"SSL_read: 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":["compile-time","filesystem","path","rust","type-safety","zero-cost"],"created_at":"2026-01-13T14:01:19.055Z","updated_at":"2026-01-13T14:01:20.043Z","avatar_url":"https://github.com/fbinkert.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RelAbs: The Typed Path Crate for Rust\n\n[![Crates.io](https://img.shields.io/crates/v/relabs.svg)](https://crates.io/crates/relabs)\n[![Docs.rs](https://docs.rs/relabs/badge.svg)](https://docs.rs/relabs)\n![License](https://img.shields.io/badge/license-MIT-blue.svg)\n\n**Strict, compile-time validation for absolute and relative paths in Rust.**\n\n`RelAbs` lifts the distinction between absolute and relative paths into the type system. It prevents common directory traversal bugs, logic errors, and \"stringly typed\" confusion by ensuring you never accidentally mix them up.\n\n\u003e ⚠️ **Status: Active Development**\n\u003e This crate is currently in the early stages of development. APIs are subject to change.\n\n---\n\n## Installation\n\nRun the following Cargo command in your project directory:\n\n```bash\ncargo add relabs\n```\n\n---\n\n## Motivation \u0026 Comparison\n\nStandard Rust paths (`std::path::Path`/`PathBuf`) are \"stringly typed.\" This ambiguity forces you to rely on repetitive runtime checks or, worse, assume invariants that the compiler cannot enforce. `RelAbs` provides a safer, compile-time guarantee.\n\n### Comparison to Existing Crates\n\n| Feature            |       **RelAbs**       | `std::path`  |   `camino`   |   `relative-path`    |    `abs_path`     |\n| :----------------- | :--------------------: | :----------: | :----------: | :------------------: | :---------------: |\n| **Type Safety**    | **Strict (Abs \u0026 Rel)** |     None     |     None     |  Strict (Rel only)   | Strict (Abs only) |\n| **Path Encoding**  |     **OS-native**      |  OS-native   |  UTF-8 only  |        UTF-8         |     OS-native     |\n| **Semantics**      |     **OS-native**      |  OS-native   |  OS-native   | POSIX-like (Virtual) |     OS-native     |\n| **Unified System** |        **Yes**         | Yes (unsafe) | Yes (unsafe) |          No          |        No         |\n\n- **vs. `camino`:** `RelAbs` focuses on **absolute/relative validation**, whereas `camino` focuses on **UTF-8 encoding**. `RelAbs` wraps `std::path` and supports non-UTF-8 OS paths.\n- **vs. `relative-path`/`abs_path`:** These solutions split the problem across separate crates. `RelAbs` provides a **unified system** for both `AbsPath` and `RelPath` with typed transitions between them.\n\n---\n\n## Flavors: Typed Paths\n\n`RelAbs` introduces **flavors** to encode invariants in the type system.\n\nCore types:\n\n- **`AbsPath`, `AbsPathBuf`** – Paths that are guaranteed to be **absolute**.\n- **`RelPath`, `RelPathBuf`** – Paths that are guaranteed to be **relative**.\n- **`AnyPath`, `AnyPathBuf`** – Unconstrained (analogous to `std::path::Path` / `PathBuf`).\n\nAll flavored types are zero-cost, `#[repr(transparent)]` wrappers.\n\n### Constructing Typed Paths\n\nValidation happens at construction. Since `RelAbs` wraps `std::path`, validation uses the **host OS rules** (e.g., `C:\\` is absolute on Windows, but not on Linux).\n\n```rust\nuse relabs::{AbsPath, RelPath, AbsPathBuf, RelPathBuf};\n\n// Fallible construction from \u0026str / \u0026Path\nlet root: \u0026AbsPath = AbsPath::try_new(\"/var/www\").unwrap();\nlet rel : \u0026RelPath = RelPath::try_new(\"static/app.css\").unwrap();\n\n// Owned variants\nlet abs_buf = AbsPathBuf::try_from(\"/etc/passwd\").unwrap();\nlet rel_buf = RelPathBuf::try_from(\"src/lib.rs\").unwrap();\n```\n\nIf the invariant doesn’t hold (e.g., constructing `AbsPath` from a relative string), construction fails instead of silently accepting it.\n\n---\n\n## Typed Composition (`push` / `join`)\n\nIn the standard library, passing an absolute path to `PathBuf::push` silently **replaces** the base path, which is a common source of logic bugs. `RelAbs` eliminates this bug at compile time.\n\n### The Safety Guarantee\n\n| Operation                  | `std::path`                            | `RelAbs`                          |\n| :------------------------- | :------------------------------------- | :-------------------------------- |\n| `base.join(\"sub/dir\")`     | Appends                                | Appends                           |\n| `base.join(\"/etc/passwd\")` | **Replaces base** (Silent logic error) | **Compile Error** (Type mismatch) |\n\nComposition is strictly typed:\n\n```mermaid\ngraph LR\n    A[AbsPath] -- join RelPath --\u003e B[AbsPathBuf]\n    C[RelPath] -- join RelPath --\u003e D[RelPathBuf]\n    A -- join AbsPath --\u003e X[❌ Compile Error]\n```\n\n### Example\n\n```rust\nuse relabs::{RelPathBuf, AbsPathBuf, RelPath, AbsPath};\n\nlet mut work_dir = RelPathBuf::try_from(\"projects/rust\").unwrap();\n\n// Typed append: only RelPath is accepted\nwork_dir.push(RelPath::try_new(\"src\").unwrap());\n\nlet root = AbsPath::try_new(\"/var/www\").unwrap();\n\n// AbsPath + RelPath -\u003e AbsPathBuf (Safe Append)\nlet full = root.join(RelPath::try_new(\"static\").unwrap());\nassert_eq!(full.as_path(), AbsPath::try_new(\"/var/www/static\").unwrap());\n\n// COMPILE ERROR: Cannot push an absolute path onto a typed path.\n// root.join(AbsPath::try_new(\"/etc/passwd\").unwrap());\n```\n\n### Escape Hatch: typed `push_std`/`join_std`\n\nIf you explicitly require the standard library's replacement semantics (where an absolute RHS replaces the base), `RelAbs` provides the `push_std` and `join_std` methods. These methods are still fully typed and preserve the flavor invariant.\n\n---\n\n## Self-Documenting APIs\n\nWith flavors, function signatures communicate intent, reducing the need for documentation or runtime checks.\n\n```rust\nuse relabs::{AbsPath, RelPath};\n\nfn init_workspace(root: \u0026AbsPath, config: \u0026RelPath) {\n    // `root` is guaranteed absolute\n    // `config` is guaranteed relative\n}\n```\n\n---\n\n## Key Features\n\n- **Zero-Cost:** `RelPath` and `AbsPath` are `#[repr(transparent)]` wrappers around `std::path::Path`.\n- **Zero Dependencies:** Lightweight implementation relying exclusively on the standard library.\n- **Ecosystem Compatibility:** Designed to interoperate seamlessly with `std::fs` and `std::path`.\n\n---\n\n## Safety\n\nTo achieve zero-cost conversion from `\u0026std::path::Path` to `\u0026Path\u003cF\u003e`, the crate relies on a single, carefully isolated `unsafe` pointer cast. This operation is justified and upheld by the `#[repr(transparent)]` memory layout guarantee. All public constructors rigorously enforce path invariants before delegating to the internal unsafe conversion, ensuring public safety.\n\n---\n\n## Roadmap\n\n- [ ] `Serde` support (Deserialize/Serialize with validation).\n- [ ] Complete `std::path::Path` API parity (metadata, ancestors, etc.).\n- [ ] Test with Miri.\n- [ ] Display and Debug implementations that respect flavors.\n- [ ] Windows/Unix specific extensions.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffbinkert%2Frelabs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffbinkert%2Frelabs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffbinkert%2Frelabs/lists"}