All Projects → cwfitzgerald → path-dsl-rs

cwfitzgerald / path-dsl-rs

Licence: MIT license
A Rust utility DSL and macro to help construct and modify Paths.

Programming Languages

rust
11053 projects

Projects that are alternatives of or similar to path-dsl-rs

is-valid-glob
Return true if a value is a valid glob pattern string, or array of glob patterns.
Stars: ✭ 21 (+10.53%)
Mutual labels:  paths, path
datoteka
A filesystem toolset and storage implementation for Clojure.
Stars: ✭ 59 (+210.53%)
Mutual labels:  paths, path
Exilence
DEPRECATED Tool for Path of Exile that calculates net worth and tracks gear, maps and other statistics for you and your group
Stars: ✭ 200 (+952.63%)
Mutual labels:  path
PathOfBuildingAPI
API for Path of Building's build sharing format for builds in Path of Exile.
Stars: ✭ 25 (+31.58%)
Mutual labels:  path
Lambda
Physically based renderer written in C++
Stars: ✭ 26 (+36.84%)
Mutual labels:  path
Picasso
Picasso is a high quality 2D vector graphic rendering library. It support path , matrix , gradient , pattern , image and truetype font.
Stars: ✭ 205 (+978.95%)
Mutual labels:  path
path-data
A gRPC API that exposes various information about the PATH transit system.
Stars: ✭ 29 (+52.63%)
Mutual labels:  path
Virgilio
Virgilio is developed and maintained by these awesome people. You can email us virgilio.datascience (at) gmail.com or join the Discord chat.
Stars: ✭ 13,200 (+69373.68%)
Mutual labels:  path
Entia
Entia is a free, open-source, data-oriented, highly performant, parallelizable and extensible Entity-Component-System (ECS) framework written in C# especially for game development.
Stars: ✭ 28 (+47.37%)
Mutual labels:  no-dependencies
jurl
Fast and simple URL parsing for Java, with UTF-8 and path resolving support
Stars: ✭ 84 (+342.11%)
Mutual labels:  path
Filekit
Simple and expressive file management in Swift
Stars: ✭ 2,183 (+11389.47%)
Mutual labels:  paths
Pkg Ok
👌 Checks paths and scripts defined in package.json before you publish
Stars: ✭ 219 (+1052.63%)
Mutual labels:  path
extensions-kit
📦 Collection of Swift+Apple Frameworks extensions for speeding up software development [iOS & iPadOS].
Stars: ✭ 71 (+273.68%)
Mutual labels:  utility-library
Set Value
Set nested values on an object using dot-notation, like 'a.b.c'.
Stars: ✭ 203 (+968.42%)
Mutual labels:  path
MARCspec
📄 MARCspec - A common MARC record path language
Stars: ✭ 21 (+10.53%)
Mutual labels:  path
Richpath
💪 Rich Android Path. 🤡 Draw as you want. 🎉 Animate much as you can.
Stars: ✭ 2,259 (+11789.47%)
Mutual labels:  path
stringify-keys
Build an array of key paths from an object.
Stars: ✭ 18 (-5.26%)
Mutual labels:  paths
scope guard
Scope Guard & Defer C++
Stars: ✭ 107 (+463.16%)
Mutual labels:  no-dependencies
ng-payment-card
💳 Responsive credit card component for Angular.
Stars: ✭ 27 (+42.11%)
Mutual labels:  no-dependencies
graphkit-learn
A python package for graph kernels, graph edit distances, and graph pre-image problem.
Stars: ✭ 87 (+357.89%)
Mutual labels:  paths

path-dsl

Latest version Documentation License

Utility DSL and macro to help deal with Paths.

PathDSL provides a simple and zero-overhead abstraction for creating paths and appending to existing Path-like things.

Overview

use path_dsl::path;
# use std::path::{PathBuf, Path};

// PathBuf::push() only called once with consecutive literals:
let literals: PathBuf = path!("dir1" | "dir2" | "dir3");
// Type annotation for illustration purposes; not needed

// Does not copy data if first path segment is a owning value:
let moving = path!(literals | "dir4");

// Mixing and matching is easy:
let start = path!("some" | "dir");
let end = path!("my_folder" | "my_file.txt");
// Can borrow as normal
let result = path!(start | "middle_folder" | &end);

// Works with PathBuf, Path, and String-likes
let file = Path::new("file.txt");
let folder = PathBuf::from("folder");
let middle: &str = "other_middle";
let combined = path!(folder | middle | "middle_folder" | file);

PathDSL Macro and Type

PathDSL's path! macro allows for the creation of a PathBuf in the most efficent way possible in the situation.

note the use of | instead of / due to rust's macro rules

use path_dsl::path;
// Type annotation for illustration only, not needed
let path: PathBuf = path!("dir1" | "dir2" | "dir3" | "file.txt");

PathDSL

You can also generate a PathDSL directly, though this is discouraged. PathDSL will pretend to be a PathBuf as best it can, but it is almost always more efficent to use the path! macro to generate a PathBuf directly.

use path_dsl::PathDSL;
let path = PathDSL::from("dir1") / "dir2" / "dir3" / "file.txt";

Adding Path-Like Structures

As well as using regular string literals, you can use anything that can be passed to PathBuf::push as a part of the DSL.

Note the borrow on other: as these types are not Copy, they will be moved into the path unless you borrow them. This matches behavior with PathBuf::push, but can be surprising when used in a infix expression.

use path_dsl::{path, PathDSL};

let other = PathBuf::from("some_dir");
let filename: &str = "my_file.txt";

let mac: PathBuf  = path!("dir1" | "dir2" | &other | filename); // Preferred
let path: PathDSL = PathDSL::from("dir1") / "dir2" / other / filename; // Also works

Moving vs Borrowing

Both the macro and the DSL type behave the same with regard to borrowing vs moving. If a reference is provided, it will borrow the provided value. However, if a value is provided it will move it, making the value unusable afterwards. While these are the normal rules for rust, infix operators are normally used with Copy types, so this may be surprising.

Both mutable and immutable borrows are supported, though they will never actually mutate anything.

use path_dsl::path;
# use std::path::PathBuf;

let value = PathBuf::from("some_dir");
let borrow: &str = "my_file.txt";

let mac  = path!(value | borrow);
let path = path!(value | borrow); // Will not compile because `value` was moved

You must manually borrow it:

let mac  = path!(&value | borrow); // Borrow value so it can be used later
let path = PathDSL::new() / value / borrow; // Not used afterwards, so doesn't need a borrow

PathDSL <=> PathBuf

PathDSL is designed to be a drop-in replacement for PathBuf, including trivial conversions between the two. In any situation where you would be able to use PathBuf you can use 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. However there are some situations where you must have a PathBuf. Obtaining a &PathBuf is trivial through dereferencing and obtaining a PathBuf is possible through the PathDSL::into_pathbuf function.

PathDSL is #[repr(transparent)] over PathBuf and all functions are force-inlined so conversions and operations should be cost-free compared to the equivalent PathBuf operation. If they aren't, please file a bug.

Some known issues are:

Equality

use path_dsl::path;

let dsl = path!("file.txt");
let buf = PathBuf::from("file.txt");

assert!(dsl == buf);
// Must de-reference to PathBuf can't implement `Eq` for `PathBuf`
assert!(buf == *dsl);

Function Calls

use path_dsl::path;

fn func(p: PathBuf) {
}

let dsl = path!("file.txt");
let buf = PathBuf::from("file.txt");

func(buf);
// Must convert into `PathBuf`
// Dereferencing doesn't work because `func` moves.
func(dsl.to_path_buf());
func(dsl.into()) // also works

Macro Optimizations

As previously mentioned, the macro contains some optimizations over using raw PathDSL and should always be used over manually using PathDSL. These optimizations happen at compile time, and are guaranteed. Further details on these can be found on the path! macro documentation.

String Literal Concatenation:

While it is ill-advised to use string literals with slashes in a Path, The path! macro takes slashes into account, and automatically constructs a single string literal from multiple consecutive string literals. This can potentially save an allocation or two in the underlying OsString.

use path_dsl::path;

let p = path!("this" | "is" | "combined");
if cfg!(windows) {
    assert_eq!(p, PathBuf::from("this\\is\\combined"));
} else {
    assert_eq!(p, PathBuf::from("this/is/combined"));
}

First-Argument Optimization:

When the very first argument of the path! macro is a owning PathBuf, OsString or PathDSL passed by value (moved), instead of copying everything into a new PathDSL, it will just steal the buffer from that moved-in value. This allows you to use the path! macro fearlessly when appending to already existing variables.

use path_dsl::path;

let first = PathBuf::from("a_very_long_folder_name");
let p = path!(first); // Does not copy anything.

Why Use A Crate?

You may be wondering why you should use a crate for this when you can easily wrap PathBuf and add some Div implementations. This is basically what I thought as well until I actually went to go implement this crate. There is a surprising amount of very tedious and particular code to try to emulate PathBuf directly, as well as to test the functionality.

With this in mind, I have made path_dsl completely dependency free, choosing to lean on declarative macros over proc macros as to not depend on things like syn. Additionally, everything is contained within this one file, I have thorough tests, and I have added #[deny(unsafe_code)] for good measure. Hopefully this makes this crate light enough and easily-auditable enough to be an acceptable dependency.

License: MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].