12个版本
0.6.1 | 2020年7月11日 |
---|---|
0.6.0 | 2020年7月11日 |
0.5.4 | 2019年8月25日 |
0.4.0 | 2019年8月13日 |
0.1.1 | 2019年8月9日 |
#455 in 开发工具
1,397 每月下载量
用于 bellboy
55KB
924 行
path-dsl
用于处理路径的实用DSL和宏。
PathDSL为创建路径和向现有类似Path
的对象追加内容提供了一个简单且无开销的抽象。
概述
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宏和类型
PathDSL的path!
宏允许在当前情况下以最有效的方式创建一个PathBuf
。
注意由于Rust的宏规则,使用|
代替/
use path_dsl::path;
// Type annotation for illustration only, not needed
let path: PathBuf = path!("dir1" | "dir2" | "dir3" | "file.txt");
PathDSL
虽然不推荐,但你也可以直接生成PathDSL。PathDSL会尽量表现得像PathBuf
,但通常使用path!
宏直接生成PathBuf
会更高效。
use path_dsl::PathDSL;
let path = PathDSL::from("dir1") / "dir2" / "dir3" / "file.txt";
添加路径结构
除了使用常规字符串字面量外,你还可以使用任何可以作为DSL的一部分传递给PathBuf::push
的值。
注意对other
的借用:由于这些类型不是Copy
,除非你进行借用,否则它们将被移动到路径中。这符合与PathBuf::push
的行为,但在中缀表达式中可能会令人惊讶。
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
移动与借用
宏和DSL类型在借用与移动方面表现相同。如果提供了引用,它将借用提供的值。然而,如果提供了值,它将移动该值,使其之后不可用。虽然这些是Rust的正常规则,但中缀运算符通常用于Copy
类型,所以这可能会令人惊讶。
支持可变和不可变借用,尽管它们永远不会实际修改任何内容。
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
你必须手动进行借用
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 设计为 PathBuf 的即插即用替代品,包括两者之间的简单转换。在任何可以使用 PathBuf 的场合,您都可以使用 PathDSL。 PathDSL 包含一个指向 PathBuf(通过代理 Path)的 Deref 实现,并重新实现了所有接受 self 的函数,因此与 API 完全兼容。然而,有些情况下您必须使用 PathBuf。通过解引用可以获得 &PathBuf,而通过 PathDSL::into_pathbuf 函数可以获得 PathBuf。
PathDSL 在 PathBuf 上是 #[repr(transparent)]
,并且所有函数都被强制内联,因此与等效的 PathBuf 操作相比,转换和操作应该是免费的。如果不是这样,请提交一个错误报告。
一些已知问题包括
相等性
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);
函数调用
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
宏优化
如前所述,该宏包含一些针对使用原始 PathDSL 的优化,并且应该始终使用宏而不是手动使用 PathDSL。这些优化发生在编译时,并得到保证。更多详情可以在 path! 宏文档中找到。
字符串字面量连接
虽然不建议在 Path 中使用带有斜杠的字符串字面量,但 path! 宏会考虑斜杠,并自动从多个连续的字符串字面量中构造一个单一的字符串字面量。这可能在底层的 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"));
}
第一个参数优化
当 path! 宏的第一个参数是一个拥有 PathBuf、OsString 或 PathDSL 的值(移动),而不是将所有内容复制到一个新的 PathDSL 中,它只会从移动进来的值中窃取缓冲区。这允许您在追加到已存在的变量时放心地使用 path! 宏。
use path_dsl::path;
let first = PathBuf::from("a_very_long_folder_name");
let p = path!(first); // Does not copy anything.
为什么要使用一个 crate?
您可能想知道为什么您应该使用一个 crate 来做这件事,而不是简单地包装 PathBuf 并添加一些 Div 实现。这正是我之前所想的,直到我真正开始实现这个 crate。直接尝试模拟 PathBuf 需要编写大量非常繁琐且特定的代码,以及测试功能。
考虑到这一点,我已经将path_dsl
完全去除了依赖,选择依赖声明宏而不是过程宏,以避免依赖于像syn
这样的东西。此外,所有内容都包含在这个文件中,我进行了彻底的测试,并且为了谨慎起见,我添加了#[deny(unsafe_code)]
。希望这能让这个crate足够轻量并且易于审计,成为一个可接受的依赖。
许可证:MIT