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
use downcast_rs::Downcast;
use std::any::Any;
use std::collections::HashMap;
pub type ResourceId = u32;
type ResourceMap = HashMap<ResourceId, (String, Box<dyn Resource>)>;
#[derive(Default)]
pub struct ResourceTable {
map: ResourceMap,
next_id: u32,
}
impl ResourceTable {
pub fn has(&self, rid: ResourceId) -> bool {
self.map.contains_key(&rid)
}
pub fn get<T: Resource>(&self, rid: ResourceId) -> Option<&T> {
if let Some((_name, resource)) = self.map.get(&rid) {
return resource.downcast_ref::<T>();
}
None
}
pub fn get_mut<T: Resource>(&mut self, rid: ResourceId) -> Option<&mut T> {
if let Some((_name, resource)) = self.map.get_mut(&rid) {
return resource.downcast_mut::<T>();
}
None
}
fn next_rid(&mut self) -> ResourceId {
let next_rid = self.next_id;
self.next_id += 1;
next_rid as ResourceId
}
pub fn add(&mut self, name: &str, resource: Box<dyn Resource>) -> ResourceId {
let rid = self.next_rid();
let r = self.map.insert(rid, (name.to_string(), resource));
assert!(r.is_none());
rid
}
pub fn entries(&self) -> Vec<(ResourceId, String)> {
self
.map
.iter()
.map(|(key, (name, _resource))| (*key, name.clone()))
.collect()
}
pub fn close(&mut self, rid: ResourceId) -> Option<()> {
self.map.remove(&rid).map(|(_name, _resource)| ())
}
}
pub trait Resource: Downcast + Any {}
impl<T> Resource for T where T: Downcast + Any {}
impl_downcast!(Resource);
#[cfg(test)]
mod tests {
use super::*;
struct FakeResource {
not_empty: u128,
}
impl FakeResource {
fn new(value: u128) -> FakeResource {
FakeResource { not_empty: value }
}
}
#[test]
fn test_create_resource_table_default() {
let table = ResourceTable::default();
assert_eq!(table.map.len(), 0);
}
#[test]
fn test_add_to_resource_table_not_empty() {
let mut table = ResourceTable::default();
table.add("fake1", Box::new(FakeResource::new(1)));
table.add("fake2", Box::new(FakeResource::new(2)));
assert_eq!(table.map.len(), 2);
}
#[test]
fn test_add_to_resource_table_are_contiguous() {
let mut table = ResourceTable::default();
let rid1 = table.add("fake1", Box::new(FakeResource::new(1)));
let rid2 = table.add("fake2", Box::new(FakeResource::new(2)));
assert_eq!(rid1 + 1, rid2);
}
#[test]
fn test_get_from_resource_table_is_what_was_given() {
let mut table = ResourceTable::default();
let rid = table.add("fake", Box::new(FakeResource::new(7)));
let resource = table.get::<FakeResource>(rid);
assert_eq!(resource.unwrap().not_empty, 7);
}
#[test]
fn test_remove_from_resource_table() {
let mut table = ResourceTable::default();
let rid1 = table.add("fake1", Box::new(FakeResource::new(1)));
let rid2 = table.add("fake2", Box::new(FakeResource::new(2)));
assert_eq!(table.map.len(), 2);
table.close(rid1);
assert_eq!(table.map.len(), 1);
table.close(rid2);
assert_eq!(table.map.len(), 0);
}
}