use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use crate::error::AssetError;
use crate::source::AssetSource;
#[derive(Debug, Clone, Default)]
pub enum AssetState<T> {
#[default]
Unloaded,
Loading,
Ready(Arc<T>),
Failed(Arc<AssetError>),
}
impl<T> AssetState<T> {
pub fn is_unloaded(&self) -> bool {
matches!(self, AssetState::Unloaded)
}
pub fn is_loading(&self) -> bool {
matches!(self, AssetState::Loading)
}
pub fn is_ready(&self) -> bool {
matches!(self, AssetState::Ready(_))
}
pub fn is_failed(&self) -> bool {
matches!(self, AssetState::Failed(_))
}
pub fn get(&self) -> Option<&Arc<T>> {
match self {
AssetState::Ready(asset) => Some(asset),
_ => None,
}
}
pub fn get_cloned(&self) -> Option<Arc<T>> {
match self {
AssetState::Ready(asset) => Some(Arc::clone(asset)),
_ => None,
}
}
pub fn error(&self) -> Option<&Arc<AssetError>> {
match self {
AssetState::Failed(err) => Some(err),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LoadState {
NotLoaded,
Loading,
Loaded,
Failed,
}
impl LoadState {
pub fn is_done(&self) -> bool {
matches!(self, LoadState::Loaded | LoadState::Failed)
}
}
impl<T> From<&AssetState<T>> for LoadState {
fn from(state: &AssetState<T>) -> Self {
match state {
AssetState::Unloaded => LoadState::NotLoaded,
AssetState::Loading => LoadState::Loading,
AssetState::Ready(_) => LoadState::Loaded,
AssetState::Failed(_) => LoadState::Failed,
}
}
}
#[derive(Debug)]
pub struct AssetVersion {
value: AtomicU32,
}
impl AssetVersion {
pub fn new() -> Self {
Self {
value: AtomicU32::new(1),
}
}
pub fn get(&self) -> u32 {
self.value.load(Ordering::Relaxed)
}
pub fn increment(&self) -> u32 {
self.value.fetch_add(1, Ordering::Relaxed) + 1
}
}
impl Clone for AssetVersion {
fn clone(&self) -> Self {
Self {
value: AtomicU32::new(self.value.load(Ordering::Relaxed)),
}
}
}
impl Default for AssetVersion {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct AssetEntry<T> {
pub source: AssetSource,
pub state: AssetState<T>,
pub version: AssetVersion,
}
impl<T> AssetEntry<T> {
pub fn new(source: AssetSource) -> Self {
Self {
source,
state: AssetState::Unloaded,
version: AssetVersion::new(),
}
}
pub fn with_asset(source: AssetSource, asset: T) -> Self {
Self {
source,
state: AssetState::Ready(Arc::new(asset)),
version: AssetVersion::new(),
}
}
pub fn is_ready(&self) -> bool {
self.state.is_ready()
}
pub fn is_loading(&self) -> bool {
self.state.is_loading()
}
pub fn asset(&self) -> Option<&Arc<T>> {
self.state.get()
}
}