Skip to content

Commit ddaeb6d

Browse files
committed
use maybe_normalize_path for normalize_path, returns cow<path> now
1 parent cfebf24 commit ddaeb6d

File tree

1 file changed

+42
-38
lines changed

1 file changed

+42
-38
lines changed

crates/bevy_asset/src/path.rs

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use core::{
1111
ops::Deref,
1212
};
1313
use serde::{de::Visitor, Deserialize, Serialize};
14-
use std::path::{Path, PathBuf};
14+
use std::{
15+
borrow::Cow,
16+
path::{Path, PathBuf},
17+
};
1518
use thiserror::Error;
1619

1720
/// Represents a path to an asset in a "virtual filesystem".
@@ -129,7 +132,7 @@ impl<'a> AssetPath<'a> {
129132
Some(source) => AssetSourceId::Name(CowArc::Borrowed(source)),
130133
None => AssetSourceId::Default,
131134
},
132-
path: maybe_normalize_path::<'a, _>(CowArc::Borrowed(path)),
135+
path: normalize_atomicow_path(CowArc::Borrowed(path)),
133136
label: label.map(CowArc::Borrowed),
134137
})
135138
}
@@ -227,7 +230,7 @@ impl<'a> AssetPath<'a> {
227230
#[inline]
228231
pub fn from_path_buf(path_buf: PathBuf) -> AssetPath<'a> {
229232
AssetPath {
230-
path: maybe_normalize_path(CowArc::<'_, Path>::Owned(path_buf.into())),
233+
path: normalize_atomicow_path(CowArc::Owned(path_buf.into())),
231234
source: AssetSourceId::Default,
232235
label: None,
233236
}
@@ -237,7 +240,7 @@ impl<'a> AssetPath<'a> {
237240
#[inline]
238241
pub fn from_path(path: &'a Path) -> AssetPath<'a> {
239242
AssetPath {
240-
path: maybe_normalize_path(CowArc::Borrowed(path)),
243+
path: normalize_atomicow_path(CowArc::Borrowed(path)),
241244
source: AssetSourceId::Default,
242245
label: None,
243246
}
@@ -346,7 +349,7 @@ impl<'a> AssetPath<'a> {
346349
pub fn normalized(self) -> AssetPath<'a> {
347350
AssetPath {
348351
source: self.source,
349-
path: maybe_normalize_path(self.path),
352+
path: normalize_atomicow_path(self.path),
350353
label: self.label,
351354
}
352355
}
@@ -460,14 +463,20 @@ impl<'a> AssetPath<'a> {
460463
PathBuf::new()
461464
};
462465
result_path.push(rpath);
463-
result_path = normalize_path(result_path.as_path());
466+
467+
// Boxing the result_path into a CowArc<Path> after normalization to
468+
// avoid a potential unnecessary allocation.
469+
let path: CowArc<Path> = maybe_normalize_path(&result_path).map_or_else(
470+
|| CowArc::Owned(result_path.into()),
471+
|path| CowArc::Owned(path.into()),
472+
);
464473

465474
Ok(AssetPath {
466475
source: match source {
467476
Some(source) => AssetSourceId::Name(CowArc::Owned(source.into())),
468477
None => self.source.clone_owned(),
469478
},
470-
path: CowArc::Owned(result_path.into()),
479+
path,
471480
label: rlabel.map(|l| CowArc::Owned(l.into())),
472481
})
473482
}
@@ -556,7 +565,7 @@ impl From<&'static str> for AssetPath<'static> {
556565
let (source, path, label) = Self::parse_internal(asset_path).unwrap();
557566
AssetPath {
558567
source: source.into(),
559-
path: maybe_normalize_path(CowArc::Static(path)),
568+
path: normalize_atomicow_path(CowArc::Static(path)),
560569
label: label.map(CowArc::Static),
561570
}
562571
}
@@ -581,7 +590,7 @@ impl From<&'static Path> for AssetPath<'static> {
581590
fn from(path: &'static Path) -> Self {
582591
Self {
583592
source: AssetSourceId::Default,
584-
path: maybe_normalize_path(CowArc::Static(path)),
593+
path: normalize_atomicow_path(CowArc::Static(path)),
585594
label: None,
586595
}
587596
}
@@ -593,7 +602,7 @@ impl From<PathBuf> for AssetPath<'static> {
593602
let path: CowArc<'_, Path> = path.into();
594603
Self {
595604
source: AssetSourceId::Default,
596-
path: maybe_normalize_path(path),
605+
path: normalize_atomicow_path(path),
597606
label: None,
598607
}
599608
}
@@ -655,29 +664,17 @@ impl<'de> Visitor<'de> for AssetPathVisitor {
655664

656665
/// Normalizes the path by collapsing all occurrences of '.' and '..' dot-segments where possible
657666
/// as per [RFC 1808](https://datatracker.ietf.org/doc/html/rfc1808)
658-
pub(crate) fn normalize_path(path: &Path) -> PathBuf {
659-
let mut result_path = PathBuf::new();
660-
for elt in path.iter() {
661-
if elt == "." {
662-
// Skip
663-
} else if elt == ".." {
664-
if !result_path.pop() {
665-
// Preserve ".." if insufficient matches (per RFC 1808).
666-
result_path.push(elt);
667-
}
668-
} else {
669-
result_path.push(elt);
670-
}
667+
pub(crate) fn normalize_path(path: &Path) -> Cow<'_, Path> {
668+
match maybe_normalize_path(path) {
669+
Some(pathbuf) => Cow::Owned(pathbuf),
670+
None => Cow::Borrowed(path),
671671
}
672-
result_path
673672
}
674673

675674
/// Normalizes the path by collapsing all occurrences of '.' and '..' dot-segments where possible
676675
/// as per [RFC 1808](https://datatracker.ietf.org/doc/html/rfc1808)
677-
/// Returns a borrowed path if no normalization was necessary, otherwise returns an owned normalized path.
678-
pub(crate) fn maybe_normalize_path<'a, P: AsRef<Path> + Into<CowArc<'a, Path>> + 'a>(
679-
as_path: P,
680-
) -> CowArc<'a, Path> {
676+
/// Returns `None` if no normalization was performed, otherwise returns a normalized `PathBuf`.
677+
pub(crate) fn maybe_normalize_path<'a, P: AsRef<Path> + 'a>(as_path: P) -> Option<PathBuf> {
681678
let path = as_path.as_ref();
682679
let mut result_path: core::cell::OnceCell<PathBuf> = core::cell::OnceCell::new();
683680
let init = |i: usize| -> PathBuf { path.iter().take(i).collect() };
@@ -699,30 +696,37 @@ pub(crate) fn maybe_normalize_path<'a, P: AsRef<Path> + Into<CowArc<'a, Path>> +
699696
}
700697
}
701698

702-
match result_path.into_inner() {
703-
Some(path_buf) => CowArc::Owned(path_buf.into()),
704-
None => as_path.into(),
699+
result_path.into_inner()
700+
}
701+
702+
pub(crate) fn normalize_atomicow_path<'a>(path: CowArc<'a, Path>) -> CowArc<'a, Path> {
703+
match maybe_normalize_path(&path) {
704+
Some(normalized) => CowArc::Owned(normalized.into()),
705+
None => path,
705706
}
706707
}
707708

708709
#[cfg(test)]
709710
mod tests {
710-
use crate::{path::maybe_normalize_path, AssetPath};
711+
use crate::{normalize_atomicow_path, AssetPath};
711712
use alloc::string::ToString;
712713
use atomicow::CowArc;
713714
use std::path::Path;
714715

715716
#[test]
716717
fn normalize_cow_paths() {
717-
let path: CowArc<Path> = "a/../a/b".into();
718+
let path: CowArc<Path> = Path::new("a/../a/b").into();
718719

719720
assert_eq!(
720-
maybe_normalize_path(path),
721-
CowArc::Owned(Path::new("a/b").into())
721+
normalize_atomicow_path(path),
722+
CowArc::<Path>::Owned(Path::new("a/b").into())
722723
);
723724

724-
let path: CowArc<Path> = "a/b".into();
725-
assert_eq!(maybe_normalize_path(path), CowArc::Static(Path::new("a/b")));
725+
let path: CowArc<Path> = Path::new("a/b").into();
726+
assert_eq!(
727+
normalize_atomicow_path(path),
728+
CowArc::Static(Path::new("a/b"))
729+
);
726730

727731
let path = "a/b";
728732
let donor = 3;
@@ -731,7 +735,7 @@ mod tests {
731735
}
732736
let path = CowArc::<Path>::Borrowed(steal_lifetime(&donor, Path::new(path)));
733737
assert_eq!(
734-
maybe_normalize_path(path),
738+
normalize_atomicow_path(path),
735739
CowArc::Borrowed(Path::new("a/b"))
736740
);
737741
}

0 commit comments

Comments
 (0)