Skip to main content

pebble/assets/
storage.rs

1use std::collections::HashMap;
2
3use slotmap::{SlotMap, new_key_type};
4
5use crate::assets::{handle::Handle, upload::AssetSource};
6
7new_key_type! {
8    pub struct RawAssetHandle;
9}
10
11struct AssetEntry<T: AssetSource> {
12    source: T,
13    processed: Option<T::Processed>,
14}
15
16pub struct Assets<T: AssetSource> {
17    storage: SlotMap<RawAssetHandle, AssetEntry<T>>,
18    handles: HashMap<String, RawAssetHandle>,
19    queue: Vec<RawAssetHandle>,
20}
21
22impl<T: AssetSource> Assets<T> {
23    pub fn new() -> Self {
24        Self {
25            storage: SlotMap::with_key(),
26            handles: HashMap::new(),
27            queue: Vec::new(),
28        }
29    }
30
31    pub fn insert(&mut self, name: &str, source: T) -> Handle<T> {
32        if let Some(&existing) = self.handles.get(name) {
33            if let Some(entry) = self.storage.get_mut(existing) {
34                entry.source = source;
35                entry.processed = None;
36                if !self.queue.contains(&existing) {
37                    self.queue.push(existing);
38                }
39                return Handle::new(existing);
40            }
41        }
42        let handle = self.storage.insert(AssetEntry { source, processed: None });
43        self.handles.insert(name.to_string(), handle);
44        self.queue.push(handle);
45        Handle::new(handle)
46    }
47
48    pub fn get(&self, handle: Handle<T>) -> Option<&T::Processed> {
49        self.storage.get(handle.id)?.processed.as_ref()
50    }
51
52    pub fn get_source(&self, handle: Handle<T>) -> Option<&T> {
53        self.storage.get(handle.id).map(|entry| &entry.source)
54    }
55
56    pub fn get_source_mut(&mut self, handle: Handle<T>) -> Option<&mut T> {
57        self.storage.get_mut(handle.id).map(|entry| &mut entry.source)
58    }
59
60    pub fn is_ready(&self, handle: Handle<T>) -> bool {
61        self.storage.get(handle.id).is_some_and(|entry| entry.processed.is_some())
62    }
63
64    pub fn contains(&self, handle: Handle<T>) -> bool {
65        self.storage.contains_key(handle.id)
66    }
67
68    pub fn mark_dirty(&mut self, handle: Handle<T>) {
69        if self.storage.contains_key(handle.id) && !self.queue.contains(&handle.id) {
70            self.queue.push(handle.id);
71        }
72    }
73
74    pub fn get_by_name(&self, name: &str) -> Option<&T::Processed> {
75        let handle = self.handles.get(name)?;
76        self.storage.get(*handle)?.processed.as_ref()
77    }
78
79    pub fn get_source_by_name(&self, name: &str) -> Option<&T> {
80        let handle = self.handles.get(name)?;
81        Some(&self.storage.get(*handle)?.source)
82    }
83
84    pub fn get_handle_by_name(&self, name: &str) -> Option<Handle<T>> {
85        self.handles.get(name).copied().map(Handle::new)
86    }
87
88    // Every currently-loaded asset of this type, source data included —
89    // e.g. to build a static collision world from every loaded Mesh, or a
90    // debug asset browser. Ready-or-not: pair with is_ready(handle) if you
91    // only want ones that have finished uploading.
92    pub fn iter(&self) -> impl Iterator<Item = (Handle<T>, &T)> {
93        self.storage.iter().map(|(id, entry)| (Handle::new(id), &entry.source))
94    }
95
96    pub fn remove(&mut self, handle: Handle<T>) -> Option<T> {
97        self.queue.retain(|&id| id != handle.id);
98        self.handles.retain(|_, &mut id| id != handle.id);
99        self.storage.remove(handle.id).map(|entry| entry.source)
100    }
101
102    pub fn remove_by_name(&mut self, name: &str) -> Option<T> {
103        let id = self.handles.remove(name)?;
104        self.queue.retain(|&h| h != id);
105        self.storage.remove(id).map(|entry| entry.source)
106    }
107
108    pub(crate) fn set_processed(&mut self, handle: RawAssetHandle, processed: T::Processed) {
109        if let Some(entry) = self.storage.get_mut(handle) {
110            entry.processed = Some(processed);
111        }
112    }
113
114    pub(crate) fn take_dirty(&mut self) -> Vec<RawAssetHandle> {
115        std::mem::take(&mut self.queue)
116    }
117
118    pub(crate) fn requeue(&mut self, handles: Vec<RawAssetHandle>) {
119        self.queue.extend(handles);
120    }
121}
122
123impl<T: AssetSource> Default for Assets<T> {
124    fn default() -> Self {
125        Self::new()
126    }
127}