1use crate::core::{
24 parking_lot::Mutex,
25 pool::{Handle, Pool},
26 SafeLock,
27};
28use crate::UntypedResource;
29use std::{
30 path::PathBuf,
31 sync::{mpsc::Sender, Arc},
32};
33
34#[derive(Clone)]
36pub enum ResourceEvent {
37 Loaded(UntypedResource),
39
40 Reloaded(UntypedResource),
42
43 Added(UntypedResource),
45
46 Removed(PathBuf),
48}
49
50pub type ResourceEventSender = Sender<ResourceEvent>;
52
53#[derive(Clone)]
55pub struct ResourceEventBroadcaster {
56 container: Arc<Mutex<Pool<ResourceEventSender>>>,
57}
58
59impl Default for ResourceEventBroadcaster {
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65impl ResourceEventBroadcaster {
66 pub fn new() -> Self {
68 Self {
69 container: Arc::new(Default::default()),
70 }
71 }
72
73 pub fn add(&self, sender: ResourceEventSender) -> Handle<ResourceEventSender> {
76 self.container.safe_lock().spawn(sender)
77 }
78
79 pub fn remove(&self, handle: Handle<ResourceEventSender>) -> ResourceEventSender {
81 self.container.safe_lock().free(handle)
82 }
83
84 pub fn broadcast(&self, event: ResourceEvent) {
86 let mut container = self.container.safe_lock();
87 container.retain(|sender| sender.send(event.clone()).is_ok());
88 }
89
90 pub fn broadcast_loaded(&self, resource: UntypedResource) {
92 self.broadcast(ResourceEvent::Loaded(resource))
93 }
94
95 pub fn broadcast_loaded_or_reloaded(&self, resource: UntypedResource, reload: bool) {
98 self.broadcast(if reload {
99 ResourceEvent::Reloaded(resource)
100 } else {
101 ResourceEvent::Loaded(resource)
102 })
103 }
104}
105
106#[cfg(test)]
107mod test {
108 use std::sync::mpsc::channel;
109
110 use super::*;
111
112 #[test]
113 fn resource_event_broadcaster_add_and_remove() {
114 let broadcaster = ResourceEventBroadcaster::new();
115 let (sender, receiver) = channel();
116
117 let h = broadcaster.add(sender);
118 assert!(h.is_some());
119 assert_eq!(h.index(), 0);
120 assert_eq!(h.generation(), 1);
121
122 broadcaster.broadcast(ResourceEvent::Added(UntypedResource::default()));
123 assert!(matches!(
124 receiver.recv(),
125 Ok(ResourceEvent::Added(UntypedResource(_)))
126 ));
127
128 broadcaster.remove(h);
129 broadcaster.broadcast(ResourceEvent::Added(UntypedResource::default()));
130 assert!(receiver.recv().is_err());
131 }
132
133 #[test]
134 fn resource_event_broadcaster_broadcast_loaded() {
135 let broadcaster = ResourceEventBroadcaster::default();
136 let (sender, receiver) = channel();
137 broadcaster.add(sender);
138
139 broadcaster.broadcast_loaded(UntypedResource::default());
140 assert!(matches!(
141 receiver.recv(),
142 Ok(ResourceEvent::Loaded(UntypedResource(_)))
143 ));
144 }
145
146 #[test]
147 fn resource_event_broadcaster_broadcast_loaded_or_reloaded() {
148 let broadcaster = ResourceEventBroadcaster::default();
149 let (sender, receiver) = channel();
150 broadcaster.add(sender);
151
152 broadcaster.broadcast_loaded_or_reloaded(UntypedResource::default(), false);
153 assert!(matches!(
154 receiver.recv(),
155 Ok(ResourceEvent::Loaded(UntypedResource(_)))
156 ));
157
158 broadcaster.broadcast_loaded_or_reloaded(UntypedResource::default(), true);
159 assert!(matches!(
160 receiver.recv(),
161 Ok(ResourceEvent::Reloaded(UntypedResource(_)))
162 ));
163 }
164
165 #[test]
166 fn resource_event_broadcaster_clone() {
167 let broadcaster = ResourceEventBroadcaster::new();
168 let (sender, receiver) = channel();
169
170 broadcaster.add(sender);
171 let broadcaster2 = broadcaster.clone();
172
173 broadcaster2.broadcast(ResourceEvent::Added(UntypedResource::default()));
174 assert!(matches!(
175 receiver.recv(),
176 Ok(ResourceEvent::Added(UntypedResource(_)))
177 ));
178 }
179}