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> {
21 storage: SlotMap<RawAssetHandle, AssetEntry<T>>,
22 handles: HashMap<String, RawAssetHandle>,
23 queue: Vec<RawAssetHandle>,
24}
25
26impl<T: AssetSource> Assets<T> {
27 pub fn new() -> Self {
28 Self {
29 storage: SlotMap::with_key(),
30 handles: HashMap::new(),
31 queue: Vec::new(),
32 }
33 }
34
35 pub fn insert(&mut self, name: &str, source: T) -> Handle<T> {
39 if let Some(&existing) = self.handles.get(name) {
40 if let Some(entry) = self.storage.get_mut(existing) {
41 entry.source = source;
42 entry.processed = None;
43 if !self.queue.contains(&existing) {
44 self.queue.push(existing);
45 }
46 return Handle::new(existing);
47 }
48 }
49 let handle = self.storage.insert(AssetEntry { source, processed: None });
50 self.handles.insert(name.to_string(), handle);
51 self.queue.push(handle);
52 Handle::new(handle)
53 }
54
55 pub fn get(&self, handle: Handle<T>) -> Option<&T::Processed> {
57 self.storage.get(handle.id)?.processed.as_ref()
58 }
59
60 pub fn get_source(&self, handle: Handle<T>) -> Option<&T> {
63 self.storage.get(handle.id).map(|entry| &entry.source)
64 }
65
66 pub fn get_source_mut(&mut self, handle: Handle<T>) -> Option<&mut T> {
67 self.storage.get_mut(handle.id).map(|entry| &mut entry.source)
68 }
69
70 pub fn is_ready(&self, handle: Handle<T>) -> bool {
72 self.storage.get(handle.id).is_some_and(|entry| entry.processed.is_some())
73 }
74
75 pub fn contains(&self, handle: Handle<T>) -> bool {
77 self.storage.contains_key(handle.id)
78 }
79
80 pub fn mark_dirty(&mut self, handle: Handle<T>) {
83 if self.storage.contains_key(handle.id) && !self.queue.contains(&handle.id) {
84 self.queue.push(handle.id);
85 }
86 }
87
88 pub fn get_by_name(&self, name: &str) -> Option<&T::Processed> {
91 let handle = self.handles.get(name)?;
92 self.storage.get(*handle)?.processed.as_ref()
93 }
94
95 pub fn get_source_by_name(&self, name: &str) -> Option<&T> {
97 let handle = self.handles.get(name)?;
98 Some(&self.storage.get(*handle)?.source)
99 }
100
101 pub fn get_handle_by_name(&self, name: &str) -> Option<Handle<T>> {
103 self.handles.get(name).copied().map(Handle::new)
104 }
105
106 pub fn iter(&self) -> impl Iterator<Item = (Handle<T>, &T)> {
111 self.storage.iter().map(|(id, entry)| (Handle::new(id), &entry.source))
112 }
113
114 pub fn remove(&mut self, handle: Handle<T>) -> Option<T> {
115 self.queue.retain(|&id| id != handle.id);
116 self.handles.retain(|_, &mut id| id != handle.id);
117 self.storage.remove(handle.id).map(|entry| entry.source)
118 }
119
120 pub fn remove_by_name(&mut self, name: &str) -> Option<T> {
121 let id = self.handles.remove(name)?;
122 self.queue.retain(|&h| h != id);
123 self.storage.remove(id).map(|entry| entry.source)
124 }
125
126 pub(crate) fn set_processed(&mut self, handle: RawAssetHandle, processed: T::Processed) {
127 if let Some(entry) = self.storage.get_mut(handle) {
128 entry.processed = Some(processed);
129 }
130 }
131
132 pub(crate) fn take_dirty(&mut self) -> Vec<RawAssetHandle> {
133 std::mem::take(&mut self.queue)
134 }
135
136 pub(crate) fn requeue(&mut self, handles: Vec<RawAssetHandle>) {
137 self.queue.extend(handles);
138 }
139}
140
141impl<T: AssetSource> Default for Assets<T> {
142 fn default() -> Self {
143 Self::new()
144 }
145}