Skip to content

Commit f3b7a41

Browse files
committed
better
1 parent f69febe commit f3b7a41

2 files changed

Lines changed: 31 additions & 60 deletions

File tree

benches/bench.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ fn bench_normalize_path_changed(bencher: divan::Bencher) {
1616

1717
#[divan::bench(sample_size = 51200)]
1818
fn bench_normalize_path_no_change(bencher: divan::Bencher) {
19-
let path = PathBuf::from("/testing/this/out/testing/test");
19+
let path = if cfg!(windows) {
20+
PathBuf::from("C:\\testing\\this\\out\\testing\\test")
21+
} else {
22+
PathBuf::from("/testing/this/out/testing/test")
23+
};
2024
bencher.bench(|| normalize_path(Cow::Borrowed(&path)))
2125
}

src/lib.rs

Lines changed: 26 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
use deno_error::JsError;
99
use std::borrow::Cow;
10-
use std::ffi::OsString;
1110
use std::path::Component;
1211
use std::path::Path;
1312
use std::path::PathBuf;
@@ -146,32 +145,39 @@ fn url_to_file_path_wasm(url: &Url) -> Result<PathBuf, ()> {
146145
/// <https://github.com/rust-lang/cargo/blob/af307a38c20a753ec60f0ad18be5abed3db3c9ac/src/cargo/util/paths.rs#L60-L85>
147146
#[inline]
148147
pub fn normalize_path(path: Cow<Path>) -> Cow<Path> {
149-
enum ShouldNormalize {
150-
Yes,
151-
No,
152-
EnsureNoTrailingSlash,
153-
}
148+
fn should_normalize(path: &Path) -> bool {
149+
if path_has_trailing_separator(&path) {
150+
return true;
151+
}
154152

155-
fn should_normalize(path: &Path) -> ShouldNormalize {
156-
let mut had_normal = false;
157153
for component in path.components() {
158154
match component {
159155
Component::CurDir | Component::ParentDir => {
160-
return ShouldNormalize::Yes;
156+
return true;
161157
}
162-
Component::Prefix(..) | Component::RootDir => {
158+
Component::Prefix(..) | Component::RootDir | Component::Normal(_) => {
163159
// ok
164160
}
165-
Component::Normal(_) => had_normal = true,
166161
}
167162
}
168163

169-
if path_has_cur_dir_separator(path) {
170-
ShouldNormalize::Yes
171-
} else if had_normal {
172-
ShouldNormalize::EnsureNoTrailingSlash
164+
path_has_cur_dir_separator(path)
165+
}
166+
167+
fn path_has_trailing_separator(path: &Path) -> bool {
168+
#[cfg(unix)]
169+
let raw = std::os::unix::ffi::OsStrExt::as_bytes(path.as_os_str());
170+
#[cfg(windows)]
171+
let raw = path.as_os_str().as_encoded_bytes();
172+
#[cfg(target_arch = "wasm32")]
173+
let raw = path.to_string_lossy();
174+
#[cfg(target_arch = "wasm32")]
175+
let raw = raw.as_bytes();
176+
177+
if sys_traits::impls::is_windows() {
178+
raw.contains(&('/' as u8)) || raw.ends_with(b"\\")
173179
} else {
174-
ShouldNormalize::No
180+
raw.ends_with(b"/")
175181
}
176182
}
177183

@@ -205,29 +211,6 @@ pub fn normalize_path(path: Cow<Path>) -> Cow<Path> {
205211
false
206212
}
207213

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-
231214
fn inner(path: &Path) -> PathBuf {
232215
let mut components = path.components().peekable();
233216
let mut ret =
@@ -256,29 +239,13 @@ pub fn normalize_path(path: Cow<Path>) -> Cow<Path> {
256239
ret
257240
}
258241

259-
match should_normalize(&path) {
260-
ShouldNormalize::Yes => Cow::Owned(inner(&path)),
261-
ShouldNormalize::No => path,
262-
ShouldNormalize::EnsureNoTrailingSlash => ensure_no_trailing_slash(path),
242+
if should_normalize(&path) {
243+
Cow::Owned(inner(&path))
244+
} else {
245+
path
263246
}
264247
}
265248

266-
#[cfg(unix)]
267-
fn truncate_os_string(mut os: OsString, n: usize) -> OsString {
268-
use std::os::unix::ffi::OsStringExt;
269-
let mut bytes = os.into_vec();
270-
bytes.truncate(n);
271-
OsString::from_vec(bytes)
272-
}
273-
274-
#[cfg(windows)]
275-
fn truncate_os_string(os: OsString, n: usize) -> OsString {
276-
use std::os::windows::ffi::OsStrExt;
277-
use std::os::windows::ffi::OsStringExt;
278-
let wide: Vec<u16> = os.encode_wide().take(n).collect();
279-
OsString::from_wide(&wide)
280-
}
281-
282249
#[derive(Debug, Clone, Error, deno_error::JsError, PartialEq, Eq)]
283250
#[class(uri)]
284251
#[error("Could not convert path to URL.\n Path: {0}")]

0 commit comments

Comments
 (0)