assets_manager 0.13.9

Conveniently load, cache, and reload external resources
Documentation
use crate::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct X(pub i32);

impl FileAsset for X {
    const EXTENSION: &'static str = "x";

    fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Result<Self, BoxedError> {
        crate::asset::load_text(&bytes).map(X)
    }
}

#[derive(Debug)]
pub struct Y(pub i32);

impl Asset for Y {
    fn load(cache: &AssetCache, id: &SharedString) -> Result<Y, BoxedError> {
        Ok(Y(cache.load::<X>(id)?.read().0))
    }
}

mod asset_cache {
    use super::{X, Y};
    use crate::AssetCache;

    #[test]
    fn new_with_valid_path() {
        let cache = AssetCache::new("assets");
        assert!(cache.is_ok());
    }

    #[test]
    fn new_with_invalid_path() {
        let cache = AssetCache::new("asset");
        assert!(cache.is_err());
    }

    #[test]
    fn new_with_valid_file() {
        let cache = AssetCache::new("src/lib.rs");
        assert!(cache.is_err());
    }

    #[test]
    fn load() {
        let cache = AssetCache::new("assets").unwrap();

        assert_eq!(*cache.load::<X>("test.cache").unwrap().read(), X(42));
        assert!(cache.contains::<X>("test.cache"));
    }

    #[test]
    fn load_owned() {
        let cache = AssetCache::new("assets").unwrap();

        assert_eq!(cache.load_owned::<X>("test.cache").unwrap(), X(42));
        assert!(!cache.contains::<X>("test.cache"));
    }

    #[test]
    fn get() {
        let cache = AssetCache::new("assets").unwrap();

        assert!(cache.get::<X>("test.cache").is_none());
        cache.load::<X>("test.cache").unwrap();
        assert_eq!(*cache.get::<X>("test.cache").unwrap().read(), X(42));
    }

    #[test]
    fn get_or_insert() {
        let cache = AssetCache::new("assets").unwrap();

        assert!(cache.get::<i32>("test.xxx").is_none());
        let handle = cache.get_or_insert::<i32>("test.xxx", 5);
        assert_eq!(*handle.read(), 5);
    }

    #[test]
    fn errors() {
        let cache = AssetCache::new("assets").unwrap();

        let err = cache.load::<String>("test.missing").unwrap_err();
        assert!(err.reason().downcast_ref::<std::io::Error>().is_some());

        let err = cache.load::<Y>("test.a").unwrap_err();
        assert_eq!(err.id(), "test.a");
        let err = err.reason().downcast_ref::<crate::Error>().unwrap();
        assert_eq!(err.id(), "test.a");
        assert!(
            err.reason()
                .downcast_ref::<std::num::ParseIntError>()
                .is_some()
        );

        let err = cache.load_owned::<X>("test.a").unwrap_err();
        assert_eq!(err.id(), "test.a");
        assert!(
            err.reason()
                .downcast_ref::<std::num::ParseIntError>()
                .is_some()
        );
    }

    #[test]
    fn load_dir_ok() {
        let cache = AssetCache::new("assets").unwrap();

        assert!(!cache.contains::<crate::Directory<X>>("test"));
        let mut loaded: Vec<_> = cache
            .load_dir::<X>("test")
            .unwrap()
            .read()
            .iter(&cache)
            .filter_map(|x| Some(x.ok()?.read().0))
            .collect();
        assert!(cache.contains::<crate::Directory<X>>("test"));

        loaded.sort();
        assert_eq!(loaded, [-7, 42]);
    }

    #[test]
    fn load_dir_all() {
        let cache = AssetCache::new("assets").unwrap();

        let dir = cache.load_dir::<X>("test").unwrap().read();
        let mut loaded: Vec<_> = dir.ids().map(|id| (id, cache.load::<X>(id))).collect();
        loaded.sort_by_key(|i| i.0);
        let mut loaded = loaded.into_iter();

        let (id, x) = loaded.next().unwrap();
        assert_eq!(id, "test.a");
        assert!(x.is_err());

        let (id, x) = loaded.next().unwrap();
        assert_eq!(id, "test.b");
        assert_eq!(*x.unwrap().read(), X(-7));

        let (id, x) = loaded.next().unwrap();
        assert_eq!(id, "test.cache");
        assert_eq!(*x.unwrap().read(), X(42));

        assert!(loaded.next().is_none());
    }

    #[test]
    fn parent() {
        let parent = AssetCache::new("assets").unwrap();
        let child = parent.make_child();

        let handle = parent.load::<X>("test.cache").unwrap();

        assert_eq!(*handle.read(), X(42));
        assert_eq!(*child.get::<X>("test.cache").unwrap().read(), X(42));
        assert!(child.contains::<X>("test.cache"));

        assert_eq!(*child.load::<X>("test.b").unwrap().read(), X(-7));
        assert!(parent.get::<X>("test.b").is_none());

        drop(child);

        assert_eq!(*handle.read(), X(42));
    }

    #[test]
    fn get_all() {
        let cache = AssetCache::new("assets").unwrap();

        cache.load_expect::<String>("test.string_base");
        cache.load_expect::<X>("test.cache");

        let mut all: Vec<_> = cache
            .iter()
            .map(|h| (h.id().as_str(), h.type_id()))
            .collect();
        all.sort();

        assert_eq!(
            all,
            &[
                ("test.cache", std::any::TypeId::of::<X>()),
                ("test.string_base", std::any::TypeId::of::<String>()),
            ]
        )
    }
}

mod handle {
    use super::*;

    #[test]
    fn id() {
        let cache = AssetCache::new("assets").unwrap();
        let handle = cache.load::<X>("test.cache").unwrap();
        assert_eq!(handle.id(), "test.cache");
    }

    #[test]
    fn same_handle() {
        let cache = AssetCache::new("assets").unwrap();
        let handle1 = cache.load::<X>("test.cache").unwrap();
        let handle2 = cache.load::<X>("test.cache").unwrap();
        assert!(std::ptr::eq(handle1, handle2));
    }

    #[test]
    fn untyped() {
        let cache = AssetCache::new("assets").unwrap();
        let handle = cache.load_expect::<X>("test.cache").as_untyped();

        assert!(handle.is::<X>());
        assert_eq!(handle.id(), "test.cache");
        assert_eq!(*handle.downcast_ref::<X>().unwrap().read(), X(42));
        assert_eq!(*handle.read().downcast_ref::<X>().unwrap(), X(42));
    }
}

#[test]
fn weird_id() {
    let cache = AssetCache::new("assets").unwrap();

    let err = cache.load::<X>("test/cache").unwrap_err();
    assert_eq!(err.reason().to_string(), "invalid id");
}