1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use crate::{entry::Entry, CellRefMut, HandleWrapper, LoadResource, Resources, Result};
use std::any::type_name;
use slotmap::SlotMap;
use crate::{Error, Handle};
pub trait Resource {}
/// Stores resources of a single type. Resources are inserted and accessed by a handle.
/// There is also a default handle that is associated to the first inserted resource, unless
/// changed.
pub struct ResourceCache<T> {
slots: SlotMap<Handle<T>, T>,
default: Handle<T>,
}
impl<T: 'static + Sized> ResourceCache<T> {
pub fn new() -> Self {
Default::default()
}
// Inserts a new resource into the cache.
// If the cache is empty, the default is set to the first inserted value
#[inline]
pub fn insert(&mut self, value: T) -> Handle<T> {
let handle = self.slots.insert(value);
// Set the default to the first inserted value
if self.slots.len() == 1 {
self.default = handle;
}
handle
}
// Inserts a new resource into the cache.
// If the cache is empty, the default is set to the first inserted value.
// Returns a reference to the new value.
#[inline]
pub fn insert_get(&mut self, value: T) -> HandleWrapper<T, &mut T> {
let handle = self.slots.insert(value);
// Set the default to the first inserted value
if self.slots.len() == 1 {
self.default = handle;
}
HandleWrapper {
handle,
borrow: &mut self.slots[handle],
}
}
// Inserts a new resource into the cache.
// If the cache is empty, the default is set to the first inserted value.
// Returns a reference to the new value.
#[inline]
pub fn insert_get_cell(cache: CellRefMut<Self>, value: T) -> HandleWrapper<T, CellRefMut<T>> {
let mut handle = Default::default();
let borrow = cache.map(|cache| {
handle = cache.slots.insert(value);
// Set the default to the first inserted value
if cache.slots.len() == 1 {
cache.default = handle;
}
&mut cache.slots[handle]
});
HandleWrapper { handle, borrow }
}
// Inserts a new resource into the cache and marks it as the default
#[inline]
pub fn insert_default(&mut self, value: T) -> Handle<T> {
self.default = self.slots.insert(value);
self.default
}
#[inline]
pub fn get(&self, handle: Handle<T>) -> Result<&T> {
if handle.is_null() {
return Err(Error::NullHandle(type_name::<T>()));
}
self.slots
.get(handle)
.ok_or_else(|| Error::InvalidHandle(type_name::<T>()))
}
#[inline]
pub fn get_mut(&mut self, handle: Handle<T>) -> Result<&mut T> {
if handle.is_null() {
return Err(Error::NullHandle(type_name::<T>()));
}
self.slots
.get_mut(handle)
.ok_or_else(|| Error::InvalidHandle(type_name::<T>()))
}
/// Returns the resource by handle, or the default is the handle is invalid.
/// Note: The function still may fail to acquire a resource if the default is null
#[inline]
pub fn get_or_default(&self, handle: Handle<T>) -> Result<&T> {
self.get(handle).or_else(|_| self.get_default())
}
/// Mimics the entry api of HashMap.
pub fn entry(&mut self, handle: Handle<T>) -> Entry<T> {
if self.slots.get(handle).is_some() {
Entry::Occupied(self, handle)
} else {
Entry::Vacant(self)
}
}
/// Entry api for the default key if it may or may not exist.
pub fn default_entry(&mut self) -> Entry<T> {
self.entry(self.default)
}
// Returns the handle to the default resource stored in this cache.
// The handle is null if the cache is empty.
#[inline]
pub fn default_handle(&self) -> Handle<T> {
self.default
}
// Returns the current default resource
#[inline]
pub fn get_default(&self) -> Result<&T> {
self.get(self.default)
.map_err(|_| Error::MissingDefault(type_name::<T>()))
}
// Returns a mutable reference to the default resource
#[inline]
pub fn get_default_mut(&mut self) -> Result<&mut T> {
self.get_mut(self.default)
.map_err(|_| Error::MissingDefault(type_name::<T>()))
}
// Sets the default resource.
// Pass Handle::null to remove the default.
#[inline]
pub fn set_default(&mut self, handle: Handle<T>) {
self.default = handle;
}
#[inline]
pub fn default(&self) -> Handle<T> {
self.default
}
}
impl<T, I, E> ResourceCache<T>
where
T: 'static + LoadResource<Info = I, Error = E>,
{
/// Attempts to load and insert a resource from the given create info. If
/// info from the same info already exists, it will be returned. This means
/// the load function has to be injective over `info`.
pub fn load(&mut self, resources: &Resources, info: &I) -> std::result::Result<Handle<T>, E> {
let resource = T::load(resources, info)?;
Ok(self.insert(resource))
}
}
impl<T: 'static + Sized> Default for ResourceCache<T> {
fn default() -> Self {
Self {
slots: SlotMap::with_key(),
// info_map: HashMap::new(),
default: Handle::null(),
}
}
}