{"id":16723987,"url":"https://github.com/cwfitzgerald/path-dsl-rs","last_synced_at":"2025-09-21T06:32:39.145Z","repository":{"id":57653494,"uuid":"201532126","full_name":"cwfitzgerald/path-dsl-rs","owner":"cwfitzgerald","description":"A Rust utility DSL and macro to help construct and modify Paths.","archived":false,"fork":false,"pushed_at":"2020-07-11T23:26:34.000Z","size":57,"stargazers_count":23,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-14T15:10:45.252Z","etag":null,"topics":["dsl","macros","no-dependencies","path","paths","rust","rust-macro","utility-library","zero-cost-abstraction"],"latest_commit_sha":null,"homepage":"","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/cwfitzgerald.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-09T19:55:32.000Z","updated_at":"2024-12-17T12:29:21.000Z","dependencies_parsed_at":"2022-08-26T07:11:02.939Z","dependency_job_id":null,"html_url":"https://github.com/cwfitzgerald/path-dsl-rs","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/cwfitzgerald/path-dsl-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwfitzgerald%2Fpath-dsl-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwfitzgerald%2Fpath-dsl-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwfitzgerald%2Fpath-dsl-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwfitzgerald%2Fpath-dsl-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cwfitzgerald","download_url":"https://codeload.github.com/cwfitzgerald/path-dsl-rs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwfitzgerald%2Fpath-dsl-rs/sbom","scorecard":{"id":313594,"data":{"date":"2025-08-11","repo":{"name":"github.com/cwfitzgerald/path-dsl-rs","commit":"7208758cd8646f3bfcb79fa19ee1ed2e4c6dcdb5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-17T23:40:14.587Z","repository_id":57653494,"created_at":"2025-08-17T23:40:14.587Z","updated_at":"2025-08-17T23:40:14.587Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276204814,"owners_count":25602738,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-21T02:00:07.055Z","response_time":72,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["dsl","macros","no-dependencies","path","paths","rust","rust-macro","utility-library","zero-cost-abstraction"],"created_at":"2024-10-12T22:40:18.231Z","updated_at":"2025-09-21T06:32:38.879Z","avatar_url":"https://github.com/cwfitzgerald.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# path-dsl\n\n[![Latest version](https://img.shields.io/crates/v/path-dsl.svg)](https://crates.io/crates/path-dsl)\n[![Documentation](https://docs.rs/path-dsl/badge.svg)](https://docs.rs/path-dsl)\n![License](https://img.shields.io/crates/l/path-dsl.svg)\n\nUtility DSL and macro to help deal with Paths.\n\nPathDSL provides a simple and zero-overhead abstraction for creating\npaths and appending to existing `Path`-like things.\n\n## Overview\n\n```rust\nuse path_dsl::path;\n# use std::path::{PathBuf, Path};\n\n// PathBuf::push() only called once with consecutive literals:\nlet literals: PathBuf = path!(\"dir1\" | \"dir2\" | \"dir3\");\n// Type annotation for illustration purposes; not needed\n\n// Does not copy data if first path segment is a owning value:\nlet moving = path!(literals | \"dir4\");\n\n// Mixing and matching is easy:\nlet start = path!(\"some\" | \"dir\");\nlet end = path!(\"my_folder\" | \"my_file.txt\");\n// Can borrow as normal\nlet result = path!(start | \"middle_folder\" | \u0026end);\n\n// Works with PathBuf, Path, and String-likes\nlet file = Path::new(\"file.txt\");\nlet folder = PathBuf::from(\"folder\");\nlet middle: \u0026str = \"other_middle\";\nlet combined = path!(folder | middle | \"middle_folder\" | file);\n```\n\n## PathDSL Macro and Type\n\nPathDSL's [`path!`](https://docs.rs/path-dsl/*/path_dsl/macro.path.html) macro allows for the creation of a `PathBuf` in the most efficent way possible in the situation.\n\nnote the use of `|` instead of `/` due to rust's macro rules\n\n```rust\nuse path_dsl::path;\n// Type annotation for illustration only, not needed\nlet path: PathBuf = path!(\"dir1\" | \"dir2\" | \"dir3\" | \"file.txt\");\n```\n\n#### PathDSL\n\nYou can also generate a PathDSL directly, though this is discouraged. PathDSL will pretend to be\na `PathBuf` as best it can, but it is almost always more efficent to use the `path!` macro to generate\na `PathBuf` directly.\n\n```rust\nuse path_dsl::PathDSL;\nlet path = PathDSL::from(\"dir1\") / \"dir2\" / \"dir3\" / \"file.txt\";\n```\n\n#### Adding Path-Like Structures\n\nAs well as using regular string literals, you can use anything that can be passed to `PathBuf::push`\nas a part of the DSL.\n\nNote the borrow on `other`: as these types are not `Copy`, they will be moved\ninto the path unless you borrow them. This matches behavior with `PathBuf::push`, but can be surprising\nwhen used in a infix expression.\n\n```rust\nuse path_dsl::{path, PathDSL};\n\nlet other = PathBuf::from(\"some_dir\");\nlet filename: \u0026str = \"my_file.txt\";\n\nlet mac: PathBuf  = path!(\"dir1\" | \"dir2\" | \u0026other | filename); // Preferred\nlet path: PathDSL = PathDSL::from(\"dir1\") / \"dir2\" / other / filename; // Also works\n```\n\n#### Moving vs Borrowing\n\nBoth the macro and the DSL type behave the same with regard to borrowing vs moving. If a\nreference is provided, it will borrow the provided value. However, if a value is provided\n**it will move it**, making the value unusable afterwards. While these are the normal rules\nfor rust, infix operators are normally used with `Copy` types, so this may be **surprising**.\n\nBoth mutable and immutable borrows are supported, though they will never actually mutate anything.\n\n```rust,compile_fail\nuse path_dsl::path;\n# use std::path::PathBuf;\n\nlet value = PathBuf::from(\"some_dir\");\nlet borrow: \u0026str = \"my_file.txt\";\n\nlet mac  = path!(value | borrow);\nlet path = path!(value | borrow); // Will not compile because `value` was moved\n```\n\nYou must manually borrow it:\n\n```rust\nlet mac  = path!(\u0026value | borrow); // Borrow value so it can be used later\nlet path = PathDSL::new() / value / borrow; // Not used afterwards, so doesn't need a borrow\n```\n\n#### PathDSL \u003c=\u003e PathBuf\n\n`PathDSL` is designed to be a drop-in replacement for `PathBuf`, including trivial conversions\nbetween the two. In any situation where you would be able to use `PathBuf` you can use\n`PathDSL`. `PathDSL` includes an implementation of `Deref` to a `PathBuf` (and by proxy `Path`) and re-implements all functions that take `self`, so is fully api compatable.\nHowever there are some situations where you must have a `PathBuf`.\nObtaining a `\u0026PathBuf` is trivial through dereferencing and obtaining a `PathBuf` is possible through the [`PathDSL::into_pathbuf`](https://docs.rs/path-dsl/*/path_dsl/struct.PathDSL.html#method.into_pathbuf) function.\n\nPathDSL is `#[repr(transparent)]` over `PathBuf` and all functions are force-inlined so\nconversions and operations should be cost-free compared to the equivalent `PathBuf` operation.\nIf they aren't, please file a bug.\n\nSome known issues are:\n\n**Equality**\n\n```rust\nuse path_dsl::path;\n\nlet dsl = path!(\"file.txt\");\nlet buf = PathBuf::from(\"file.txt\");\n\nassert!(dsl == buf);\n// Must de-reference to PathBuf can't implement `Eq` for `PathBuf`\nassert!(buf == *dsl);\n```\n\n**Function Calls**\n\n```rust\nuse path_dsl::path;\n\nfn func(p: PathBuf) {\n}\n\nlet dsl = path!(\"file.txt\");\nlet buf = PathBuf::from(\"file.txt\");\n\nfunc(buf);\n// Must convert into `PathBuf`\n// Dereferencing doesn't work because `func` moves.\nfunc(dsl.to_path_buf());\nfunc(dsl.into()) // also works\n```\n\n#### Macro Optimizations\n\nAs previously mentioned, the macro contains some optimizations over using raw `PathDSL` and should always\nbe used over manually using PathDSL. These optimizations happen at compile time, and are guaranteed.\nFurther details on these can be found on the [`path!`](https://docs.rs/path-dsl/*/path_dsl/macro.path.html) macro documentation.\n\n**String Literal Concatenation:**\n\nWhile it is ill-advised to use string literals with slashes in a `Path`, The [`path!`](https://docs.rs/path-dsl/*/path_dsl/macro.path.html) macro\ntakes slashes into account, and automatically constructs a single string literal from multiple\nconsecutive string literals. This can potentially save an allocation or two in the underlying\n`OsString`.\n\n```rust\nuse path_dsl::path;\n\nlet p = path!(\"this\" | \"is\" | \"combined\");\nif cfg!(windows) {\n    assert_eq!(p, PathBuf::from(\"this\\\\is\\\\combined\"));\n} else {\n    assert_eq!(p, PathBuf::from(\"this/is/combined\"));\n}\n```\n\n**First-Argument Optimization:**\n\nWhen the very first argument of the [`path!`](https://docs.rs/path-dsl/*/path_dsl/macro.path.html) macro is a owning `PathBuf`, `OsString` or `PathDSL`\npassed by value (moved), instead of copying everything into a new `PathDSL`, it will just steal the\nbuffer from that moved-in value. This allows you to use the [`path!`](https://docs.rs/path-dsl/*/path_dsl/macro.path.html) macro fearlessly when\nappending to already existing variables.\n\n```rust\nuse path_dsl::path;\n\nlet first = PathBuf::from(\"a_very_long_folder_name\");\nlet p = path!(first); // Does not copy anything.\n```\n\n## Why Use A Crate?\n\nYou may be wondering why you should use a crate for this when you can easily wrap `PathBuf` and\nadd some `Div` implementations. This is basically what I thought as well until I actually went\nto go implement this crate. There is a surprising amount of very tedious and particular code to try to emulate\n`PathBuf` directly, as well as to test the functionality.\n\nWith this in mind, I have made `path_dsl` completely dependency free, choosing to lean on declarative\nmacros over proc macros as to not depend on things like `syn`. Additionally, everything is contained within\nthis one file, I have thorough tests, and I have added `#[deny(unsafe_code)]` for good measure.\nHopefully this makes this crate light enough and easily-auditable enough to be an acceptable dependency.\n\nLicense: MIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcwfitzgerald%2Fpath-dsl-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcwfitzgerald%2Fpath-dsl-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcwfitzgerald%2Fpath-dsl-rs/lists"}