From 475ca7a62ec99f0b4d8319410b7ee3134a5fcfec Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 27 Nov 2020 22:35:42 +0100 Subject: =?UTF-8?q?Basic=20environment=20and=20resource=20loader=20?= =?UTF-8?q?=F0=9F=8F=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/env.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/env.rs (limited to 'src/env.rs') diff --git a/src/env.rs b/src/env.rs new file mode 100644 index 00000000..eba0e59b --- /dev/null +++ b/src/env.rs @@ -0,0 +1,75 @@ +//! Environment interactions. + +use std::any::Any; +use std::cell::RefCell; +use std::collections::{hash_map::Entry, HashMap}; +use std::fmt::{self, Debug, Formatter}; +use std::fs; +use std::path::{Path, PathBuf}; +use std::rc::Rc; + +use crate::font::FontLoader; + +/// A reference-counted shared environment. +pub type SharedEnv = Rc>; + +/// Encapsulates all environment dependencies (fonts, resources). +#[derive(Debug)] +pub struct Env { + /// Loads fonts from a dynamic font source. + pub fonts: FontLoader, + /// Loads resource from the file system. + pub resources: ResourceLoader, +} + +/// Loads resource from the file system. +pub struct ResourceLoader { + paths: HashMap, + entries: Vec>, +} + +/// A unique identifier for a resource. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct ResourceId(usize); + +impl ResourceLoader { + /// Create a new resource loader. + pub fn new() -> Self { + Self { paths: HashMap::new(), entries: vec![] } + } + + /// Load a resource from a path. + pub fn load( + &mut self, + path: impl AsRef, + parse: impl FnOnce(Vec) -> Option, + ) -> Option<(ResourceId, &R)> { + let path = path.as_ref(); + let id = match self.paths.entry(path.to_owned()) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let id = *entry.insert(ResourceId(self.entries.len())); + let data = fs::read(path).ok()?; + let resource = parse(data)?; + self.entries.push(Box::new(resource)); + id + } + }; + + Some((id, self.get_loaded(id))) + } + + /// Retrieve a previously loaded resource by its id. + /// + /// # Panics + /// This panics if no resource with this id was loaded. + pub fn get_loaded(&self, id: ResourceId) -> &R { + self.entries[id.0].downcast_ref().expect("bad resource type") + } +} + +impl Debug for ResourceLoader { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_set().entries(self.paths.keys()).finish() + } +} -- cgit v1.2.3