diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml index 2c7c918300536..ed55bdee235ce 100644 --- a/crates/bevy_asset/Cargo.toml +++ b/crates/bevy_asset/Cargo.toml @@ -44,7 +44,6 @@ either = "1.13" futures-io = "0.3" futures-lite = "2.0.1" blake3 = "1.5" -parking_lot = { version = "0.12", features = ["arc_lock", "send_guard"] } ron = "0.8" serde = { version = "1", features = ["derive"] } thiserror = { version = "2", default-features = false } diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 9fa8eb4381485..bda993319d816 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -6,7 +6,7 @@ use bevy_ecs::{ resource::Resource, system::{Res, ResMut, SystemChangeTick}, }; -use bevy_platform::collections::HashMap; +use bevy_platform::{collections::HashMap, sync::PoisonError}; use bevy_reflect::{Reflect, TypePath}; use core::{any::TypeId, iter::Enumerate, marker::PhantomData, sync::atomic::AtomicU32}; use crossbeam_channel::{Receiver, Sender}; @@ -545,7 +545,11 @@ impl Assets { // that `asset_server.load` calls that occur during it block, which ensures that // re-loads are kicked off appropriately. This function must be "transactional" relative // to other asset info operations - let mut infos = asset_server.data.infos.write(); + let mut infos = asset_server + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); while let Ok(drop_event) = assets.handle_provider.drop_receiver.try_recv() { let id = drop_event.id.typed(); diff --git a/crates/bevy_asset/src/io/embedded/embedded_watcher.rs b/crates/bevy_asset/src/io/embedded/embedded_watcher.rs index f7fb56be747b4..1086b1e18ea20 100644 --- a/crates/bevy_asset/src/io/embedded/embedded_watcher.rs +++ b/crates/bevy_asset/src/io/embedded/embedded_watcher.rs @@ -4,10 +4,12 @@ use crate::io::{ AssetSourceEvent, AssetWatcher, }; use alloc::{boxed::Box, sync::Arc, vec::Vec}; -use bevy_platform::collections::HashMap; +use bevy_platform::{ + collections::HashMap, + sync::{PoisonError, RwLock}, +}; use core::time::Duration; use notify_debouncer_full::{notify::RecommendedWatcher, Debouncer, RecommendedCache}; -use parking_lot::RwLock; use std::{ fs::File, io::{BufReader, Read}, @@ -63,7 +65,12 @@ impl FilesystemEventHandler for EmbeddedEventHandler { fn get_path(&self, absolute_path: &Path) -> Option<(PathBuf, bool)> { let (local_path, is_meta) = get_asset_path(&self.root, absolute_path); - let final_path = self.root_paths.read().get(local_path.as_path())?.clone(); + let final_path = self + .root_paths + .read() + .unwrap_or_else(PoisonError::into_inner) + .get(local_path.as_path())? + .clone(); if is_meta { warn!("Meta file asset hot-reloading is not supported yet: {final_path:?}"); } diff --git a/crates/bevy_asset/src/io/embedded/mod.rs b/crates/bevy_asset/src/io/embedded/mod.rs index 13610531e299a..25316f736b2fe 100644 --- a/crates/bevy_asset/src/io/embedded/mod.rs +++ b/crates/bevy_asset/src/io/embedded/mod.rs @@ -13,7 +13,7 @@ use bevy_ecs::resource::Resource; use std::path::{Path, PathBuf}; #[cfg(feature = "embedded_watcher")] -use alloc::borrow::ToOwned; +use {alloc::borrow::ToOwned, bevy_platform::sync::PoisonError}; /// The name of the `embedded` [`AssetSource`], /// as stored in the [`AssetSourceBuilders`] resource. @@ -29,7 +29,7 @@ pub struct EmbeddedAssetRegistry { dir: Dir, #[cfg(feature = "embedded_watcher")] root_paths: alloc::sync::Arc< - parking_lot::RwLock, PathBuf>>, + bevy_platform::sync::RwLock, PathBuf>>, >, } @@ -49,6 +49,7 @@ impl EmbeddedAssetRegistry { #[cfg(feature = "embedded_watcher")] self.root_paths .write() + .unwrap_or_else(PoisonError::into_inner) .insert(full_path.into(), asset_path.to_owned()); self.dir.insert_asset(asset_path, value); } @@ -68,6 +69,7 @@ impl EmbeddedAssetRegistry { #[cfg(feature = "embedded_watcher")] self.root_paths .write() + .unwrap_or_else(PoisonError::into_inner) .insert(full_path.into(), asset_path.to_owned()); self.dir.insert_meta(asset_path, value); } diff --git a/crates/bevy_asset/src/io/gated.rs b/crates/bevy_asset/src/io/gated.rs index fa4f0f0d3fd30..5cd485faff67f 100644 --- a/crates/bevy_asset/src/io/gated.rs +++ b/crates/bevy_asset/src/io/gated.rs @@ -1,8 +1,10 @@ use crate::io::{AssetReader, AssetReaderError, PathStream, Reader}; use alloc::{boxed::Box, sync::Arc}; -use bevy_platform::collections::HashMap; +use bevy_platform::{ + collections::HashMap, + sync::{PoisonError, RwLock}, +}; use crossbeam_channel::{Receiver, Sender}; -use parking_lot::RwLock; use std::path::Path; /// A "gated" reader that will prevent asset reads from returning until @@ -32,7 +34,7 @@ impl GateOpener { /// Opens the `path` "gate", allowing a _single_ [`AssetReader`] operation to return for that path. /// If multiple operations are expected, call `open` the expected number of calls. pub fn open>(&self, path: P) { - let mut gates = self.gates.write(); + let mut gates = self.gates.write().unwrap_or_else(PoisonError::into_inner); let gates = gates .entry_ref(path.as_ref()) .or_insert_with(crossbeam_channel::unbounded); @@ -58,7 +60,7 @@ impl GatedReader { impl AssetReader for GatedReader { async fn read<'a>(&'a self, path: &'a Path) -> Result { let receiver = { - let mut gates = self.gates.write(); + let mut gates = self.gates.write().unwrap_or_else(PoisonError::into_inner); let gates = gates .entry_ref(path.as_ref()) .or_insert_with(crossbeam_channel::unbounded); diff --git a/crates/bevy_asset/src/io/memory.rs b/crates/bevy_asset/src/io/memory.rs index 4c56057ff9e3c..ac936b9be9a10 100644 --- a/crates/bevy_asset/src/io/memory.rs +++ b/crates/bevy_asset/src/io/memory.rs @@ -1,10 +1,12 @@ use crate::io::{AssetReader, AssetReaderError, PathStream, Reader}; use alloc::{borrow::ToOwned, boxed::Box, sync::Arc, vec::Vec}; -use bevy_platform::collections::HashMap; +use bevy_platform::{ + collections::HashMap, + sync::{PoisonError, RwLock}, +}; use core::{pin::Pin, task::Poll}; use futures_io::AsyncRead; use futures_lite::{ready, Stream}; -use parking_lot::RwLock; use std::path::{Path, PathBuf}; use super::AsyncSeekForward; @@ -44,13 +46,17 @@ impl Dir { if let Some(parent) = path.parent() { dir = self.get_or_insert_dir(parent); } - dir.0.write().assets.insert( - path.file_name().unwrap().to_string_lossy().into(), - Data { - value: value.into(), - path: path.to_owned(), - }, - ); + dir.0 + .write() + .unwrap_or_else(PoisonError::into_inner) + .assets + .insert( + path.file_name().unwrap().to_string_lossy().into(), + Data { + value: value.into(), + path: path.to_owned(), + }, + ); } /// Removes the stored asset at `path` and returns the `Data` stored if found and otherwise `None`. @@ -60,7 +66,11 @@ impl Dir { dir = self.get_or_insert_dir(parent); } let key: Box = path.file_name().unwrap().to_string_lossy().into(); - dir.0.write().assets.remove(&key) + dir.0 + .write() + .unwrap_or_else(PoisonError::into_inner) + .assets + .remove(&key) } pub fn insert_meta(&self, path: &Path, value: impl Into) { @@ -68,13 +78,17 @@ impl Dir { if let Some(parent) = path.parent() { dir = self.get_or_insert_dir(parent); } - dir.0.write().metadata.insert( - path.file_name().unwrap().to_string_lossy().into(), - Data { - value: value.into(), - path: path.to_owned(), - }, - ); + dir.0 + .write() + .unwrap_or_else(PoisonError::into_inner) + .metadata + .insert( + path.file_name().unwrap().to_string_lossy().into(), + Data { + value: value.into(), + path: path.to_owned(), + }, + ); } pub fn get_or_insert_dir(&self, path: &Path) -> Dir { @@ -84,7 +98,7 @@ impl Dir { full_path.push(c); let name = c.as_os_str().to_string_lossy().into(); dir = { - let dirs = &mut dir.0.write().dirs; + let dirs = &mut dir.0.write().unwrap_or_else(PoisonError::into_inner).dirs; dirs.entry(name) .or_insert_with(|| Dir::new(full_path.clone())) .clone() @@ -98,7 +112,13 @@ impl Dir { let mut dir = self.clone(); for p in path.components() { let component = p.as_os_str().to_str().unwrap(); - let next_dir = dir.0.read().dirs.get(component)?.clone(); + let next_dir = dir + .0 + .read() + .unwrap_or_else(PoisonError::into_inner) + .dirs + .get(component)? + .clone(); dir = next_dir; } Some(dir) @@ -110,8 +130,14 @@ impl Dir { dir = dir.get_dir(parent)?; } - path.file_name() - .and_then(|f| dir.0.read().assets.get(f.to_str().unwrap()).cloned()) + path.file_name().and_then(|f| { + dir.0 + .read() + .unwrap_or_else(PoisonError::into_inner) + .assets + .get(f.to_str().unwrap()) + .cloned() + }) } pub fn get_metadata(&self, path: &Path) -> Option { @@ -120,12 +146,22 @@ impl Dir { dir = dir.get_dir(parent)?; } - path.file_name() - .and_then(|f| dir.0.read().metadata.get(f.to_str().unwrap()).cloned()) + path.file_name().and_then(|f| { + dir.0 + .read() + .unwrap_or_else(PoisonError::into_inner) + .metadata + .get(f.to_str().unwrap()) + .cloned() + }) } pub fn path(&self) -> PathBuf { - self.0.read().path.to_owned() + self.0 + .read() + .unwrap_or_else(PoisonError::into_inner) + .path + .to_owned() } } @@ -153,7 +189,7 @@ impl Stream for DirStream { _cx: &mut core::task::Context<'_>, ) -> Poll> { let this = self.get_mut(); - let dir = this.dir.0.read(); + let dir = this.dir.0.read().unwrap_or_else(PoisonError::into_inner); let dir_index = this.dir_index; if let Some(dir_path) = dir diff --git a/crates/bevy_asset/src/processor/mod.rs b/crates/bevy_asset/src/processor/mod.rs index a239d66a9b59a..641af81450589 100644 --- a/crates/bevy_asset/src/processor/mod.rs +++ b/crates/bevy_asset/src/processor/mod.rs @@ -58,11 +58,13 @@ use crate::{ }; use alloc::{borrow::ToOwned, boxed::Box, collections::VecDeque, sync::Arc, vec, vec::Vec}; use bevy_ecs::prelude::*; -use bevy_platform::collections::{HashMap, HashSet}; +use bevy_platform::{ + collections::{HashMap, HashSet}, + sync::{PoisonError, RwLock}, +}; use bevy_tasks::IoTaskPool; use futures_io::ErrorKind; use futures_lite::{AsyncReadExt, AsyncWriteExt, StreamExt}; -use parking_lot::RwLock; use std::path::{Path, PathBuf}; use thiserror::Error; use tracing::{debug, error, trace, warn}; @@ -533,7 +535,12 @@ impl AssetProcessor { async fn finish_processing_assets(&self) { self.try_reprocessing_queued().await; // clean up metadata in asset server - self.server.data.infos.write().consume_handle_drop_events(); + self.server + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner) + .consume_handle_drop_events(); self.set_state(ProcessorState::Finished).await; } @@ -581,7 +588,11 @@ impl AssetProcessor { /// Register a new asset processor. pub fn register_processor(&self, processor: P) { - let mut process_plans = self.data.processors.write(); + let mut process_plans = self + .data + .processors + .write() + .unwrap_or_else(PoisonError::into_inner); #[cfg(feature = "trace")] let processor = InstrumentedAssetProcessor(processor); process_plans.insert(core::any::type_name::

(), Arc::new(processor)); @@ -589,20 +600,37 @@ impl AssetProcessor { /// Set the default processor for the given `extension`. Make sure `P` is registered with [`AssetProcessor::register_processor`]. pub fn set_default_processor(&self, extension: &str) { - let mut default_processors = self.data.default_processors.write(); + let mut default_processors = self + .data + .default_processors + .write() + .unwrap_or_else(PoisonError::into_inner); default_processors.insert(extension.into(), core::any::type_name::

()); } /// Returns the default processor for the given `extension`, if it exists. pub fn get_default_processor(&self, extension: &str) -> Option> { - let default_processors = self.data.default_processors.read(); + let default_processors = self + .data + .default_processors + .read() + .unwrap_or_else(PoisonError::into_inner); let key = default_processors.get(extension)?; - self.data.processors.read().get(key).cloned() + self.data + .processors + .read() + .unwrap_or_else(PoisonError::into_inner) + .get(key) + .cloned() } /// Returns the processor with the given `processor_type_name`, if it exists. pub fn get_processor(&self, processor_type_name: &str) -> Option> { - let processors = self.data.processors.read(); + let processors = self + .data + .processors + .read() + .unwrap_or_else(PoisonError::into_inner); processors.get(processor_type_name).cloned() } diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index ff5800474d8b7..58618f6649cdc 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -26,7 +26,10 @@ use alloc::{ }; use atomicow::CowArc; use bevy_ecs::prelude::*; -use bevy_platform::collections::HashSet; +use bevy_platform::{ + collections::HashSet, + sync::{PoisonError, RwLock, RwLockWriteGuard}, +}; use bevy_tasks::IoTaskPool; use core::{any::TypeId, future::Future, panic::AssertUnwindSafe, task::Poll}; use crossbeam_channel::{Receiver, Sender}; @@ -34,7 +37,6 @@ use either::Either; use futures_lite::{FutureExt, StreamExt}; use info::*; use loaders::*; -use parking_lot::{RwLock, RwLockWriteGuard}; use std::path::{Path, PathBuf}; use thiserror::Error; use tracing::{error, info}; @@ -153,12 +155,20 @@ impl AssetServer { /// Returns true if the [`AssetServer`] watches for changes. pub fn watching_for_changes(&self) -> bool { - self.data.infos.read().watching_for_changes + self.data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner) + .watching_for_changes } /// Registers a new [`AssetLoader`]. [`AssetLoader`]s must be registered before they can be used. pub fn register_loader(&self, loader: L) { - self.data.loaders.write().push(loader); + self.data + .loaders + .write() + .unwrap_or_else(PoisonError::into_inner) + .push(loader); } /// Registers a new [`Asset`] type. [`Asset`] types must be registered before assets of that type can be loaded. @@ -184,7 +194,11 @@ impl AssetServer { }); } - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); infos .dependency_loaded_event_sender @@ -196,7 +210,11 @@ impl AssetServer { } pub(crate) fn register_handle_provider(&self, handle_provider: AssetHandleProvider) { - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); infos .handle_providers .insert(handle_provider.type_id, handle_provider); @@ -211,7 +229,13 @@ impl AssetServer { extensions: vec![extension.to_string()], }; - let loader = { self.data.loaders.read().get_by_extension(extension) }; + let loader = { + self.data + .loaders + .read() + .unwrap_or_else(PoisonError::into_inner) + .get_by_extension(extension) + }; loader.ok_or_else(error)?.get().await.map_err(|_| error()) } @@ -225,7 +249,13 @@ impl AssetServer { type_name: type_name.to_string(), }; - let loader = { self.data.loaders.read().get_by_name(type_name) }; + let loader = { + self.data + .loaders + .read() + .unwrap_or_else(PoisonError::into_inner) + .get_by_name(type_name) + }; loader.ok_or_else(error)?.get().await.map_err(|_| error()) } @@ -252,7 +282,13 @@ impl AssetServer { MissingAssetLoaderForExtensionError { extensions } }; - let loader = { self.data.loaders.read().get_by_path(&path) }; + let loader = { + self.data + .loaders + .read() + .unwrap_or_else(PoisonError::into_inner) + .get_by_path(&path) + }; loader.ok_or_else(error)?.get().await.map_err(|_| error()) } @@ -264,7 +300,13 @@ impl AssetServer { ) -> Result, MissingAssetLoaderForTypeIdError> { let error = || MissingAssetLoaderForTypeIdError { type_id }; - let loader = { self.data.loaders.read().get_by_type(type_id) }; + let loader = { + self.data + .loaders + .read() + .unwrap_or_else(PoisonError::into_inner) + .get_by_type(type_id) + }; loader.ok_or_else(error)?.get().await.map_err(|_| error()) } @@ -473,7 +515,11 @@ impl AssetServer { } } - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); let (handle, should_load) = infos.get_or_create_path_handle::( path.clone(), HandleLoadingMode::Request, @@ -495,7 +541,11 @@ impl AssetServer { guard: G, ) -> UntypedHandle { let path = path.into().into_owned(); - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); let (handle, should_load) = infos.get_or_create_path_handle_erased( path.clone(), type_id, @@ -568,7 +618,11 @@ impl AssetServer { CowArc::Owned(format!("{source}--{UNTYPED_SOURCE_SUFFIX}").into()) } }); - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); let (handle, should_load) = infos.get_or_create_path_handle::( path.clone().with_source(untyped_source), HandleLoadingMode::Request, @@ -697,7 +751,11 @@ impl AssetServer { Some((handle, true)) } None => { - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); let result = infos.get_or_create_path_handle_internal( path.clone(), path.label().is_none().then(|| loader.asset_type_id()), @@ -732,7 +790,11 @@ impl AssetServer { // if the handle result is None, we definitely need to load the asset let (base_handle, base_path) = if path.label().is_some() { - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); let base_path = path.without_label().into_owned(); let (base_handle, _) = infos.get_or_create_path_handle_erased( base_path.clone(), @@ -816,6 +878,7 @@ impl AssetServer { .data .infos .read() + .unwrap_or_else(PoisonError::into_inner) .get_path_handles(&path) .map(|handle| server.load_internal(Some(handle), path.clone(), true, None)) .collect::>(); @@ -827,7 +890,14 @@ impl AssetServer { } } - if !reloaded && server.data.infos.read().should_reload(&path) { + if !reloaded + && server + .data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner) + .should_reload(&path) + { if let Err(err) = server.load_internal(None, path, true, None).await { error!("{}", err); } @@ -860,19 +930,28 @@ impl AssetServer { ) -> UntypedHandle { let loaded_asset = asset.into(); let handle = if let Some(path) = path { - let (handle, _) = self.data.infos.write().get_or_create_path_handle_erased( - path, - loaded_asset.asset_type_id(), - Some(loaded_asset.asset_type_name()), - HandleLoadingMode::NotLoading, - None, - ); + let (handle, _) = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner) + .get_or_create_path_handle_erased( + path, + loaded_asset.asset_type_id(), + Some(loaded_asset.asset_type_name()), + HandleLoadingMode::NotLoading, + None, + ); handle } else { - self.data.infos.write().create_loading_handle_untyped( - loaded_asset.asset_type_id(), - loaded_asset.asset_type_name(), - ) + self.data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner) + .create_loading_handle_untyped( + loaded_asset.asset_type_id(), + loaded_asset.asset_type_name(), + ) }; self.send_asset_event(InternalAssetEvent::Loaded { id: handle.id(), @@ -890,7 +969,11 @@ impl AssetServer { &self, future: impl Future> + Send + 'static, ) -> Handle { - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); let handle = infos.create_loading_handle_untyped(TypeId::of::(), core::any::type_name::()); @@ -950,6 +1033,7 @@ impl AssetServer { .data .infos .write() + .unwrap_or_else(PoisonError::into_inner) .get_or_create_path_handle::( path.clone(), HandleLoadingMode::Request, @@ -1056,13 +1140,18 @@ impl AssetServer { &self, id: impl Into, ) -> Option<(LoadState, DependencyLoadState, RecursiveDependencyLoadState)> { - self.data.infos.read().get(id.into()).map(|i| { - ( - i.load_state.clone(), - i.dep_load_state.clone(), - i.rec_dep_load_state.clone(), - ) - }) + self.data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner) + .get(id.into()) + .map(|i| { + ( + i.load_state.clone(), + i.dep_load_state.clone(), + i.rec_dep_load_state.clone(), + ) + }) } /// Retrieves the main [`LoadState`] of a given asset `id`. @@ -1074,6 +1163,7 @@ impl AssetServer { self.data .infos .read() + .unwrap_or_else(PoisonError::into_inner) .get(id.into()) .map(|i| i.load_state.clone()) } @@ -1090,6 +1180,7 @@ impl AssetServer { self.data .infos .read() + .unwrap_or_else(PoisonError::into_inner) .get(id.into()) .map(|i| i.dep_load_state.clone()) } @@ -1106,6 +1197,7 @@ impl AssetServer { self.data .infos .read() + .unwrap_or_else(PoisonError::into_inner) .get(id.into()) .map(|i| i.rec_dep_load_state.clone()) } @@ -1187,13 +1279,21 @@ impl AssetServer { /// Get an `UntypedHandle` from an `UntypedAssetId`. /// See [`AssetServer::get_id_handle`] for details. pub fn get_id_handle_untyped(&self, id: UntypedAssetId) -> Option { - self.data.infos.read().get_id_handle(id) + self.data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner) + .get_id_handle(id) } /// Returns `true` if the given `id` corresponds to an asset that is managed by this [`AssetServer`]. /// Otherwise, returns `false`. pub fn is_managed(&self, id: impl Into) -> bool { - self.data.infos.read().contains_key(id.into()) + self.data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner) + .contains_key(id.into()) } /// Returns an active untyped asset id for the given path, if the asset at the given path has already started loading, @@ -1203,7 +1303,11 @@ impl AssetServer { /// # See also /// [`get_path_ids`][Self::get_path_ids] for all handles. pub fn get_path_id<'a>(&self, path: impl Into>) -> Option { - let infos = self.data.infos.read(); + let infos = self + .data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner); let path = path.into(); let mut ids = infos.get_path_ids(&path); ids.next() @@ -1213,7 +1317,11 @@ impl AssetServer { /// or are still "alive". /// Multiple IDs will be returned in the event that a single path is used by multiple [`AssetLoader`]'s. pub fn get_path_ids<'a>(&self, path: impl Into>) -> Vec { - let infos = self.data.infos.read(); + let infos = self + .data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner); let path = path.into(); infos.get_path_ids(&path).collect() } @@ -1225,7 +1333,11 @@ impl AssetServer { /// # See also /// [`get_handles_untyped`][Self::get_handles_untyped] for all handles. pub fn get_handle_untyped<'a>(&self, path: impl Into>) -> Option { - let infos = self.data.infos.read(); + let infos = self + .data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner); let path = path.into(); let mut handles = infos.get_path_handles(&path); handles.next() @@ -1235,7 +1347,11 @@ impl AssetServer { /// or are still "alive". /// Multiple handles will be returned in the event that a single path is used by multiple [`AssetLoader`]'s. pub fn get_handles_untyped<'a>(&self, path: impl Into>) -> Vec { - let infos = self.data.infos.read(); + let infos = self + .data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner); let path = path.into(); infos.get_path_handles(&path).collect() } @@ -1247,14 +1363,22 @@ impl AssetServer { path: &AssetPath, type_id: TypeId, ) -> Option { - let infos = self.data.infos.read(); + let infos = self + .data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner); let path = path.into(); infos.get_path_and_type_id_handle(&path, type_id) } /// Returns the path for the given `id`, if it has one. pub fn get_path(&self, id: impl Into) -> Option { - let infos = self.data.infos.read(); + let infos = self + .data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner); let info = infos.get(id.into())?; Some(info.path.as_ref()?.clone()) } @@ -1269,7 +1393,11 @@ impl AssetServer { /// Assets loaded with matching extensions will be blocked until the /// real loader is added. pub fn preregister_loader(&self, extensions: &[&str]) { - self.data.loaders.write().reserve::(extensions); + self.data + .loaders + .write() + .unwrap_or_else(PoisonError::into_inner) + .reserve::(extensions); } /// Retrieve a handle for the given path. This will create a handle (and [`AssetInfo`]) if it does not exist @@ -1278,7 +1406,11 @@ impl AssetServer { path: impl Into>, meta_transform: Option, ) -> Handle { - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); infos .get_or_create_path_handle::( path.into().into_owned(), @@ -1298,7 +1430,11 @@ impl AssetServer { type_id: TypeId, meta_transform: Option, ) -> UntypedHandle { - let mut infos = self.data.infos.write(); + let mut infos = self + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); infos .get_or_create_path_handle_erased( path.into().into_owned(), @@ -1378,6 +1514,7 @@ impl AssetServer { self.data .loaders .read() + .unwrap_or_else(PoisonError::into_inner) .find(None, asset_type_id, None, Some(asset_path)) }; @@ -1400,6 +1537,7 @@ impl AssetServer { self.data .loaders .read() + .unwrap_or_else(PoisonError::into_inner) .find(None, asset_type_id, None, Some(asset_path)) }; @@ -1511,7 +1649,11 @@ impl AssetServer { cx: &mut core::task::Context<'_>, id: UntypedAssetId, ) -> Poll> { - let infos = self.data.infos.read(); + let infos = self + .data + .infos + .read() + .unwrap_or_else(PoisonError::into_inner); let Some(info) = infos.get(id) else { return Poll::Ready(Err(WaitForAssetError::NotLoaded)); @@ -1538,7 +1680,10 @@ impl AssetServer { let mut infos = { // Must drop read-only guard to acquire write guard drop(infos); - self.data.infos.write() + self.data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner) }; let Some(info) = infos.get_mut(id) else { @@ -1620,7 +1765,11 @@ impl AssetServer { /// A system that manages internal [`AssetServer`] events, such as finalizing asset loads. pub fn handle_internal_asset_events(world: &mut World) { world.resource_scope(|world, server: Mut| { - let mut infos = server.data.infos.write(); + let mut infos = server + .data + .infos + .write() + .unwrap_or_else(PoisonError::into_inner); let var_name = vec![]; let mut untyped_failures = var_name; for event in server.data.asset_event_receiver.try_iter() { diff --git a/crates/bevy_macro_utils/Cargo.toml b/crates/bevy_macro_utils/Cargo.toml index 36be75234901b..b8ffa5068845a 100644 --- a/crates/bevy_macro_utils/Cargo.toml +++ b/crates/bevy_macro_utils/Cargo.toml @@ -15,7 +15,6 @@ proc-macro2 = "1.0" toml_edit = { version = "0.22.7", default-features = false, features = [ "parse", ] } -parking_lot = { version = "0.12" } [lints] workspace = true diff --git a/crates/bevy_macro_utils/src/bevy_manifest.rs b/crates/bevy_macro_utils/src/bevy_manifest.rs index 8d327810695a9..ad14ec03a6805 100644 --- a/crates/bevy_macro_utils/src/bevy_manifest.rs +++ b/crates/bevy_macro_utils/src/bevy_manifest.rs @@ -1,11 +1,12 @@ extern crate proc_macro; use alloc::collections::BTreeMap; -use parking_lot::{lock_api::RwLockReadGuard, MappedRwLockReadGuard, RwLock, RwLockWriteGuard}; use proc_macro::TokenStream; use std::{ env, + ops::Deref, path::{Path, PathBuf}, + sync::{PoisonError, RwLock, RwLockReadGuard}, time::SystemTime, }; use toml_edit::{ImDocument, Item}; @@ -21,32 +22,42 @@ const BEVY: &str = "bevy"; impl BevyManifest { /// Returns a global shared instance of the [`BevyManifest`] struct. - pub fn shared() -> MappedRwLockReadGuard<'static, BevyManifest> { + pub fn shared() -> impl Deref { static MANIFESTS: RwLock> = RwLock::new(BTreeMap::new()); let manifest_path = Self::get_manifest_path(); let modified_time = Self::get_manifest_modified_time(&manifest_path) .expect("The Cargo.toml should have a modified time"); + let path = manifest_path.clone(); - if let Ok(manifest) = - RwLockReadGuard::try_map(MANIFESTS.read(), |manifests| manifests.get(&manifest_path)) + let manifests = MANIFESTS.read().unwrap_or_else(PoisonError::into_inner); + + if manifests + .get(&manifest_path) + .is_some_and(|manifest| manifest.modified_time == modified_time) { - if manifest.modified_time == modified_time { - return manifest; + BevyManifestGuard { + guard: manifests, + path, } - } + } else { + drop(manifests); - let manifest = BevyManifest { - manifest: Self::read_manifest(&manifest_path), - modified_time, - }; + let manifest = BevyManifest { + manifest: Self::read_manifest(&manifest_path), + modified_time, + }; - let key = manifest_path.clone(); - let mut manifests = MANIFESTS.write(); - manifests.insert(key, manifest); + let mut manifests = MANIFESTS.write().unwrap_or_else(PoisonError::into_inner); + manifests.insert(path.clone(), manifest); - RwLockReadGuard::map(RwLockWriteGuard::downgrade(manifests), |manifests| { - manifests.get(&manifest_path).unwrap() - }) + drop(manifests); + let manifests = MANIFESTS.read().unwrap_or_else(PoisonError::into_inner); + + BevyManifestGuard { + guard: manifests, + path, + } + } } fn get_manifest_path() -> PathBuf { @@ -131,3 +142,16 @@ impl BevyManifest { Self::try_parse_str(path).unwrap() } } + +struct BevyManifestGuard<'a> { + guard: RwLockReadGuard<'a, BTreeMap>, + path: PathBuf, +} + +impl Deref for BevyManifestGuard<'_> { + type Target = BevyManifest; + + fn deref(&self) -> &Self::Target { + self.guard.get(&self.path).unwrap() + } +} diff --git a/crates/bevy_render/macros/src/as_bind_group.rs b/crates/bevy_render/macros/src/as_bind_group.rs index 4252929170f19..56abf8d1f4b4a 100644 --- a/crates/bevy_render/macros/src/as_bind_group.rs +++ b/crates/bevy_render/macros/src/as_bind_group.rs @@ -58,7 +58,8 @@ struct BindlessIndexTableRangeAttr { } pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { - let manifest = BevyManifest::shared(); + let guard = BevyManifest::shared(); + let manifest = &*guard; let render_path = manifest.get_path("bevy_render"); let image_path = manifest.get_path("bevy_image"); let asset_path = manifest.get_path("bevy_asset");