Skip to content

Commit 017331a

Browse files
bors[bot]matklad
andauthored
Merge #4875
4875: Introduce paths crate r=matklad a=matklad It's a good idea to distinguish between absolute and relative paths at the type level, to avoid accidental dependency on the cwd, which really shouldn't matter for rust-analyzer service bors r+ 🤖 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents 246c66a + a32cff3 commit 017331a

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/paths/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "paths"
3+
version = "0.1.0"
4+
authors = ["rust-analyzer developers"]
5+
edition = "2018"
6+
7+
[lib]
8+
doctest = false

crates/paths/src/lib.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//! Thin wrappers around `std::path`, distinguishing between absolute and
2+
//! relative paths.
3+
use std::{
4+
convert::{TryFrom, TryInto},
5+
ops,
6+
path::{Component, Path, PathBuf},
7+
};
8+
9+
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
10+
pub struct AbsPathBuf(PathBuf);
11+
12+
impl From<AbsPathBuf> for PathBuf {
13+
fn from(AbsPathBuf(path_buf): AbsPathBuf) -> PathBuf {
14+
path_buf
15+
}
16+
}
17+
18+
impl ops::Deref for AbsPathBuf {
19+
type Target = AbsPath;
20+
fn deref(&self) -> &AbsPath {
21+
self.as_path()
22+
}
23+
}
24+
25+
impl AsRef<Path> for AbsPathBuf {
26+
fn as_ref(&self) -> &Path {
27+
self.0.as_path()
28+
}
29+
}
30+
31+
impl TryFrom<PathBuf> for AbsPathBuf {
32+
type Error = PathBuf;
33+
fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> {
34+
if !path_buf.is_absolute() {
35+
return Err(path_buf);
36+
}
37+
Ok(AbsPathBuf(path_buf))
38+
}
39+
}
40+
41+
impl TryFrom<&str> for AbsPathBuf {
42+
type Error = PathBuf;
43+
fn try_from(path: &str) -> Result<AbsPathBuf, PathBuf> {
44+
AbsPathBuf::try_from(PathBuf::from(path))
45+
}
46+
}
47+
48+
impl AbsPathBuf {
49+
pub fn as_path(&self) -> &AbsPath {
50+
AbsPath::new_unchecked(self.0.as_path())
51+
}
52+
pub fn pop(&mut self) -> bool {
53+
self.0.pop()
54+
}
55+
}
56+
57+
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
58+
#[repr(transparent)]
59+
pub struct AbsPath(Path);
60+
61+
impl ops::Deref for AbsPath {
62+
type Target = Path;
63+
fn deref(&self) -> &Path {
64+
&self.0
65+
}
66+
}
67+
68+
impl AsRef<Path> for AbsPath {
69+
fn as_ref(&self) -> &Path {
70+
&self.0
71+
}
72+
}
73+
74+
impl<'a> TryFrom<&'a Path> for &'a AbsPath {
75+
type Error = &'a Path;
76+
fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> {
77+
if !path.is_absolute() {
78+
return Err(path);
79+
}
80+
Ok(AbsPath::new_unchecked(path))
81+
}
82+
}
83+
84+
impl AbsPath {
85+
fn new_unchecked(path: &Path) -> &AbsPath {
86+
unsafe { &*(path as *const Path as *const AbsPath) }
87+
}
88+
89+
pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf {
90+
self.as_ref().join(path).try_into().unwrap()
91+
}
92+
pub fn normalize(&self) -> AbsPathBuf {
93+
AbsPathBuf(normalize_path(&self.0))
94+
}
95+
}
96+
97+
// https://github.com/rust-lang/cargo/blob/79c769c3d7b4c2cf6a93781575b7f592ef974255/src/cargo/util/paths.rs#L60-L85
98+
fn normalize_path(path: &Path) -> PathBuf {
99+
let mut components = path.components().peekable();
100+
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
101+
components.next();
102+
PathBuf::from(c.as_os_str())
103+
} else {
104+
PathBuf::new()
105+
};
106+
107+
for component in components {
108+
match component {
109+
Component::Prefix(..) => unreachable!(),
110+
Component::RootDir => {
111+
ret.push(component.as_os_str());
112+
}
113+
Component::CurDir => {}
114+
Component::ParentDir => {
115+
ret.pop();
116+
}
117+
Component::Normal(c) => {
118+
ret.push(c);
119+
}
120+
}
121+
}
122+
ret
123+
}

0 commit comments

Comments
 (0)