1use collections::BTreeMap;
2use gpui_util::post_inc;
3use std::{
4 cell::{Cell, RefCell},
5 fmt::Debug,
6 mem,
7 rc::Rc,
8};
9
10pub(crate) struct SingleSubscriberSet<Callback>(Rc<RefCell<SingleSubscriberSetState<Callback>>>);
12
13pub(crate) struct SubscriberSet<EmitterKey, Callback>(
15 Rc<RefCell<SubscriberSetState<EmitterKey, Callback>>>,
16);
17
18impl<EmitterKey, Callback> Clone for SubscriberSet<EmitterKey, Callback> {
19 fn clone(&self) -> Self {
20 SubscriberSet(self.0.clone())
21 }
22}
23
24struct SubscriberSetState<EmitterKey, Callback> {
25 subscribers: BTreeMap<EmitterKey, BTreeMap<usize, Subscriber<Callback>>>,
26 next_subscriber_id: usize,
27}
28
29#[derive(Clone, Copy, PartialEq, Eq)]
30enum SubscriberState {
31 Pending,
32 Active,
33 Dropped,
34}
35
36struct Subscriber<Callback> {
37 state: Rc<Cell<SubscriberState>>,
38 callback: Callback,
39}
40
41impl<EmitterKey, Callback> SubscriberSet<EmitterKey, Callback>
42where
43 EmitterKey: 'static + Ord + Clone + Debug,
44 Callback: 'static,
45{
46 pub fn new() -> Self {
47 Self(Rc::new(RefCell::new(SubscriberSetState {
48 subscribers: Default::default(),
49 next_subscriber_id: 0,
50 })))
51 }
52
53 pub fn insert(&self, emitter_key: EmitterKey, callback: Callback) -> Subscription {
55 let (subscription, activate) = self.insert_pending(emitter_key, callback);
56 activate();
57 subscription
58 }
59
60 pub fn insert_pending(
64 &self,
65 emitter_key: EmitterKey,
66 callback: Callback,
67 ) -> (Subscription, impl FnOnce() + use<EmitterKey, Callback>) {
68 let state = Rc::new(Cell::new(SubscriberState::Pending));
69 let mut lock = self.0.borrow_mut();
70 let subscriber_id = post_inc(&mut lock.next_subscriber_id);
71 lock.subscribers
72 .entry(emitter_key.clone())
73 .or_default()
74 .insert(
75 subscriber_id,
76 Subscriber {
77 state: state.clone(),
78 callback,
79 },
80 );
81 let this = self.0.clone();
82
83 let subscription = Subscription {
84 unsubscribe: Some(Box::new({
85 let state = state.clone();
86 move || {
87 state.set(SubscriberState::Dropped);
88
89 let mut lock = this.borrow_mut();
90 let Some(subscribers) = lock.subscribers.get_mut(&emitter_key) else {
91 return;
92 };
93
94 subscribers.remove(&subscriber_id);
95 if subscribers.is_empty() {
96 lock.subscribers.remove(&emitter_key);
97 }
98 }
99 })),
100 };
101 (subscription, move || {
102 if state.get() == SubscriberState::Pending {
103 state.set(SubscriberState::Active);
104 }
105 })
106 }
107
108 pub fn remove(
109 &self,
110 emitter: &EmitterKey,
111 ) -> impl IntoIterator<Item = Callback> + use<EmitterKey, Callback> {
112 let subscribers = self.0.borrow_mut().subscribers.remove(emitter);
113 subscribers
114 .map(|s| s.into_values())
115 .into_iter()
116 .flatten()
117 .filter_map(|subscriber| {
118 if subscriber.state.get() == SubscriberState::Active {
119 Some(subscriber.callback)
120 } else {
121 None
122 }
123 })
124 }
125
126 pub fn retain<F>(&self, emitter: &EmitterKey, mut f: F)
129 where
130 F: FnMut(&mut Callback) -> bool,
131 {
132 let Some(mut subscribers) = self
134 .0
135 .borrow_mut()
136 .subscribers
137 .get_mut(emitter)
138 .map(mem::take)
139 else {
140 return;
141 };
142
143 subscribers.retain(|_, subscriber| subscriber.retain(&mut f));
144 let mut lock = self.0.borrow_mut();
145
146 if subscribers.is_empty() {
147 if lock
148 .subscribers
149 .get(emitter)
150 .is_some_and(|subscribers| subscribers.is_empty())
151 {
152 lock.subscribers.remove(emitter);
153 }
154 return;
155 }
156
157 lock.subscribers
159 .entry(emitter.clone())
160 .or_default()
161 .append(&mut subscribers);
162 }
163}
164
165struct SingleSubscriberSetState<Callback> {
166 subscribers: BTreeMap<usize, Subscriber<Callback>>,
167 next_subscriber_id: usize,
168}
169
170impl<Callback> Clone for SingleSubscriberSet<Callback> {
171 fn clone(&self) -> Self {
172 Self(self.0.clone())
173 }
174}
175
176impl<Callback: 'static> SingleSubscriberSet<Callback> {
177 pub fn new() -> Self {
178 Self(Rc::new(RefCell::new(SingleSubscriberSetState {
179 subscribers: BTreeMap::new(),
180 next_subscriber_id: 0,
181 })))
182 }
183
184 pub fn insert(&self, callback: Callback) -> Subscription {
186 let (subscription, activate) = self.insert_pending(callback);
187 activate();
188 subscription
189 }
190
191 pub fn insert_pending(
195 &self,
196 callback: Callback,
197 ) -> (Subscription, impl FnOnce() + use<Callback>) {
198 let state = Rc::new(Cell::new(SubscriberState::Pending));
199 let mut lock = self.0.borrow_mut();
200 let subscriber_id = post_inc(&mut lock.next_subscriber_id);
201 lock.subscribers.insert(
202 subscriber_id,
203 Subscriber {
204 state: state.clone(),
205 callback,
206 },
207 );
208 let this = self.0.clone();
209
210 let subscription = Subscription {
211 unsubscribe: Some(Box::new({
212 let state = state.clone();
213 move || {
214 state.set(SubscriberState::Dropped);
215 this.borrow_mut().subscribers.remove(&subscriber_id);
216 }
217 })),
218 };
219 (subscription, move || {
220 if state.get() == SubscriberState::Pending {
221 state.set(SubscriberState::Active);
222 }
223 })
224 }
225
226 pub fn remove(&self) -> impl IntoIterator<Item = Callback> + use<Callback> {
228 let subscribers = mem::take(&mut self.0.borrow_mut().subscribers);
229 subscribers.into_values().filter_map(|subscriber| {
230 if subscriber.state.get() == SubscriberState::Active {
231 Some(subscriber.callback)
232 } else {
233 None
234 }
235 })
236 }
237
238 pub fn retain(&self, mut f: impl FnMut(&mut Callback) -> bool) {
240 let mut subscribers = mem::take(&mut self.0.borrow_mut().subscribers);
241 subscribers.retain(|_, subscriber| subscriber.retain(&mut f));
242 self.0.borrow_mut().subscribers.append(&mut subscribers);
243 }
244}
245
246impl<Callback> Subscriber<Callback> {
247 fn retain(&mut self, f: &mut impl FnMut(&mut Callback) -> bool) -> bool {
248 match self.state.get() {
249 SubscriberState::Pending => true,
250 SubscriberState::Dropped => false,
251 SubscriberState::Active => {
252 let keep = f(&mut self.callback);
253 keep && self.state.get() != SubscriberState::Dropped
254 }
255 }
256 }
257}
258
259#[must_use]
262pub struct Subscription {
263 unsubscribe: Option<Box<dyn FnOnce() + 'static>>,
264}
265
266impl Subscription {
267 pub fn new(unsubscribe: impl 'static + FnOnce()) -> Self {
270 Self {
271 unsubscribe: Some(Box::new(unsubscribe)),
272 }
273 }
274
275 pub fn detach(mut self) {
279 self.unsubscribe.take();
280 }
281
282 pub fn join(mut subscription_a: Self, mut subscription_b: Self) -> Self {
285 let a_unsubscribe = subscription_a.unsubscribe.take();
286 let b_unsubscribe = subscription_b.unsubscribe.take();
287 Self {
288 unsubscribe: Some(Box::new(move || {
289 if let Some(self_unsubscribe) = a_unsubscribe {
290 self_unsubscribe();
291 }
292 if let Some(other_unsubscribe) = b_unsubscribe {
293 other_unsubscribe();
294 }
295 })),
296 }
297 }
298}
299
300impl Drop for Subscription {
301 fn drop(&mut self) {
302 if let Some(unsubscribe) = self.unsubscribe.take() {
303 unsubscribe();
304 }
305 }
306}
307
308impl std::fmt::Debug for Subscription {
309 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
310 f.debug_struct("Subscription").finish()
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317 use crate::{Global, TestApp};
318
319 #[test]
320 fn test_immediate_and_pending_insertions() {
321 let subscribers = SubscriberSet::new();
322 let first = subscribers.insert(1usize, 10);
323 let (second, activate_second) = subscribers.insert_pending(1, 20);
324 let mut visited = Vec::new();
325 subscribers.retain(&1, |callback| {
326 visited.push(*callback);
327 subscribers.insert(1, 30).detach();
328 true
329 });
330 assert_eq!(visited, [10]);
331 activate_second();
332 assert_eq!(
333 subscribers.remove(&1).into_iter().collect::<Vec<_>>(),
334 [10, 20, 30]
335 );
336 drop(first);
337 drop(second);
338
339 let (pending, _activate) = subscribers.insert_pending(1, 40);
340 assert_eq!(subscribers.remove(&1).into_iter().count(), 0);
341 drop(pending);
342 }
343
344 #[test]
345 fn test_single_immediate_and_pending_insertions() {
346 let subscribers = SingleSubscriberSet::new();
347 let first = subscribers.insert(10);
348 let (second, activate_second) = subscribers.insert_pending(20);
349 let mut visited = Vec::new();
350 subscribers.retain(|callback| {
351 visited.push(*callback);
352 subscribers.insert(30).detach();
353 true
354 });
355 assert_eq!(visited, [10]);
356 activate_second();
357 assert_eq!(
358 subscribers.remove().into_iter().collect::<Vec<_>>(),
359 [10, 20, 30]
360 );
361 drop(first);
362 drop(second);
363
364 let (pending, _activate) = subscribers.insert_pending(40);
365 assert_eq!(subscribers.remove().into_iter().count(), 0);
366 drop(pending);
367 }
368
369 #[test]
370 fn test_activation_after_drop_during_retain() {
371 let subscribers = SubscriberSet::new();
372 let (first, activate_first) = subscribers.insert_pending(1usize, 10);
373 let (second, activate_second) = subscribers.insert_pending(1, 20);
374 subscribers.retain(&1, |_| panic!("pending subscriber invoked"));
375 activate_first();
376 let mut second = Some((second, activate_second));
377 let mut visited = Vec::new();
378
379 subscribers.retain(&1, |callback| {
380 visited.push(*callback);
381 let (subscription, activate) = second.take().expect("only the first callback runs");
382 drop(subscription);
383 activate();
384 true
385 });
386
387 assert_eq!(visited, [10]);
388 assert_eq!(subscribers.remove(&1).into_iter().collect::<Vec<_>>(), [10]);
389 drop(first);
390 }
391
392 #[test]
393 fn test_single_activation_after_drop_during_retain() {
394 let subscribers = SingleSubscriberSet::new();
395 let (first, activate_first) = subscribers.insert_pending(10);
396 let (second, activate_second) = subscribers.insert_pending(20);
397 subscribers.retain(|_| panic!("pending subscriber invoked"));
398 activate_first();
399 let mut second = Some((second, activate_second));
400 let mut visited = Vec::new();
401
402 subscribers.retain(|callback| {
403 visited.push(*callback);
404 let (subscription, activate) = second.take().expect("only the first callback runs");
405 drop(subscription);
406 activate();
407 true
408 });
409
410 assert_eq!(visited, [10]);
411 assert_eq!(subscribers.remove().into_iter().collect::<Vec<_>>(), [10]);
412 drop(first);
413 }
414
415 #[test]
416 fn test_unsubscribe_during_callback_with_insert() {
417 struct TestGlobal;
418 impl Global for TestGlobal {}
419
420 let mut app = TestApp::new();
421 app.set_global(TestGlobal);
422
423 let observer_a_count = Rc::new(Cell::new(0usize));
424 let observer_b_count = Rc::new(Cell::new(0usize));
425
426 let sub_a: Rc<RefCell<Option<Subscription>>> = Default::default();
427 let sub_b: Rc<RefCell<Option<Subscription>>> = Default::default();
428
429 *sub_a.borrow_mut() = Some(app.update({
432 let count = observer_a_count.clone();
433 let sub_a = sub_a.clone();
434 move |cx| {
435 cx.observe_global::<TestGlobal>(move |cx| {
436 count.set(count.get() + 1);
437 sub_a.borrow_mut().take();
438 cx.observe_global::<TestGlobal>(|_| {}).detach();
439 })
440 }
441 }));
442
443 *sub_b.borrow_mut() = Some(app.update({
445 let count = observer_b_count.clone();
446 let sub_b = sub_b.clone();
447 move |cx| {
448 cx.observe_global::<TestGlobal>(move |_cx| {
449 count.set(count.get() + 1);
450 sub_b.borrow_mut().take();
451 })
452 }
453 }));
454
455 app.update(|cx| cx.set_global(TestGlobal));
457 assert_eq!(observer_a_count.get(), 1);
458 assert_eq!(observer_b_count.get(), 1);
459
460 app.update(|cx| cx.set_global(TestGlobal));
462 assert_eq!(observer_a_count.get(), 1);
463 assert_eq!(observer_b_count.get(), 1, "orphaned subscriber fired again");
464 }
465
466 #[test]
467 fn test_callback_dropped_by_earlier_callback_does_not_fire() {
468 struct TestGlobal;
469 impl Global for TestGlobal {}
470
471 let mut app = TestApp::new();
472 app.set_global(TestGlobal);
473
474 let observer_b_count = Rc::new(Cell::new(0usize));
475 let sub_b: Rc<RefCell<Option<Subscription>>> = Default::default();
476
477 app.update({
479 let sub_b = sub_b.clone();
480 move |cx| {
481 cx.observe_global::<TestGlobal>(move |_cx| {
482 sub_b.borrow_mut().take();
483 })
484 .detach();
485 }
486 });
487
488 *sub_b.borrow_mut() = Some(app.update({
490 let count = observer_b_count.clone();
491 move |cx| {
492 cx.observe_global::<TestGlobal>(move |_cx| {
493 count.set(count.get() + 1);
494 })
495 }
496 }));
497
498 app.update(|cx| cx.set_global(TestGlobal));
499 assert_eq!(
500 observer_b_count.get(),
501 0,
502 "B should not fire — A dropped its subscription"
503 );
504 }
505
506 #[test]
507 fn test_self_drop_during_callback() {
508 struct TestGlobal;
509 impl Global for TestGlobal {}
510
511 let mut app = TestApp::new();
512 app.set_global(TestGlobal);
513
514 let count = Rc::new(Cell::new(0usize));
515 let sub: Rc<RefCell<Option<Subscription>>> = Default::default();
516
517 *sub.borrow_mut() = Some(app.update({
518 let count = count.clone();
519 let sub = sub.clone();
520 move |cx| {
521 cx.observe_global::<TestGlobal>(move |_cx| {
522 count.set(count.get() + 1);
523 sub.borrow_mut().take();
524 })
525 }
526 }));
527
528 app.update(|cx| cx.set_global(TestGlobal));
529 assert_eq!(count.get(), 1);
530
531 app.update(|cx| cx.set_global(TestGlobal));
532 assert_eq!(count.get(), 1, "should not fire after self-drop");
533 }
534
535 #[test]
536 fn test_subscription_drop() {
537 struct TestGlobal;
538 impl Global for TestGlobal {}
539
540 let mut app = TestApp::new();
541 app.set_global(TestGlobal);
542
543 let count = Rc::new(Cell::new(0usize));
544
545 let subscription = app.update({
546 let count = count.clone();
547 move |cx| {
548 cx.observe_global::<TestGlobal>(move |_cx| {
549 count.set(count.get() + 1);
550 })
551 }
552 });
553
554 drop(subscription);
555
556 app.update(|cx| cx.set_global(TestGlobal));
557 assert_eq!(count.get(), 0, "should not fire after drop");
558 }
559}