diff --git a/crates/bevy_asset/src/io/file/file_watcher.rs b/crates/bevy_asset/src/io/file/file_watcher.rs index e70cf1665f..891b6fa0ae 100644 --- a/crates/bevy_asset/src/io/file/file_watcher.rs +++ b/crates/bevy_asset/src/io/file/file_watcher.rs @@ -3,6 +3,8 @@ use crate::{ path::normalize_path, }; use alloc::borrow::ToOwned; +use alloc::string::String; +use alloc::vec::Vec; use core::time::Duration; use crossbeam_channel::Sender; use notify_debouncer_full::{ @@ -31,11 +33,12 @@ pub struct FileWatcher { impl FileWatcher { /// Creates a new [`FileWatcher`] that watches for changes to the asset files in the given `path`. pub fn new( - path: PathBuf, + path: String, sender: Sender, debounce_wait_time: Duration, ) -> Result { - let root = normalize_path(&path).canonicalize()?; + let split_path: Vec<_> = path.split("/").collect(); + let root = normalize_path(&split_path).join("/"); let watcher = new_asset_event_debouncer( path.clone(), debounce_wait_time, @@ -72,7 +75,7 @@ pub(crate) fn get_asset_path(root: &Path, absolute_path: &Path) -> (PathBuf, boo /// event management logic across filesystem-driven [`AssetWatcher`] impls. Each operating system / platform behaves /// a little differently and this is the result of a delicate balancing act that we should only perform once. pub(crate) fn new_asset_event_debouncer( - root: PathBuf, + root: String, debounce_wait_time: Duration, mut handler: impl FilesystemEventHandler, ) -> Result, notify::Error> { @@ -253,7 +256,7 @@ pub(crate) fn new_asset_event_debouncer( pub(crate) struct FileEventHandler { sender: Sender, - root: PathBuf, + root: String, last_event: Option, } @@ -263,7 +266,7 @@ impl FilesystemEventHandler for FileEventHandler { } fn get_path(&self, absolute_path: &Path) -> Option<(PathBuf, bool)> { let absolute_path = absolute_path.canonicalize().ok()?; - Some(get_asset_path(&self.root, &absolute_path)) + Some(get_asset_path(Path::new(&self.root), &absolute_path)) } fn handle(&mut self, _absolute_paths: &[PathBuf], event: AssetSourceEvent) { diff --git a/crates/bevy_asset/src/io/source.rs b/crates/bevy_asset/src/io/source.rs index 4852a2a71f..6496a85a06 100644 --- a/crates/bevy_asset/src/io/source.rs +++ b/crates/bevy_asset/src/io/source.rs @@ -545,7 +545,7 @@ impl AssetSource { if path.exists() { Some(Box::new( super::file::FileWatcher::new( - path.clone(), + path.to_string_lossy().to_string(), sender, file_debounce_wait_time, ) diff --git a/crates/bevy_asset/src/path.rs b/crates/bevy_asset/src/path.rs index d09ef86372..9159857147 100644 --- a/crates/bevy_asset/src/path.rs +++ b/crates/bevy_asset/src/path.rs @@ -167,27 +167,6 @@ impl<'a> AssetPath<'a> { }) } - /// Normalizes a string-based path by collapsing all occurrences of '.' and '..' dot-segments where possible - /// as per [RFC 1808](https://datatracker.ietf.org/doc/html/rfc1808) - fn normalize_path<'b>(path: &'b [&'b str]) -> Vec<&'b str> { - let mut result_path = Vec::new(); - for &elt in path { - if elt == "." { - // Skip - } else if elt == ".." { - if result_path.is_empty() { - // Preserve ".." if insufficient matches (per RFC 1808). - result_path.push(elt); - } else { - result_path.pop(); - } - } else { - result_path.push(elt); - } - } - result_path - } - // Attempts to Parse a &str into an `AssetPath`'s `AssetPath::source`, `AssetPath::path`, and `AssetPath::label` components. fn parse_internal( asset_path: &str, @@ -509,7 +488,7 @@ impl<'a> AssetPath<'a> { Vec::new() }; result_path.extend(rpath.split("/").filter(|s| !s.is_empty())); - let result_path = Self::normalize_path(&result_path).join("/"); + let result_path = normalize_path(&result_path).join("/"); Ok(AssetPath { source: match source { @@ -732,15 +711,17 @@ impl<'de> Visitor<'de> for AssetPathVisitor { /// Normalizes the path by collapsing all occurrences of '.' and '..' dot-segments where possible /// as per [RFC 1808](https://datatracker.ietf.org/doc/html/rfc1808) -pub(crate) fn normalize_path(path: &Path) -> PathBuf { - let mut result_path = PathBuf::new(); - for elt in path.iter() { +pub(crate) fn normalize_path<'b>(path: &'b [&'b str]) -> Vec<&'b str> { + let mut result_path = Vec::new(); + for &elt in path { if elt == "." { // Skip } else if elt == ".." { - if !result_path.pop() { + if result_path.is_empty() { // Preserve ".." if insufficient matches (per RFC 1808). result_path.push(elt); + } else { + result_path.pop(); } } else { result_path.push(elt); @@ -748,7 +729,6 @@ pub(crate) fn normalize_path(path: &Path) -> PathBuf { } result_path } - #[cfg(test)] mod tests { use crate::AssetPath;