1use crate::core::{
24 parking_lot::Mutex,
25 pool::{Handle, Pool},
26};
27use crate::UntypedResource;
28use std::{
29 path::PathBuf,
30 sync::{mpsc::Sender, Arc},
31};
32
33#[derive(Clone)]
35pub enum ResourceEvent {
36 Loaded(UntypedResource),
38
39 Reloaded(UntypedResource),
41
42 Added(UntypedResource),
44
45 Removed(PathBuf),
47}
48
49pub type ResourceEventSender = Sender<ResourceEvent>;
51
52#[derive(Clone)]
54pub struct ResourceEventBroadcaster {
55 container: Arc<Mutex<Pool<ResourceEventSender>>>,
56}
57
58impl Default for ResourceEventBroadcaster {
59 fn default() -> Self {
60 Self::new()
61 }
62}
63
64impl ResourceEventBroadcaster {
65 pub fn new() -> Self {
67 Self {
68 container: Arc::new(Default::default()),
69 }
70 }
71
72 pub fn add(&self, sender: ResourceEventSender) -> Handle<ResourceEventSender> {
74 self.container.lock().spawn(sender)
75 }
76
77 pub fn remove(&self, handle: Handle<ResourceEventSender>) -> ResourceEventSender {
79 self.container.lock().free(handle)
80 }
81
82 pub fn broadcast(&self, event: ResourceEvent) {
84 let container = self.container.lock();
85 for sender in container.iter() {
86 let _ = sender.send(event.clone());
87 }
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}