use std::{ collections::{hash_map::Iter, HashMap}, fmt::{self, Display}, }; use thiserror::Error; #[derive(Debug, Error)] enum Error { #[error("Asset could not be found: {0}")] AssetNotFound(AssetId), } #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct AssetId(String); impl Display for AssetId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "AssetId({})", self.0) } } impl From<&str> for AssetId { fn from(s: &str) -> Self { AssetId(s.to_owned()) } } impl From for AssetId { fn from(s: String) -> Self { AssetId(s) } } pub struct AssetIter<'a>(Iter<'a, AssetId, String>); impl <'a> Iterator for AssetIter<'a> { type Item = (&'a AssetId, &'a String); fn next(&mut self) -> Option { self.0.next() } } pub trait Assets { fn assets<'a>(&'a self) -> AssetIter<'a>; fn get(&self, asset_id: AssetId) -> Result, Error>; } pub struct FsAssets { assets: HashMap, } impl FsAssets { pub fn new() -> Self { Self { assets: HashMap::new(), } } fn assets<'a>(&'a self) -> impl Iterator { self.assets.keys() } } impl Assets for FsAssets { fn assets<'a>(&'a self) -> AssetIter<'a> { AssetIter(self.assets.iter()) } fn get(&self, asset_id: AssetId) -> Result, Error> { unimplemented!() } } #[cfg(test)] pub mod mocks { use std::collections::HashMap; use super::*; pub struct MemoryAssets { assets: HashMap, } impl MemoryAssets { pub fn new(data: Vec<(AssetId, String)>) -> Self { let mut m = HashMap::new(); data.into_iter().for_each(|(asset, path)| { m.insert(asset, path); }); Self { assets: m } } } impl Assets for MemoryAssets { fn assets<'a>(&'a self) -> AssetIter<'a> { AssetIter(self.assets.iter()) } fn get(&self, asset_id: AssetId) -> Result, Error> { unimplemented!() } } }