resource: fix wait_for_load haning when using handles from 'request_raw'

This commit is contained in:
SeanOMik 2024-04-27 00:31:20 -04:00
parent 15807a3dc1
commit 1b08482ef7
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
1 changed files with 18 additions and 52 deletions

View File

@ -7,7 +7,7 @@ use notify_debouncer_full::{DebouncedEvent, FileIdMap};
use thiserror::Error; use thiserror::Error;
use uuid::Uuid; use uuid::Uuid;
use crate::{gltf::ModelLoader, loader::{ImageLoader, LoaderError, ResourceLoader}, resource::ResHandle, ResourceData, ResourceState}; use crate::{gltf::ModelLoader, loader::{ImageLoader, LoaderError, ResourceLoader}, resource::ResHandle, ResourceData, ResourceState, UntypedResHandle};
/// A trait for type erased storage of a resource. /// A trait for type erased storage of a resource.
/// Implemented for [`ResHandle<T>`] /// Implemented for [`ResHandle<T>`]
@ -26,6 +26,7 @@ pub trait ResourceStorage: Send + Sync + Any + 'static {
fn is_watched(&self) -> bool; fn is_watched(&self) -> bool;
fn is_loaded(&self) -> bool; fn is_loaded(&self) -> bool;
fn set_state(&self, new: ResourceState); fn set_state(&self, new: ResourceState);
fn clone_untyped(&self) -> UntypedResHandle;
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -121,54 +122,14 @@ impl ResourceManager {
/// ///
/// Loading resources is done asynchronously on a task spawned by `async-std`. You can use the /// Loading resources is done asynchronously on a task spawned by `async-std`. You can use the
/// handle to check if the resource is loaded. /// handle to check if the resource is loaded.
#[inline(always)]
pub fn request<T>(&self, path: &str) -> Result<ResHandle<T>, RequestError> pub fn request<T>(&self, path: &str) -> Result<ResHandle<T>, RequestError>
where where
T: ResourceData T: ResourceData
{ {
let mut state = self.state_mut(); self.request_raw(path)
match state.resources.get(&path.to_string()) { .map(|res| res.as_typed::<T>()
Some(res) => { .expect("mismatched asset type, cannot downcast"))
let res = res.clone().as_arc_any();
let res: Arc<ResHandle<T>> = res.downcast::<ResHandle<T>>().expect("Failure to downcast resource");
let res = ResHandle::<T>::clone(&res);
Ok(res)
},
None => {
if let Some(loader) = state.loaders.iter()
.find(|l| l.does_support_file(path)) {
// Load the resource and store it
let loader = Arc::clone(loader); // stop borrowing from self
let res = loader.load(self.clone(), path);
let handle = ResHandle::<T>::new_loading(Some(path));
let thand = handle.clone();
task::spawn(async move {
match res.await {
Ok(data) => {
let mut d = thand.write();
d.state = ResourceState::Ready(data);
d.condvar.1.notify_all();
}
Err(err) => {
let mut d = thand.write();
d.state = ResourceState::Error(Arc::new(err));
}
}
});
let res: Arc<dyn ResourceStorage> = Arc::from(handle.clone());
state.resources.insert(path.to_string(), res.clone());
state.uuid_resources.insert(res.uuid(), res);
Ok(handle)
} else {
Err(RequestError::UnsupportedFileExtension(path.to_string()))
}
}
}
} }
/// Request a resource without downcasting to a `ResHandle<T>`. /// Request a resource without downcasting to a `ResHandle<T>`.
@ -177,11 +138,11 @@ impl ResourceManager {
/// let arc_any = res_arc.as_arc_any(); /// let arc_any = res_arc.as_arc_any();
/// let res: Arc<ResHandle<T>> = res.downcast::<ResHandle<T>>().expect("Failure to downcast resource"); /// let res: Arc<ResHandle<T>> = res.downcast::<ResHandle<T>>().expect("Failure to downcast resource");
/// ``` /// ```
pub fn request_raw(&self, path: &str) -> Result<Arc<dyn ResourceStorage>, RequestError> { pub fn request_raw(&self, path: &str) -> Result<UntypedResHandle, RequestError> {
let mut state = self.state_mut(); let mut state = self.state_mut();
match state.resources.get(&path.to_string()) { match state.resources.get(&path.to_string()) {
Some(res) => { Some(res) => {
Ok(res.clone()) Ok(res.clone().clone_untyped())
}, },
None => { None => {
if let Some(loader) = state.loaders.iter() if let Some(loader) = state.loaders.iter()
@ -192,24 +153,29 @@ impl ResourceManager {
let res = loader.load(self.clone(), path); let res = loader.load(self.clone(), path);
let handle = loader.create_erased_handle(); let handle = loader.create_erased_handle();
//let handle = ResHandle::<T>::new_loading();
let thand = handle.clone(); let untyped = handle.clone_untyped();
untyped.write().path = Some(path.to_string());
task::spawn(async move { task::spawn(async move {
match res.await { match res.await {
Ok(data) => { Ok(data) => {
thand.set_state(ResourceState::Ready(data)); let mut d = untyped.write();
d.state = ResourceState::Ready(data);
d.condvar.1.notify_all();
} }
Err(err) => { Err(err) => {
thand.set_state(ResourceState::Error(Arc::new(err))); let mut d = untyped.write();
d.state = ResourceState::Error(Arc::new(err));
} }
} }
}); });
let res: Arc<dyn ResourceStorage> = Arc::from(handle.clone()); let res: Arc<dyn ResourceStorage> = Arc::from(handle.clone());
state.resources.insert(path.to_string(), res.clone());
state.uuid_resources.insert(res.uuid(), res); state.uuid_resources.insert(res.uuid(), res);
Ok(handle) Ok(handle.clone_untyped())
} else { } else {
Err(RequestError::UnsupportedFileExtension(path.to_string())) Err(RequestError::UnsupportedFileExtension(path.to_string()))
} }