use crate::{
database::{AssetDatabase, handle::AssetHandle, path::AssetPathStatic},
fetch::{AssetAwaitsAsyncFetch, AssetAwaitsResolution, AssetBytesAreReadyToProcess},
store::{AssetAwaitsAsyncStore, AssetAwaitsStoring, AssetBytesAreReadyToStore},
};
use anput::component::Component;
use std::{collections::HashSet, error::Error};
#[derive(Debug, Default, Clone)]
pub struct AssetsTracker {
handles: HashSet<AssetHandle>,
}
impl AssetsTracker {
pub fn with(mut self, handle: AssetHandle) -> Self {
self.track(handle);
self
}
pub fn with_many(mut self, handles: impl IntoIterator<Item = AssetHandle>) -> Self {
self.track_many(handles);
self
}
pub fn track(&mut self, handle: AssetHandle) {
self.handles.insert(handle);
}
pub fn track_many(&mut self, handles: impl IntoIterator<Item = AssetHandle>) {
self.handles.extend(handles);
}
pub fn untrack(&mut self, handle: AssetHandle) {
self.handles.remove(&handle);
}
pub fn untrack_many(&mut self, handles: impl IntoIterator<Item = AssetHandle>) {
for handle in handles {
self.handles.remove(&handle);
}
}
pub fn len(&self) -> usize {
self.handles.len()
}
pub fn is_empty(&self) -> bool {
self.handles.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = AssetHandle> + '_ {
self.handles.iter().copied()
}
pub fn report(&self, database: &AssetDatabase, out_status: &mut AssetsStatus) {
out_status.clear();
for handle in &self.handles {
if handle.does_exists(database) {
if handle.has::<AssetAwaitsStoring>(database) {
out_status.awaiting_storing.add(*handle);
} else if handle.has::<AssetBytesAreReadyToStore>(database) {
out_status.with_bytes_ready_to_store.add(*handle);
} else if handle.has::<AssetAwaitsAsyncStore>(database) {
out_status.awaiting_async_store.add(*handle);
} else if handle.has::<AssetAwaitsResolution>(database) {
out_status.awaiting_resolution.add(*handle);
} else if handle.has::<AssetBytesAreReadyToProcess>(database) {
out_status.with_bytes_ready_to_process.add(*handle);
} else if handle.has::<AssetAwaitsAsyncFetch>(database) {
out_status.awaiting_async_fetch.add(*handle);
} else {
out_status.ready_to_use.add(*handle);
}
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AssetsStatusCategory {
Amount(usize),
List(Vec<AssetHandle>),
}
impl Default for AssetsStatusCategory {
fn default() -> Self {
AssetsStatusCategory::amount()
}
}
impl AssetsStatusCategory {
pub fn amount() -> Self {
AssetsStatusCategory::Amount(0)
}
pub fn list() -> Self {
AssetsStatusCategory::List(Default::default())
}
pub fn len(&self) -> usize {
match self {
AssetsStatusCategory::Amount(len) => *len,
AssetsStatusCategory::List(list) => list.len(),
}
}
pub fn is_empty(&self) -> bool {
match self {
AssetsStatusCategory::Amount(len) => *len == 0,
AssetsStatusCategory::List(list) => list.is_empty(),
}
}
pub fn clear(&mut self) {
match self {
AssetsStatusCategory::Amount(len) => *len = 0,
AssetsStatusCategory::List(list) => list.clear(),
}
}
pub fn add(&mut self, handle: AssetHandle) {
match self {
AssetsStatusCategory::Amount(len) => *len += 1,
AssetsStatusCategory::List(list) => list.push(handle),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct AssetsStatus {
pub awaiting_storing: AssetsStatusCategory,
pub with_bytes_ready_to_store: AssetsStatusCategory,
pub awaiting_async_store: AssetsStatusCategory,
pub awaiting_resolution: AssetsStatusCategory,
pub with_bytes_ready_to_process: AssetsStatusCategory,
pub awaiting_async_fetch: AssetsStatusCategory,
pub ready_to_use: AssetsStatusCategory,
}
impl AssetsStatus {
pub fn amount() -> Self {
AssetsStatus {
awaiting_storing: AssetsStatusCategory::amount(),
with_bytes_ready_to_store: AssetsStatusCategory::amount(),
awaiting_async_store: AssetsStatusCategory::amount(),
awaiting_resolution: AssetsStatusCategory::amount(),
with_bytes_ready_to_process: AssetsStatusCategory::amount(),
awaiting_async_fetch: AssetsStatusCategory::amount(),
ready_to_use: AssetsStatusCategory::amount(),
}
}
pub fn list() -> Self {
AssetsStatus {
awaiting_storing: AssetsStatusCategory::list(),
with_bytes_ready_to_store: AssetsStatusCategory::list(),
awaiting_async_store: AssetsStatusCategory::list(),
awaiting_resolution: AssetsStatusCategory::list(),
with_bytes_ready_to_process: AssetsStatusCategory::list(),
awaiting_async_fetch: AssetsStatusCategory::list(),
ready_to_use: AssetsStatusCategory::list(),
}
}
pub fn clear(&mut self) {
self.awaiting_resolution.clear();
self.with_bytes_ready_to_process.clear();
self.awaiting_async_fetch.clear();
self.ready_to_use.clear();
}
pub fn progress(&self) -> AssetsProgress {
AssetsProgress {
awaiting_storing: self.awaiting_storing.len(),
with_bytes_ready_to_store: self.with_bytes_ready_to_store.len(),
awaiting_async_store: self.awaiting_async_store.len(),
awaiting_resolution: self.awaiting_resolution.len(),
with_bytes_ready_to_process: self.with_bytes_ready_to_process.len(),
awaiting_async_fetch: self.awaiting_async_fetch.len(),
ready_to_use: self.ready_to_use.len(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AssetsProgress {
pub awaiting_storing: usize,
pub with_bytes_ready_to_store: usize,
pub awaiting_async_store: usize,
pub awaiting_resolution: usize,
pub with_bytes_ready_to_process: usize,
pub awaiting_async_fetch: usize,
pub ready_to_use: usize,
}
impl AssetsProgress {
pub fn only_storing(&self) -> Self {
AssetsProgress {
awaiting_storing: self.awaiting_storing,
with_bytes_ready_to_store: self.with_bytes_ready_to_store,
awaiting_async_store: self.awaiting_async_store,
awaiting_resolution: 0,
with_bytes_ready_to_process: 0,
awaiting_async_fetch: 0,
ready_to_use: 0,
}
}
pub fn only_fetching(&self) -> Self {
AssetsProgress {
awaiting_storing: 0,
with_bytes_ready_to_store: 0,
awaiting_async_store: 0,
awaiting_resolution: self.awaiting_resolution,
with_bytes_ready_to_process: self.with_bytes_ready_to_process,
awaiting_async_fetch: self.awaiting_async_fetch,
ready_to_use: self.ready_to_use,
}
}
pub fn total(&self) -> usize {
self.awaiting_storing
+ self.with_bytes_ready_to_store
+ self.awaiting_async_store
+ self.awaiting_resolution
+ self.with_bytes_ready_to_process
+ self.awaiting_async_fetch
+ self.ready_to_use
}
pub fn is_complete(&self) -> bool {
self.awaiting_storing == 0
&& self.with_bytes_ready_to_store == 0
&& self.awaiting_async_store == 0
&& self.awaiting_resolution == 0
&& self.with_bytes_ready_to_process == 0
&& self.awaiting_async_fetch == 0
}
pub fn is_in_progress(&self) -> bool {
!self.is_complete()
}
pub fn factor(&self) -> f32 {
let total = self.total();
if total == 0 {
1.0
} else {
self.ready_to_use as f32 / total as f32
}
}
}
pub enum ConsumedSingleAssetLoader<T: Component + Default> {
Path(AssetPathStatic),
Handle(AssetHandle),
Data(T),
Error(Box<dyn Error>),
}
impl<T: Component + Default> ConsumedSingleAssetLoader<T> {
pub fn path(path: impl Into<AssetPathStatic>) -> Self {
ConsumedSingleAssetLoader::Path(path.into())
}
pub fn handle(handle: AssetHandle) -> Self {
ConsumedSingleAssetLoader::Handle(handle)
}
pub fn is_complete(&self) -> bool {
matches!(
self,
ConsumedSingleAssetLoader::Data(_) | ConsumedSingleAssetLoader::Error(_)
)
}
pub fn is_in_progress(&self) -> bool {
matches!(
self,
ConsumedSingleAssetLoader::Path(_) | ConsumedSingleAssetLoader::Handle(_)
)
}
pub fn maintain(&mut self, database: &mut AssetDatabase) {
match self {
ConsumedSingleAssetLoader::Path(path) => {
let handle = match database.ensure(path.clone()) {
Ok(handle) => handle,
Err(err) => {
*self = ConsumedSingleAssetLoader::Error(err);
return;
}
};
*self = ConsumedSingleAssetLoader::Handle(handle);
}
ConsumedSingleAssetLoader::Handle(handle) => {
let mut component = match database.storage.component_mut::<true, T>(handle.entity())
{
Ok(component) => component,
Err(err) => {
*self = ConsumedSingleAssetLoader::Error(err.into());
return;
}
};
let data = std::mem::take(&mut *component);
drop(component);
handle.delete(database);
*self = ConsumedSingleAssetLoader::Data(data);
}
_ => {}
}
}
}