flatbox_assets 0.1.0

Provides assets management functionality for Flatbox engine
Documentation
use std::sync::Arc;
use as_any::AsAny;
use parking_lot::{RwLock, MappedRwLockWriteGuard, RwLockWriteGuard, MappedRwLockReadGuard, RwLockReadGuard};
use pretty_type_name::pretty_type_name;
use serde::{Serialize, Deserialize};
use slotmap::SlotMap;

use crate::error::AssetError;
use crate::AssetHandle;

#[typetag::serde(tag = "asset")]
pub trait Asset: AsAny + Send + Sync {}

#[derive(Default, Serialize, Deserialize)]
pub struct AssetManager {
    cache: SlotMap<AssetHandle, Arc<RwLock<Box<dyn Asset>>>>,
}

impl AssetManager {
    pub fn new() -> Self {
        AssetManager::default()
    }

    pub fn insert<A: Asset>(&mut self, asset: A) -> AssetHandle {
        self.cache.insert(Arc::new(RwLock::new(Box::new(asset))))
    }

    pub fn get<A: Asset>(&self, handle: AssetHandle) -> Result<MappedRwLockReadGuard<A>, AssetError> {
        if let Some(asset) = self.cache.get(handle) {
            let data = match asset.try_read() {
                Some(data) => data,
                None => return Err(AssetError::AssetBlocked),
            };
            
            return RwLockReadGuard::try_map(data, |data| {
                (**data).as_any().downcast_ref::<A>()
            }).map_err(|_| AssetError::WrongAssetType { asset_type: pretty_type_name::<A>().to_string() });
        }

        Err(AssetError::InvalidHandle)
    }

    pub fn get_mut<A: Asset>(&mut self, handle: AssetHandle) -> Result<MappedRwLockWriteGuard<A>, AssetError> {
        if let Some(asset) = self.cache.get_mut(handle) {
            let data = match asset.try_write() {
                Some(data) => data,
                None => return Err(AssetError::AssetBlocked),
            };
            
            return RwLockWriteGuard::try_map(data, |data| {
                (**data).as_any_mut().downcast_mut::<A>()
            }).map_err(|_| AssetError::WrongAssetType { asset_type: pretty_type_name::<A>().to_string() });
        }

        Err(AssetError::InvalidHandle)
    }

    pub fn get_dynamic(&self, handle: AssetHandle) -> Result<RwLockReadGuard<Box<dyn Asset>>, AssetError> {
        if let Some(asset) = self.cache.get(handle) {
            return asset.try_read().ok_or(AssetError::AssetBlocked);  
        }

        Err(AssetError::InvalidHandle)
    }

    pub fn remove<A: Asset>(&mut self, handle: AssetHandle) {
        self.cache.remove(handle);
    }
}