1use super::{WeakEventArgs, WeakEventHandler, WeakEventSender};
2use std::any::{Any, TypeId};
3use std::cell::{Cell, RefCell};
4use std::collections::HashMap;
5use std::ops::Deref;
6use std::rc::{Rc, Weak};
7
8pub trait WeakEventHandlerTarget<A: WeakEventArgs + ?Sized> {
11 fn add_event_handler(&self, event_name: &str, handler: Rc<WeakEventHandler<A>>) -> Option<Box<dyn FnOnce()>>;
18}
19
20pub type WeakEventHandlerMethod<A, TSubscriber> =
23 for<'s, 'r, 'a> fn(&TSubscriber, Option<&'s dyn Any>, &'r <A as WeakEventArgs>::Args<'a>);
24
25pub struct WeakEventHandlerManager;
27
28impl WeakEventHandlerManager {
29 pub fn subscribe<TTarget, A, TSubscriber>(
37 target: &TTarget,
38 event_name: &str,
39 subscriber: &Rc<TSubscriber>,
40 method: WeakEventHandlerMethod<A, TSubscriber>,
41 ) where
42 TTarget: WeakEventSender + Deref,
43 TTarget::Target: WeakEventHandlerTarget<A>,
44 A: WeakEventArgs + ?Sized,
45 TSubscriber: 'static,
46 {
47 let dic = SubscriptionTypeStorage::<A, TSubscriber>::subscribers().get_or_create_value(target);
48
49 let existing = dic.subscriptions.borrow().get(event_name).cloned();
50 let sub = match existing {
51 Some(sub) => sub,
52 None => {
53 let sub = Subscription::new(&dic, target, event_name);
54 dic.subscriptions.borrow_mut().insert(event_name.to_string(), sub.clone());
55 sub
56 }
57 };
58
59 sub.add(subscriber, method);
60 }
61
62 pub fn unsubscribe<A, TSubscriber>(target: &impl WeakEventSender, event_name: &str, subscriber: &Rc<TSubscriber>)
68 where
69 A: WeakEventArgs + ?Sized,
70 TSubscriber: 'static,
71 {
72 if let Some(dic) = SubscriptionTypeStorage::<A, TSubscriber>::subscribers().try_get_value(target) {
73 let sub = dic.subscriptions.borrow().get(event_name).cloned();
74 if let Some(sub) = sub {
75 sub.remove(subscriber);
76 }
77 }
78 }
79}
80
81crate::ferro_thread_local! {
82 static SUBSCRIPTION_TYPE_STORAGE: RefCell<HashMap<TypeId, Box<dyn Any>>> = RefCell::new(HashMap::new());
84}
85
86struct SubscriptionTypeStorage<A: WeakEventArgs + ?Sized, TSubscriber: 'static> {
91 subscribers: RefCell<HashMap<usize, Rc<SubscriptionDic<A, TSubscriber>>>>,
92 sweep_at: Cell<usize>,
93}
94
95const MIN_SWEEP: usize = 16;
96
97impl<A: WeakEventArgs + ?Sized, TSubscriber: 'static> SubscriptionTypeStorage<A, TSubscriber> {
98 fn subscribers() -> Rc<Self> {
99 SUBSCRIPTION_TYPE_STORAGE.with(|storage| {
100 storage
101 .borrow_mut()
102 .entry(TypeId::of::<fn(&A) -> TSubscriber>())
103 .or_insert_with(|| {
104 Box::new(Rc::new(Self { subscribers: RefCell::new(HashMap::new()), sweep_at: Cell::new(MIN_SWEEP) }))
105 })
106 .downcast_ref::<Rc<Self>>()
107 .expect("the storage of a type pair holds that pair")
108 .clone()
109 })
110 }
111
112 fn try_get_value(&self, target: &impl WeakEventSender) -> Option<Rc<SubscriptionDic<A, TSubscriber>>> {
113 self.subscribers.borrow().get(&target.sender_address()).cloned()
114 }
115
116 fn get_or_create_value<TTarget: WeakEventSender>(&self, target: &TTarget) -> Rc<SubscriptionDic<A, TSubscriber>> {
117 if let Some(dic) = self.try_get_value(target) {
118 return dic;
119 }
120 let weak_target = target.downgrade_sender();
121 let dic = Rc::new(SubscriptionDic {
122 subscriptions: RefCell::new(HashMap::new()),
123 target_alive: Box::new(move || TTarget::upgrade_sender(&weak_target).is_some()),
124 });
125 let mut subscribers = self.subscribers.borrow_mut();
126 subscribers.insert(target.sender_address(), dic.clone());
127 if subscribers.len() >= self.sweep_at.get() {
128 subscribers.retain(|_, dic| (dic.target_alive)());
129 self.sweep_at.set((subscribers.len() * 2).max(MIN_SWEEP));
130 }
131 dic
132 }
133}
134
135struct SubscriptionDic<A: WeakEventArgs + ?Sized, TSubscriber: 'static> {
137 subscriptions: RefCell<HashMap<String, Rc<Subscription<A, TSubscriber>>>>,
138 target_alive: Box<dyn Fn() -> bool>,
139}
140
141struct Descriptor<A: WeakEventArgs + ?Sized, TSubscriber> {
142 subscriber: Option<Weak<TSubscriber>>,
143 caller: Option<WeakEventHandlerMethod<A, TSubscriber>>,
144}
145
146impl<A: WeakEventArgs + ?Sized, TSubscriber> Default for Descriptor<A, TSubscriber> {
147 fn default() -> Self {
148 Self { subscriber: None, caller: None }
149 }
150}
151
152impl<A: WeakEventArgs + ?Sized, TSubscriber> Clone for Descriptor<A, TSubscriber> {
153 fn clone(&self) -> Self {
154 Self { subscriber: self.subscriber.clone(), caller: self.caller }
155 }
156}
157
158struct Subscription<A: WeakEventArgs + ?Sized, TSubscriber: 'static> {
159 sdic: Weak<SubscriptionDic<A, TSubscriber>>,
160 event_name: String,
161 remove_handler: RefCell<Option<Box<dyn FnOnce()>>>,
162 data: RefCell<Vec<Descriptor<A, TSubscriber>>>,
163 count: Cell<usize>,
164}
165
166impl<A: WeakEventArgs + ?Sized, TSubscriber: 'static> Subscription<A, TSubscriber> {
167 fn new<TTarget>(sdic: &Rc<SubscriptionDic<A, TSubscriber>>, target: &TTarget, event_name: &str) -> Rc<Self>
168 where
169 TTarget: WeakEventSender + Deref,
170 TTarget::Target: WeakEventHandlerTarget<A>,
171 {
172 let this = Rc::new(Self {
173 sdic: Rc::downgrade(sdic),
174 event_name: event_name.to_string(),
175 remove_handler: RefCell::new(None),
176 data: RefCell::new(vec![Descriptor::default(); 2]),
177 count: Cell::new(0),
178 });
179
180 let weak = Rc::downgrade(&this);
182 let delegate: Rc<WeakEventHandler<A>> = Rc::new(move |sender: Option<&dyn Any>, event_args: &A::Args<'_>| {
183 if let Some(this) = weak.upgrade() {
184 this.on_event(sender, event_args);
185 }
186 });
187 match (**target).add_event_handler(event_name, delegate) {
188 Some(remove_handler) => *this.remove_handler.borrow_mut() = Some(remove_handler),
189 None => panic!("The event {event_name} was not found on {}.", std::any::type_name::<TTarget::Target>()),
190 }
191 this
192 }
193
194 fn destroy(&self) {
195 let remove_handler = self.remove_handler.borrow_mut().take();
196 if let Some(remove_handler) = remove_handler {
197 remove_handler();
198 }
199 if let Some(sdic) = self.sdic.upgrade() {
200 sdic.subscriptions.borrow_mut().remove(&self.event_name);
201 }
202 }
203
204 fn add(&self, subscriber: &Rc<TSubscriber>, method: WeakEventHandlerMethod<A, TSubscriber>) {
205 self.compact(true);
206 let mut data = self.data.borrow_mut();
207 if self.count.get() == data.len() {
208 let len = data.len();
210 data.resize(len * 2, Descriptor::default());
211 }
212
213 data[self.count.get()] = Descriptor { caller: Some(method), subscriber: Some(Rc::downgrade(subscriber)) };
214 self.count.set(self.count.get() + 1);
215 }
216
217 fn remove(&self, subscriber: &Rc<TSubscriber>) {
218 let mut removed = false;
219
220 {
221 let mut data = self.data.borrow_mut();
222 for c in 0..self.count.get() {
223 let is_subscriber = data[c]
224 .subscriber
225 .as_ref()
226 .and_then(Weak::upgrade)
227 .is_some_and(|instance| Rc::ptr_eq(&instance, subscriber));
228 if is_subscriber {
229 data[c] = Descriptor::default();
230 removed = true;
231 }
232 }
233 }
234
235 if removed {
236 self.compact(false);
237 }
238 }
239
240 fn compact(&self, prevent_destroy: bool) {
241 let mut empty: Option<usize> = None;
242 {
243 let mut data = self.data.borrow_mut();
244 for c in 0..self.count.get() {
245 let r = data[c].clone();
246
247 let target = r.subscriber.as_ref().and_then(Weak::upgrade);
248
249 if target.is_none() && empty.is_none() {
251 empty = Some(c);
252 }
253 if let (Some(_), Some(e)) = (&target, empty) {
255 data[c] = Descriptor::default();
256 data[e] = r;
257 empty = Some(e + 1);
258 }
259 }
260 }
261 if let Some(empty) = empty {
262 self.count.set(empty);
263 }
264 if self.count.get() == 0 && !prevent_destroy {
265 self.destroy();
266 }
267 }
268
269 fn on_event(&self, sender: Option<&dyn Any>, event_args: &A::Args<'_>) {
270 let mut need_compact = false;
271 let mut c = 0;
272 while c < self.count.get() {
273 let descriptor = self.data.borrow()[c].clone();
274 let r = descriptor.subscriber.expect("a counted descriptor has a subscriber");
275 match r.upgrade() {
276 Some(sub) => (descriptor.caller.expect("a counted descriptor has a caller"))(&sub, sender, event_args),
277 None => need_compact = true,
278 }
279 c += 1;
280 }
281 if need_compact {
282 self.compact(false);
283 }
284 }
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290 use crate::utilities::EventArgs;
291
292 struct EventSource {
293 event: RefCell<Vec<Rc<WeakEventHandler<EventArgs>>>>,
294 this: Weak<EventSource>,
295 }
296
297 impl EventSource {
298 fn new() -> Rc<Self> {
299 Rc::new_cyclic(|this| Self { event: RefCell::new(Vec::new()), this: this.clone() })
300 }
301
302 fn fire(&self) {
303 let this = self.this.upgrade();
304 let handlers = self.event.borrow().clone();
305 for handler in handlers {
306 handler(this.as_ref().map(|this| this as &dyn Any), &EventArgs::EMPTY);
307 }
308 }
309 }
310
311 impl WeakEventHandlerTarget<EventArgs> for EventSource {
312 fn add_event_handler(
313 &self,
314 event_name: &str,
315 handler: Rc<WeakEventHandler<EventArgs>>,
316 ) -> Option<Box<dyn FnOnce()>> {
317 if event_name != "Event" {
318 return None;
319 }
320 self.event.borrow_mut().push(handler.clone());
321 let this = self.this.clone();
322 Some(Box::new(move || {
323 if let Some(this) = this.upgrade() {
324 let mut event = this.event.borrow_mut();
325 if let Some(index) = event.iter().rposition(|h| Rc::ptr_eq(h, &handler)) {
326 event.remove(index);
327 }
328 }
329 }))
330 }
331 }
332
333 struct Subscriber {
334 on_event: Option<Box<dyn Fn()>>,
335 }
336
337 impl Subscriber {
338 fn new(on_event: Box<dyn Fn()>) -> Rc<Self> {
339 Rc::new(Self { on_event: Some(on_event) })
340 }
341
342 fn on_event(&self, _sender: Option<&dyn Any>, _ev: &EventArgs) {
343 if let Some(on_event) = &self.on_event {
344 on_event();
345 }
346 }
347 }
348
349 #[test]
350 fn event_should_be_passed_to_subscriber() {
351 let handled = Rc::new(Cell::new(false));
352 let h = handled.clone();
353 let subscriber = Subscriber::new(Box::new(move || h.set(true)));
354 let source = EventSource::new();
355 WeakEventHandlerManager::subscribe::<_, EventArgs, Subscriber>(&source, "Event", &subscriber, Subscriber::on_event);
356 source.fire();
357 assert!(handled.get());
358 }
359
360 #[test]
361 fn event_should_not_be_raised_after_unsubscribe() {
362 let handled = Rc::new(Cell::new(false));
363 let h = handled.clone();
364 let subscriber = Subscriber::new(Box::new(move || h.set(true)));
365 let source = EventSource::new();
366 WeakEventHandlerManager::subscribe::<_, EventArgs, Subscriber>(&source, "Event", &subscriber, Subscriber::on_event);
367
368 WeakEventHandlerManager::unsubscribe::<EventArgs, Subscriber>(&source, "Event", &subscriber);
369
370 source.fire();
371
372 assert!(!handled.get());
373 }
374
375 #[test]
376 fn event_handler_should_not_be_kept_alive() {
377 let handled = Rc::new(Cell::new(false));
378 let source = EventSource::new();
379 let h = handled.clone();
380 add_collectable_subscriber(&source, "Event", Box::new(move || h.set(true)));
381 source.fire();
382 assert!(!handled.get());
383 }
384
385 fn add_collectable_subscriber(source: &Rc<EventSource>, name: &str, func: Box<dyn Fn()>) {
386 WeakEventHandlerManager::subscribe::<_, EventArgs, Subscriber>(source, name, &Subscriber::new(func), Subscriber::on_event);
387 }
388}