Skip to content

Commit f69febe

Browse files
committed
better
1 parent 1a07088 commit f69febe

1 file changed

Lines changed: 45 additions & 30 deletions

File tree

src/lib.rs

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -146,19 +146,33 @@ fn url_to_file_path_wasm(url: &Url) -> Result<PathBuf, ()> {
146146
/// <https://github.com/rust-lang/cargo/blob/af307a38c20a753ec60f0ad18be5abed3db3c9ac/src/cargo/util/paths.rs#L60-L85>
147147
#[inline]
148148
pub fn normalize_path(path: Cow<Path>) -> Cow<Path> {
149-
fn should_normalize(path: &Path) -> bool {
149+
enum ShouldNormalize {
150+
Yes,
151+
No,
152+
EnsureNoTrailingSlash,
153+
}
154+
155+
fn should_normalize(path: &Path) -> ShouldNormalize {
156+
let mut had_normal = false;
150157
for component in path.components() {
151158
match component {
152159
Component::CurDir | Component::ParentDir => {
153-
return true;
160+
return ShouldNormalize::Yes;
154161
}
155-
Component::Prefix(..) | Component::RootDir | Component::Normal(_) => {
162+
Component::Prefix(..) | Component::RootDir => {
156163
// ok
157164
}
165+
Component::Normal(_) => had_normal = true,
158166
}
159167
}
160168

161-
path_has_cur_dir_separator(path)
169+
if path_has_cur_dir_separator(path) {
170+
ShouldNormalize::Yes
171+
} else if had_normal {
172+
ShouldNormalize::EnsureNoTrailingSlash
173+
} else {
174+
ShouldNormalize::No
175+
}
162176
}
163177

164178
// Rust normalizes away `Component::CurDir` most of the time
@@ -191,6 +205,29 @@ pub fn normalize_path(path: Cow<Path>) -> Cow<Path> {
191205
false
192206
}
193207

208+
// Warning: this makes some assumptions like not handling a
209+
// path like `/path/../` because it's assumed paths like that
210+
// won't be passed here because they'd be normalized by looping
211+
// over the components instead.
212+
fn ensure_no_trailing_slash(path: Cow<Path>) -> Cow<Path> {
213+
let is_windows = sys_traits::impls::is_windows();
214+
let mut bytes = path.as_os_str().as_encoded_bytes();
215+
let start_len = bytes.len();
216+
while bytes.len() > 1
217+
&& (is_windows && bytes.ends_with(b"\\") || bytes.ends_with(b"/"))
218+
{
219+
bytes = &bytes[..bytes.len() - 1];
220+
}
221+
222+
if bytes.len() == start_len {
223+
return path;
224+
}
225+
226+
let new_len = bytes.len();
227+
let os_string = path.into_owned().into_os_string();
228+
Cow::Owned(PathBuf::from(truncate_os_string(os_string, new_len)))
229+
}
230+
194231
fn inner(path: &Path) -> PathBuf {
195232
let mut components = path.components().peekable();
196233
let mut ret =
@@ -219,35 +256,13 @@ pub fn normalize_path(path: Cow<Path>) -> Cow<Path> {
219256
ret
220257
}
221258

222-
if should_normalize(&path) {
223-
Cow::Owned(inner(&path))
224-
} else {
225-
ensure_no_trailing_slash(path)
259+
match should_normalize(&path) {
260+
ShouldNormalize::Yes => Cow::Owned(inner(&path)),
261+
ShouldNormalize::No => path,
262+
ShouldNormalize::EnsureNoTrailingSlash => ensure_no_trailing_slash(path),
226263
}
227264
}
228265

229-
fn ensure_no_trailing_slash(path: Cow<Path>) -> Cow<Path> {
230-
let is_windows = sys_traits::impls::is_windows();
231-
let mut bytes = path.as_os_str().as_encoded_bytes();
232-
let start_len = bytes.len();
233-
while bytes.len() > 1
234-
&& (is_windows && bytes.ends_with(b"\\") || bytes.ends_with(b"/"))
235-
{
236-
bytes = &bytes[..bytes.len() - 1];
237-
}
238-
239-
if bytes.len() == start_len
240-
|| bytes.ends_with(b".")
241-
|| is_windows && bytes.ends_with(b":")
242-
{
243-
return path;
244-
}
245-
246-
let new_len = bytes.len();
247-
let os_string = path.into_owned().into_os_string();
248-
Cow::Owned(PathBuf::from(truncate_os_string(os_string, new_len)))
249-
}
250-
251266
#[cfg(unix)]
252267
fn truncate_os_string(mut os: OsString, n: usize) -> OsString {
253268
use std::os::unix::ffi::OsStringExt;

0 commit comments

Comments
 (0)